Several of changes involving PSK checks.

This commit is contained in:
Sascha Spreitzer 2009-05-24 11:48:50 +02:00
parent fab0936a72
commit 9fdacb611f
3 changed files with 186 additions and 34 deletions

View file

@ -1,7 +1,7 @@
CFLAGS += -fPIC -Wall
ifdef DEBUG
CFLAGS += -O0 -ggdb -DDEBUG
CFLAGS += -O0 -ggdb
else
CFLAGS += -O2
endif
@ -24,6 +24,8 @@ endif
all: ${obj}
debug:
${MAKE} DEBUG=1 all
${obj}: ${objo}
${CC} ${LDFLAGS} -o ${obj} ${objo}

View file

@ -2,16 +2,47 @@
* pam_url - authenticate against webservers
*
* This software is opensource software licensed under the GNU Public License version 2.
* The author of this software is Sascha Thomas Spreitzer <sspreitzer@fedoraproject.org>.
* The author of this software is Sascha Thomas Spreitzer <sspreitzer (at) fedoraproject.org>.
* Please take a look in the COPYING, INSTALL and README files.
*
* USE THIS SOFTWARE WITH ABSOLUTELY NO GUARANTEE AND WARRANTY
*
*
* /etc/pam.d/sshd or /etc/pam.d/system-auth:
*
* [...]
* auth sufficient pam_url.so https://www.example.org/ secret user passwd &do=login
* auth sufficient pam_url.so URL PSK USER PASSWD EXTRA
* [...]
* This module takes 4 arguments:
* - URL = HTTPS URL
* - PSK = Pre Shared Key
* - USER = The name of the user variable
* - PASSWD = The name of the password variable
* - EXTRA = additional url encoded data
*
* auth sufficient pam_url.so https://www.example.org/ secret user passwd &do=auth
* This line forms the following url encoded POST data:
* ?user=<username>&passwd=<pass>&mode=<PAM_AUTH|PAM_ACCT|PAM_SESS|PAM_PASS>&PSK=secret&do=auth
* It should return either 200 OK with PSK in the body or 403 Forbidden if unsuccessful.
*/
#define PAM_SM_AUTH
#define PAM_SM_ACCOUNT
#define PAM_SM_SESSION
#define PAM_SM_PASSWORD
#ifndef NAME
#define NAME "pam_url"
#endif
#ifndef VERS
#define VERS "0.0"
#endif
#ifndef USER_AGENT
#define USER_AGENT NAME "/" VERS
#endif
#define PAM_SM_AUTH 1
#define PAM_SM_ACCOUNT 2
#define PAM_SM_SESSION 3
#define PAM_SM_PASSWORD 4
#include <security/pam_modules.h>
#include <security/pam_ext.h>
@ -28,21 +59,16 @@
#include <string.h>
#include <stdlib.h>
#include <syslog.h>
// /etc/pam.d/sshd or /etc/pam.d/system-auth:
//
// [...]
// auth sufficient pam_url.so https://www.example.org/ user passwd &mode=login
// auth sufficient pam_url.so URL USER PASSWD EXTRA
// [...]
// This module takes 3 arguments:
// URL, USERNAME, PASSWORD
// The username ,password and extra fields are optional.
#include <unistd.h>
#ifndef DEF_URL
#define DEF_URL "https://www.example.org/"
#endif
#ifndef DEF_PSK
#define DEF_PSK "presharedsecret"
#endif
#ifndef DEF_USER
#define DEF_USER "user"
#endif
@ -52,17 +78,22 @@
#endif
#ifndef DEF_EXTRA
#define DEF_EXTRA "&mode=login"
#define DEF_EXTRA "&do=pam_url"
#endif
typedef struct pam_url_opts_ {
char* url;
char* PSK;
char* userfield;
char* passwdfield;
char* extrafield;
char* mode;
const void* user;
const void* passwd;
FILE* answer;
char* fanswer;
} pam_url_opts;
void notice(pam_handle_t* pamh, const char *msg)
@ -72,9 +103,7 @@ void notice(pam_handle_t* pamh, const char *msg)
void debug(pam_handle_t* pamh, const char *msg)
{
// #ifdef DEBUG
pam_syslog(pamh, LOG_NOTICE, "%s", msg);
// #endif
pam_syslog(pamh, LOG_ERR, "%s", msg);
}
int get_password(pam_handle_t* pamh, pam_url_opts* opts)
@ -93,11 +122,14 @@ int get_password(pam_handle_t* pamh, pam_url_opts* opts)
}
}
int parse_opts(pam_url_opts* opts, int argc, const char** argv)
int parse_opts(pam_url_opts* opts, int argc, const char** argv, int mode)
{
opts->url = calloc(1, strlen(DEF_URL) + 1);
strcpy(opts->url, DEF_URL);
opts->PSK = calloc(1, strlen(DEF_PSK) + 1);
strcpy(opts->PSK, DEF_PSK);
opts->userfield = calloc(1, strlen(DEF_USER) + 1);
strcpy(opts->userfield, DEF_USER);
@ -118,22 +150,59 @@ int parse_opts(pam_url_opts* opts, int argc, const char** argv)
strcpy(opts->url, argv[0]);
}
if( argc >= 2)
if( argc >= 2 )
{
opts->userfield = calloc(1, strlen(argv[1]) + 1);
strcpy(opts->userfield, argv[1]);
opts->PSK = calloc(1, strlen(argv[1]) +1);
strcpy(opts->PSK, argv[1]);
}
if( argc >= 3)
if( argc >= 3 )
{
opts->passwdfield = calloc(1, strlen(argv[2]) + 1);
strcpy(opts->passwdfield, argv[2]);
opts->userfield = calloc(1, strlen(argv[2]) + 1);
strcpy(opts->userfield, argv[2]);
}
if( argc >= 4 )
{
opts->extrafield = calloc(1, strlen(argv[3]) + 1);
strcpy(opts->extrafield, argv[3]);
opts->passwdfield = calloc(1, strlen(argv[3]) + 1);
strcpy(opts->passwdfield, argv[3]);
}
if( argc >= 5 )
{
opts->extrafield = calloc(1, strlen(argv[4]) + 1);
strcpy(opts->extrafield, argv[4]);
}
opts->fanswer = calloc(1, strlen(tmpnam(NULL)) + 1 );
strcpy(opts->fanswer, tmpnam(NULL));
switch(mode)
{
case PAM_SM_ACCOUNT:
opts->mode = calloc(1, strlen("PAM_SM_ACCOUNT") + 1);
strcpy(opts->mode, "PAM_SM_ACCOUNT");
break;
case PAM_SM_SESSION:
opts->mode = calloc(1, strlen("PAM_SM_SESSION") + 1);
strcpy(opts->mode, "PAM_SM_SESSION");
break;
case PAM_SM_PASSWORD:
opts->mode = calloc(1, strlen("PAM_SM_PASSWORD") + 1);
strcpy(opts->mode, "PAM_SM_PASSWORD");
break;
default: // PAM_SM_AUTH
opts->mode = calloc(1, strlen("PAM_SM_AUTH") + 1);
strcpy(opts->mode,"PAM_SM_AUTH");
}
if( NULL == (opts->answer = fopen(opts->fanswer, "w+")) )
{
return PAM_AUTH_ERR;
}
return PAM_SUCCESS;
@ -144,13 +213,29 @@ int fetch_url(pam_url_opts opts)
CURL* eh = NULL;
char* post = NULL;
post = calloc(1, strlen(opts.userfield) +
post = calloc(1,
strlen("PSK=") +
strlen(opts.PSK) +
strlen("&") +
strlen(opts.userfield) +
strlen("=") +
strlen(opts.user) +
strlen("&") +
strlen(opts.passwdfield) +
strlen("=") +
strlen(opts.passwd) +
strlen(opts.extrafield) + 4); // 4 = two times "=" and one "&" and \0
strlen("&mode=") +
strlen(opts.mode) +
strlen(opts.extrafield) +
strlen("\0") );
sprintf(post, "%s=%s&%s=%s%s", opts.userfield, (char*)opts.user, opts.passwdfield, (char*)opts.passwd, opts.extrafield);
sprintf(post, "PSK=%s&%s=%s&%s=%s&mode=%s%s", opts.PSK,
opts.userfield,
(char*)opts.user,
opts.passwdfield,
(char*)opts.passwd,
opts.mode,
opts.extrafield);
if( 0 != curl_global_init(CURL_GLOBAL_ALL) )
return PAM_AUTH_ERR;
@ -164,6 +249,18 @@ int fetch_url(pam_url_opts opts)
return PAM_AUTH_ERR;
}
if( CURLE_OK != curl_easy_setopt(eh, CURLOPT_USERAGENT, USER_AGENT) )
{
curl_easy_cleanup(eh);
return PAM_AUTH_ERR;
}
if( CURLE_OK != curl_easy_setopt(eh, CURLOPT_WRITEDATA, opts.answer) )
{
curl_easy_cleanup(eh);
return PAM_AUTH_ERR;
}
if( CURLE_OK != curl_easy_setopt(eh, CURLOPT_URL, opts.url) )
{
curl_easy_cleanup(eh);
@ -200,6 +297,51 @@ int fetch_url(pam_url_opts opts)
}
}
int check_psk(pam_url_opts opts)
{
int ret=0;
char* buf;
if( 0 != access( opts.fanswer, R_OK|W_OK ) || NULL == opts.answer )
{
ret++;
return ret;
}
rewind(opts.answer);
// buf = calloc(1, 2000);
if( NULL == fgets(buf, sizeof(buf),opts.answer) )
{
ret++;
rewind(opts.answer);
return PAM_AUTH_ERR;
}
if( 0 != strncmp(buf, opts.PSK, strlen(opts.PSK)) )
{
ret++;
}
rewind(opts.answer);
if( 0 != ret )
{
return PAM_AUTH_ERR;
}
else
{
return PAM_SUCCESS;
}
}
void cleanup(pam_url_opts opts)
{
fclose(opts.answer);
remove(opts.fanswer);
}
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
{ // by now, a dummy
return PAM_SUCCESS;
@ -234,7 +376,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,
}
}
if( PAM_SUCCESS != parse_opts(&opts, argc, argv) )
if( PAM_SUCCESS != parse_opts(&opts, argc, argv, PAM_SM_AUTH) )
{
ret++;
debug(pamh, "Could not parse module options.");
@ -246,10 +388,18 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,
debug(pamh, "Could not fetch URL.");
}
if( PAM_SUCCESS != check_psk(opts) )
{
ret++;
debug(pamh, "Pre Shared Key differs from ours.");
}
if( 0 == ret )
return PAM_SUCCESS;
debug(pamh, "Authentication failed.");
cleanup(opts);
return PAM_AUTH_ERR;
}

View file

@ -16,7 +16,7 @@ PAM module to fetch from URL.
%setup -n %{name}
%build
make DESTDIR=%{buildroot} all
make DEBUG=1 DESTDIR=%{buildroot} all
%install
make DESTDIR=%{buildroot} install