diff options
Diffstat (limited to 'source4/pam_smbpass/support.c')
-rw-r--r-- | source4/pam_smbpass/support.c | 637 |
1 files changed, 0 insertions, 637 deletions
diff --git a/source4/pam_smbpass/support.c b/source4/pam_smbpass/support.c deleted file mode 100644 index 11de306d13..0000000000 --- a/source4/pam_smbpass/support.c +++ /dev/null @@ -1,637 +0,0 @@ - /* Unix NT password database implementation, version 0.6. - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 675 - * Mass Ave, Cambridge, MA 02139, USA. - */ - - #include "includes.h" - #include "general.h" - - #include "support.h" - - - #define _pam_overwrite(x) \ - do { \ - register char *__xx__; \ - if ((__xx__=(x))) \ - while (*__xx__) \ - *__xx__++ = '\0'; \ - } while (0) - - /* - * Don't just free it, forget it too. - */ - - #define _pam_drop(X) \ - do { \ - if (X) { \ - free(X); \ - X=NULL; \ - } \ - } while (0) - - #define _pam_drop_reply(/* struct pam_response * */ reply, /* int */ replies) \ - do { \ - int reply_i; \ - \ - for (reply_i=0; reply_i<replies; ++reply_i) { \ - if (reply[reply_i].resp) { \ - _pam_overwrite(reply[reply_i].resp); \ - free(reply[reply_i].resp); \ - } \ - } \ - if (reply) \ - free(reply); \ - } while (0) - - - int converse(pam_handle_t *, int, int, struct pam_message **, - struct pam_response **); - int make_remark(pam_handle_t *, unsigned int, int, const char *); - void _cleanup(pam_handle_t *, void *, int); - char *_pam_delete(register char *); - - /* default configuration file location */ - - char *servicesf = dyn_CONFIGFILE; - - /* syslogging function for errors and other information */ - - void _log_err( int err, const char *format, ... ) - { - va_list args; - - va_start( args, format ); - openlog( "PAM_smbpass", LOG_CONS | LOG_PID, LOG_AUTH ); - vsyslog( err, format, args ); - va_end( args ); - closelog(); - } - - /* this is a front-end for module-application conversations */ - - int converse( pam_handle_t * pamh, int ctrl, int nargs - , struct pam_message **message - , struct pam_response **response ) - { - int retval; - struct pam_conv *conv; - - retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv); - if (retval == PAM_SUCCESS) { - - retval = conv->conv(nargs, (const struct pam_message **) message - ,response, conv->appdata_ptr); - - if (retval != PAM_SUCCESS && on(SMB_DEBUG, ctrl)) { - _log_err(LOG_DEBUG, "conversation failure [%s]" - ,pam_strerror(pamh, retval)); - } - } else { - _log_err(LOG_ERR, "couldn't obtain coversation function [%s]" - ,pam_strerror(pamh, retval)); - } - - return retval; /* propagate error status */ - } - - int make_remark( pam_handle_t * pamh, unsigned int ctrl - , int type, const char *text ) - { - if (off(SMB__QUIET, ctrl)) { - struct pam_message *pmsg[1], msg[1]; - struct pam_response *resp; - - pmsg[0] = &msg[0]; - msg[0].msg = text; - msg[0].msg_style = type; - resp = NULL; - - return converse(pamh, ctrl, 1, pmsg, &resp); - } - return PAM_SUCCESS; - } - - - /* set the control flags for the SMB module. */ - -int set_ctrl( int flags, int argc, const char **argv ) -{ - int i = 0; - const char *service_file = dyn_CONFIGFILE; - unsigned int ctrl; - - ctrl = SMB_DEFAULTS; /* the default selection of options */ - - /* set some flags manually */ - - /* A good, sane default (matches Samba's behavior). */ - set( SMB__NONULL, ctrl ); - - /* initialize service file location */ - service_file=servicesf; - - if (flags & PAM_SILENT) { - set( SMB__QUIET, ctrl ); - } - - /* Run through the arguments once, looking for an alternate smb config - file location */ - while (i < argc) { - int j; - - for (j = 0; j < SMB_CTRLS_; ++j) { - if (smb_args[j].token - && !strncmp(argv[i], smb_args[j].token, strlen(smb_args[j].token))) - { - break; - } - } - - if (j == SMB_CONF_FILE) { - service_file = argv[i] + 8; - } - i++; - } - - /* Read some options from the Samba config. Can be overridden by - the PAM config. */ - if(lp_load(service_file,True,False,False) == False) { - _log_err( LOG_ERR, "Error loading service file %s", service_file ); - } - - secrets_init(); - - if (lp_null_passwords()) { - set( SMB__NULLOK, ctrl ); - } - - /* now parse the rest of the arguments to this module */ - - while (argc-- > 0) { - int j; - - for (j = 0; j < SMB_CTRLS_; ++j) { - if (smb_args[j].token - && !strncmp(*argv, smb_args[j].token, strlen(smb_args[j].token))) - { - break; - } - } - - if (j >= SMB_CTRLS_) { - _log_err( LOG_ERR, "unrecognized option [%s]", *argv ); - } else { - ctrl &= smb_args[j].mask; /* for turning things off */ - ctrl |= smb_args[j].flag; /* for turning things on */ - } - - ++argv; /* step to next argument */ - } - - /* auditing is a more sensitive version of debug */ - - if (on( SMB_AUDIT, ctrl )) { - set( SMB_DEBUG, ctrl ); - } - /* return the set of flags */ - - return ctrl; -} - -/* use this to free strings. ESPECIALLY password strings */ - -char * _pam_delete( register char *xx ) -{ - _pam_overwrite( xx ); - _pam_drop( xx ); - return NULL; -} - -void _cleanup( pam_handle_t * pamh, void *x, int error_status ) -{ - x = _pam_delete( (char *) x ); -} - -/* JHT - * - * Safe duplication of character strings. "Paranoid"; don't leave - * evidence of old token around for later stack analysis. - * - */ -char * smbpXstrDup( const char *x ) -{ - register char *new = NULL; - - if (x != NULL) { - register int i; - - for (i = 0; x[i]; ++i); /* length of string */ - if ((new = malloc(++i)) == NULL) { - i = 0; - _log_err( LOG_CRIT, "out of memory in smbpXstrDup" ); - } else { - while (i-- > 0) { - new[i] = x[i]; - } - } - x = NULL; - } - return new; /* return the duplicate or NULL on error */ -} - -/* ************************************************************** * - * Useful non-trivial functions * - * ************************************************************** */ - -void _cleanup_failures( pam_handle_t * pamh, void *fl, int err ) -{ - int quiet; - const char *service = NULL; - struct _pam_failed_auth *failure; - -#ifdef PAM_DATA_SILENT - quiet = err & PAM_DATA_SILENT; /* should we log something? */ -#else - quiet = 0; -#endif -#ifdef PAM_DATA_REPLACE - err &= PAM_DATA_REPLACE; /* are we just replacing data? */ -#endif - failure = (struct _pam_failed_auth *) fl; - - if (failure != NULL) { - -#ifdef PAM_DATA_SILENT - if (!quiet && !err) { /* under advisement from Sun,may go away */ -#else - if (!quiet) { /* under advisement from Sun,may go away */ -#endif - - /* log the number of authentication failures */ - if (failure->count != 0) { - pam_get_item( pamh, PAM_SERVICE, (const void **) &service ); - _log_err( LOG_NOTICE - , "%d authentication %s " - "from %s for service %s as %s(%d)" - , failure->count - , failure->count == 1 ? "failure" : "failures" - , failure->agent - , service == NULL ? "**unknown**" : service - , failure->user, failure->id ); - if (failure->count > SMB_MAX_RETRIES) { - _log_err( LOG_ALERT - , "service(%s) ignoring max retries; %d > %d" - , service == NULL ? "**unknown**" : service - , failure->count - , SMB_MAX_RETRIES ); - } - } - } - _pam_delete( failure->agent ); /* tidy up */ - _pam_delete( failure->user ); /* tidy up */ - SAFE_FREE( failure ); - } -} - -int _smb_verify_password( pam_handle_t * pamh, SAM_ACCOUNT *sampass, - const char *p, unsigned int ctrl ) -{ - uchar hash_pass[16]; - uchar lm_pw[16]; - uchar nt_pw[16]; - int retval = PAM_AUTH_ERR; - char *data_name; - const char *name; - - if (!sampass) - return PAM_ABORT; - - name = pdb_get_username(sampass); - -#ifdef HAVE_PAM_FAIL_DELAY - if (off( SMB_NODELAY, ctrl )) { - (void) pam_fail_delay( pamh, 1000000 ); /* 1 sec delay for on failure */ - } -#endif - - if (!pdb_get_lanman_passwd(sampass)) - { - _log_err( LOG_DEBUG, "user %s has null SMB password" - , name ); - - if (off( SMB__NONULL, ctrl ) - && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ)) - { /* this means we've succeeded */ - return PAM_SUCCESS; - } else { - const char *service; - - pam_get_item( pamh, PAM_SERVICE, (const void **)&service ); - _log_err( LOG_NOTICE - , "failed auth request by %s for service %s as %s(%d)" - , uidtoname( getuid() ) - , service ? service : "**unknown**", name - , pdb_get_uid(sampass) ); - return PAM_AUTH_ERR; - } - } - - data_name = (char *) malloc( sizeof(FAIL_PREFIX) + strlen( name )); - if (data_name == NULL) { - _log_err( LOG_CRIT, "no memory for data-name" ); - } - strncpy( data_name, FAIL_PREFIX, sizeof(FAIL_PREFIX) ); - strncpy( data_name + sizeof(FAIL_PREFIX) - 1, name, strlen( name ) + 1 ); - - /* - * The password we were given wasn't an encrypted password, or it - * didn't match the one we have. We encrypt the password now and try - * again. - */ - - nt_lm_owf_gen(p, nt_pw, lm_pw); - - /* the moment of truth -- do we agree with the password? */ - - if (!memcmp( nt_pw, pdb_get_nt_passwd(sampass), 16 )) { - - retval = PAM_SUCCESS; - if (data_name) { /* reset failures */ - pam_set_data(pamh, data_name, NULL, _cleanup_failures); - } - } else { - - const char *service; - - pam_get_item( pamh, PAM_SERVICE, (const void **)&service ); - - if (data_name != NULL) { - struct _pam_failed_auth *new = NULL; - const struct _pam_failed_auth *old = NULL; - - /* get a failure recorder */ - - new = (struct _pam_failed_auth *) - malloc( sizeof(struct _pam_failed_auth) ); - - if (new != NULL) { - - /* any previous failures for this user ? */ - pam_get_data(pamh, data_name, (const void **) &old); - - if (old != NULL) { - new->count = old->count + 1; - if (new->count >= SMB_MAX_RETRIES) { - retval = PAM_MAXTRIES; - } - } else { - _log_err( LOG_NOTICE - , "failed auth request by %s for service %s as %s(%d)" - , uidtoname( getuid() ) - , service ? service : "**unknown**", name - , pdb_get_uid(sampass) ); - new->count = 1; - } - new->user = smbpXstrDup( name ); - new->id = pdb_get_uid(sampass); - new->agent = smbpXstrDup( uidtoname( getuid() ) ); - pam_set_data( pamh, data_name, new, _cleanup_failures ); - - } else { - _log_err( LOG_CRIT, "no memory for failure recorder" ); - _log_err( LOG_NOTICE - , "failed auth request by %s for service %s as %s(%d)" - , uidtoname( getuid() ) - , service ? service : "**unknown**", name - , pdb_get_uid(sampass) ); - } - } else { - _log_err( LOG_NOTICE - , "failed auth request by %s for service %s as %s(%d)" - , uidtoname( getuid() ) - , service ? service : "**unknown**", name - , pdb_get_uid(sampass) ); - retval = PAM_AUTH_ERR; - } - } - - _pam_delete( data_name ); - - return retval; -} - - -/* - * _smb_blankpasswd() is a quick check for a blank password - * - * returns TRUE if user does not have a password - * - to avoid prompting for one in such cases (CG) - */ - -int _smb_blankpasswd( unsigned int ctrl, SAM_ACCOUNT *sampass ) -{ - int retval; - - /* - * This function does not have to be too smart if something goes - * wrong, return FALSE and let this case to be treated somewhere - * else (CG) - */ - - if (on( SMB__NONULL, ctrl )) - return 0; /* will fail but don't let on yet */ - - if (pdb_get_lanman_passwd(sampass) == NULL) - retval = 1; - else - retval = 0; - - return retval; -} - -/* - * obtain a password from the user - */ - -int _smb_read_password( pam_handle_t * pamh, unsigned int ctrl, - const char *comment, const char *prompt1, - const char *prompt2, const char *data_name, char **pass ) -{ - int authtok_flag; - int retval; - char *item = NULL; - char *token; - - struct pam_message msg[3], *pmsg[3]; - struct pam_response *resp; - int i, expect; - - - /* make sure nothing inappropriate gets returned */ - - *pass = token = NULL; - - /* which authentication token are we getting? */ - - authtok_flag = on(SMB__OLD_PASSWD, ctrl) ? PAM_OLDAUTHTOK : PAM_AUTHTOK; - - /* should we obtain the password from a PAM item ? */ - - if (on(SMB_TRY_FIRST_PASS, ctrl) || on(SMB_USE_FIRST_PASS, ctrl)) { - retval = pam_get_item( pamh, authtok_flag, (const void **) &item ); - if (retval != PAM_SUCCESS) { - /* very strange. */ - _log_err( LOG_ALERT - , "pam_get_item returned error to smb_read_password" ); - return retval; - } else if (item != NULL) { /* we have a password! */ - *pass = item; - item = NULL; - return PAM_SUCCESS; - } else if (on( SMB_USE_FIRST_PASS, ctrl )) { - return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */ - } else if (on( SMB_USE_AUTHTOK, ctrl ) - && off( SMB__OLD_PASSWD, ctrl )) - { - return PAM_AUTHTOK_RECOVER_ERR; - } - } - - /* - * getting here implies we will have to get the password from the - * user directly. - */ - - /* prepare to converse */ - if (comment != NULL && off(SMB__QUIET, ctrl)) { - pmsg[0] = &msg[0]; - msg[0].msg_style = PAM_TEXT_INFO; - msg[0].msg = comment; - i = 1; - } else { - i = 0; - } - - pmsg[i] = &msg[i]; - msg[i].msg_style = PAM_PROMPT_ECHO_OFF; - msg[i++].msg = prompt1; - - if (prompt2 != NULL) { - pmsg[i] = &msg[i]; - msg[i].msg_style = PAM_PROMPT_ECHO_OFF; - msg[i++].msg = prompt2; - expect = 2; - } else - expect = 1; - - resp = NULL; - - retval = converse( pamh, ctrl, i, pmsg, &resp ); - - if (resp != NULL) { - int j = comment ? 1 : 0; - /* interpret the response */ - - if (retval == PAM_SUCCESS) { /* a good conversation */ - - token = smbpXstrDup(resp[j++].resp); - if (token != NULL) { - if (expect == 2) { - /* verify that password entered correctly */ - if (!resp[j].resp || strcmp( token, resp[j].resp )) { - _pam_delete( token ); - retval = PAM_AUTHTOK_RECOVER_ERR; - make_remark( pamh, ctrl, PAM_ERROR_MSG - , MISTYPED_PASS ); - } - } - } else { - _log_err(LOG_NOTICE, "could not recover authentication token"); - } - } - - /* tidy up */ - _pam_drop_reply( resp, expect ); - - } else { - retval = (retval == PAM_SUCCESS) ? PAM_AUTHTOK_RECOVER_ERR : retval; - } - - if (retval != PAM_SUCCESS) { - if (on( SMB_DEBUG, ctrl )) - _log_err( LOG_DEBUG, "unable to obtain a password" ); - return retval; - } - /* 'token' is the entered password */ - - if (off( SMB_NOT_SET_PASS, ctrl )) { - - /* we store this password as an item */ - - retval = pam_set_item( pamh, authtok_flag, (const void *)token ); - _pam_delete( token ); /* clean it up */ - if (retval != PAM_SUCCESS - || (retval = pam_get_item( pamh, authtok_flag - ,(const void **)&item )) != PAM_SUCCESS) - { - _log_err( LOG_CRIT, "error manipulating password" ); - return retval; - } - } else { - /* - * then store it as data specific to this module. pam_end() - * will arrange to clean it up. - */ - - retval = pam_set_data( pamh, data_name, (void *) token, _cleanup ); - if (retval != PAM_SUCCESS - || (retval = pam_get_data( pamh, data_name, (const void **)&item )) - != PAM_SUCCESS) - { - _log_err( LOG_CRIT, "error manipulating password data [%s]" - , pam_strerror( pamh, retval )); - _pam_delete( token ); - item = NULL; - return retval; - } - token = NULL; /* break link to password */ - } - - *pass = item; - item = NULL; /* break link to password */ - - return PAM_SUCCESS; -} - -int _pam_smb_approve_pass(pam_handle_t * pamh, - unsigned int ctrl, - const char *pass_old, - const char *pass_new ) -{ - - /* Further checks should be handled through module stacking. -SRL */ - if (pass_new == NULL || (pass_old && !strcmp( pass_old, pass_new ))) - { - if (on(SMB_DEBUG, ctrl)) { - _log_err( LOG_DEBUG, - "passwd: bad authentication token (null or unchanged)" ); - } - make_remark( pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ? - "No password supplied" : "Password unchanged" ); - return PAM_AUTHTOK_ERR; - } - - return PAM_SUCCESS; -} |