diff --git a/apps/pam_url/Makefile b/apps/pam_url/Makefile index 978159d..acebf61 100644 --- a/apps/pam_url/Makefile +++ b/apps/pam_url/Makefile @@ -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} diff --git a/apps/pam_url/pam_url.c b/apps/pam_url/pam_url.c index d33326e..be49d6e 100644 --- a/apps/pam_url/pam_url.c +++ b/apps/pam_url/pam_url.c @@ -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 . + * The author of this software is Sascha Thomas Spreitzer . * 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=&passwd=&mode=&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 #include @@ -28,21 +59,16 @@ #include #include #include - -// /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 #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; } diff --git a/apps/pam_url/pam_url.spec b/apps/pam_url/pam_url.spec index bcffac4..eb1cb67 100644 --- a/apps/pam_url/pam_url.spec +++ b/apps/pam_url/pam_url.spec @@ -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