static int verify_krb4(struct passwd *pwd, char *password, int32_t *exp, int quiet) { int ret = 1; char lrealm[REALM_SZ]; if (krb_get_lrealm (lrealm, 1) != KFAILURE) { set_krbtkfile(pwd->pw_uid); ret = krb_verify_user (pwd->pw_name, "", lrealm, password, KRB_VERIFY_SECURE, NULL); if (ret == KSUCCESS) { if (!pag_set && k_hasafs()) { k_setpag (); pag_set = 1; } if (pag_set) krb_afslog_uid_home (0, 0, pwd->pw_uid, pwd->pw_dir); } else if (!quiet) printf ("%s\n", krb_get_err_text (ret)); } return ret; }
static int verify_pass(pam_handle_t *pamh, const char *name, const char *inst, const char *pass) { char realm[REALM_SZ]; int ret, krb_verify, old_euid, old_ruid; krb_get_lrealm(realm, 1); if (ctrl_on(KRB4_NO_VERIFY)) krb_verify = KRB_VERIFY_SECURE_FAIL; else krb_verify = KRB_VERIFY_SECURE; old_ruid = getuid(); old_euid = geteuid(); setreuid(0, 0); ret = krb_verify_user(name, inst, realm, pass, krb_verify, NULL); pdeb("krb_verify_user(`%s', `%s', `%s', pw, %d, NULL) returns %s", name, inst, realm, krb_verify, krb_get_err_text(ret)); setreuid(old_ruid, old_euid); if (getuid() != old_ruid || geteuid() != old_euid) { psyslog(LOG_ALERT , "setreuid(%d, %d) failed at line %d", old_ruid, old_euid, __LINE__); exit(1); } switch(ret) { case KSUCCESS: return PAM_SUCCESS; case KDC_PR_UNKNOWN: return PAM_USER_UNKNOWN; case SKDC_CANT: case SKDC_RETRY: case RD_AP_TIME: return PAM_AUTHINFO_UNAVAIL; default: return PAM_AUTH_ERR; } }
/******************************************************************* check on Kerberos authentication ********************************************************************/ static BOOL krb4_auth(char *this_user,char *password) { char realm[REALM_SZ]; char tkfile[MAXPATHLEN]; if (krb_get_lrealm(realm, 1) != KSUCCESS) (void) strncpy(realm, KRB_REALM, sizeof (realm)); (void) slprintf(tkfile, sizeof(tkfile)-1, "/tmp/samba_tkt_%d", getpid()); krb_set_tkt_string(tkfile); if (krb_verify_user(this_user, "", realm, password, 0, "rmcd") == KSUCCESS) { unlink(tkfile); return 1; } unlink(tkfile); return 0; }
static int #if defined(USE_PAM) || defined(_AIX) isNoPassAllowed( const char *un ) { struct passwd *pw = 0; # ifdef HAVE_GETSPNAM /* (sic!) - not USESHADOW */ struct spwd *spw; # endif #else isNoPassAllowed( const char *un, struct passwd *pw ) { #endif struct group *gr; char **fp; int hg; if (!*un) return 0; if (cursource != PWSRC_MANUAL) return 1; for (hg = 0, fp = td->noPassUsers; *fp; fp++) if (**fp == '@') hg = 1; else if (!strcmp( un, *fp )) return 1; else if (!strcmp( "*", *fp )) { #if defined(USE_PAM) || defined(_AIX) if (!(pw = getpwnam( un ))) return 0; if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*') continue; # ifdef HAVE_GETSPNAM /* (sic!) - not USESHADOW */ if ((spw = getspnam( un )) && (spw->sp_pwdp[0] == '!' || spw->sp_pwdp[0] == '*')) continue; # endif #endif if (pw->pw_uid) return 1; } #if defined(USE_PAM) || defined(_AIX) if (hg && (pw || (pw = getpwnam( un )))) { #else if (hg) { #endif for (setgrent(); (gr = getgrent()); ) for (fp = td->noPassUsers; *fp; fp++) if (**fp == '@' && !strcmp( gr->gr_name, *fp + 1 )) { if (pw->pw_gid == gr->gr_gid) { endgrent(); return 1; } for (; *gr->gr_mem; gr->gr_mem++) if (!strcmp( un, *gr->gr_mem )) { endgrent(); return 1; } } endgrent(); } return 0; } #if !defined(USE_PAM) && !defined(_AIX) && defined(HAVE_SETUSERCONTEXT) # define LC_RET0 do { login_close(lc); return 0; } while(0) #else # define LC_RET0 return 0 #endif int verify( GConvFunc gconv, int rootok ) { #ifdef USE_PAM const char *psrv; struct pam_data pdata; int pretc, pnopass; char psrvb[64]; #elif defined(_AIX) char *msg, *curret; int i, reenter; #else struct stat st; const char *nolg; char *buf; int fd; # ifdef HAVE_GETUSERSHELL char *s; # endif # if defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || defined(USESHADOW) int tim, expir, warntime, quietlog; # endif #endif debug( "verify ...\n" ); #ifdef USE_PAM pnopass = FALSE; if (!strcmp( curtype, "classic" )) { if (!gconv( GCONV_USER, 0 )) return 0; if (isNoPassAllowed( curuser )) { gconv( GCONV_PASS_ND, 0 ); if (!*curpass) { pnopass = TRUE; sprintf( psrvb, "%.31s-np", PAMService ); psrv = psrvb; } else psrv = PAMService; } else psrv = PAMService; pdata.usecur = TRUE; } else { sprintf( psrvb, "%.31s-%.31s", PAMService, curtype ); psrv = psrvb; pdata.usecur = FALSE; } pdata.gconv = gconv; if (!doPAMAuth( psrv, &pdata )) return 0; #elif defined(_AIX) if ((td->displayType & d_location) == dForeign) { char *tmpch; strncpy( hostname, td->name, sizeof(hostname) - 1 ); hostname[sizeof(hostname)-1] = '\0'; if ((tmpch = strchr( hostname, ':' ))) *tmpch = '\0'; } else hostname[0] = '\0'; /* tty names should only be 15 characters long */ # if 0 for (i = 0; i < 15 && td->name[i]; i++) { if (td->name[i] == ':' || td->name[i] == '.') tty[i] = '_'; else tty[i] = td->name[i]; } tty[i] = '\0'; # else memcpy( tty, "/dev/xdm/", 9 ); for (i = 0; i < 6 && td->name[i]; i++) { if (td->name[i] == ':' || td->name[i] == '.') tty[9 + i] = '_'; else tty[9 + i] = td->name[i]; } tty[9 + i] = '\0'; # endif if (!strcmp( curtype, "classic" )) { if (!gconv( GCONV_USER, 0 )) return 0; if (isNoPassAllowed( curuser )) { gconv( GCONV_PASS_ND, 0 ); if (!*curpass) { debug( "accepting despite empty password\n" ); goto done; } } else if (!gconv( GCONV_PASS, 0 )) return 0; enduserdb(); msg = NULL; if ((i = authenticate( curuser, curpass, &reenter, &msg ))) { debug( "authenticate() failed: %s\n", msg ); if (msg) free( msg ); loginfailed( curuser, hostname, tty ); if (i == ENOENT || i == ESAD) V_RET_AUTH; else V_RET_FAIL( 0 ); } if (reenter) { logError( "authenticate() requests more data: %s\n", msg ); free( msg ); V_RET_FAIL( 0 ); } } else if (!strcmp( curtype, "generic" )) { if (!gconv( GCONV_USER, 0 )) return 0; for (curret = 0;;) { msg = NULL; if ((i = authenticate( curuser, curret, &reenter, &msg ))) { debug( "authenticate() failed: %s\n", msg ); if (msg) free( msg ); loginfailed( curuser, hostname, tty ); if (i == ENOENT || i == ESAD) V_RET_AUTH; else V_RET_FAIL( 0 ); } if (curret) free( curret ); if (!reenter) break; if (!(curret = gconv( GCONV_HIDDEN, msg ))) return 0; free( msg ); } } else { logError( "Unsupported authentication type %\"s requested\n", curtype ); V_RET_FAIL( 0 ); } if (msg) { displayStr( V_MSG_INFO, msg ); free( msg ); } done: #else if (strcmp( curtype, "classic" )) { logError( "Unsupported authentication type %\"s requested\n", curtype ); V_RET_FAIL( 0 ); } if (!gconv( GCONV_USER, 0 )) return 0; if (!(p = getpwnam( curuser ))) { debug( "getpwnam() failed.\n" ); gconv( GCONV_PASS, 0 ); V_RET_AUTH; } if (p->pw_passwd[0] == '!' || p->pw_passwd[0] == '*') { debug( "account is locked\n" ); gconv( GCONV_PASS, 0 ); V_RET_AUTH; } # ifdef USESHADOW if ((sp = getspnam( curuser ))) { p->pw_passwd = sp->sp_pwdp; if (p->pw_passwd[0] == '!' || p->pw_passwd[0] == '*') { debug( "account is locked\n" ); gconv( GCONV_PASS, 0 ); V_RET_AUTH; } } else debug( "getspnam() failed: %m. Are you root?\n" ); # endif if (!*p->pw_passwd) { if (!td->allowNullPasswd) { debug( "denying user with empty password\n" ); gconv( GCONV_PASS, 0 ); V_RET_AUTH; } goto nplogin; } if (isNoPassAllowed( curuser, p )) { nplogin: gconv( GCONV_PASS_ND, 0 ); if (!*curpass) { debug( "accepting password-less login\n" ); goto done; } } else if (!gconv( GCONV_PASS, 0 )) return 0; # ifdef KERBEROS if (p->pw_uid) { int ret; char realm[REALM_SZ]; if (krb_get_lrealm( realm, 1 )) { logError( "Cannot get KerberosIV realm.\n" ); V_RET_FAIL( 0 ); } sprintf( krbtkfile, "%s.%.*s", TKT_ROOT, MAXPATHLEN - strlen( TKT_ROOT ) - 2, td->name ); krb_set_tkt_string( krbtkfile ); unlink( krbtkfile ); ret = krb_verify_user( curuser, "", realm, curpass, 1, "rcmd" ); if (ret == KSUCCESS) { chown( krbtkfile, p->pw_uid, p->pw_gid ); debug( "KerberosIV verify succeeded\n" ); goto done; } else if (ret != KDC_PR_UNKNOWN && ret != SKDC_CANT) { logError( "KerberosIV verification failure %\"s for %s\n", krb_get_err_text( ret ), curuser ); krbtkfile[0] = '\0'; V_RET_FAIL( 0 ); } debug( "KerberosIV verify failed: %s\n", krb_get_err_text( ret ) ); } krbtkfile[0] = '\0'; # endif /* KERBEROS */ # if defined(ultrix) || defined(__ultrix__) if (authenticate_user( p, curpass, NULL ) < 0) # elif defined(HAVE_PW_ENCRYPT) if (strcmp( pw_encrypt( curpass, p->pw_passwd ), p->pw_passwd )) # elif defined(HAVE_CRYPT) if (strcmp( crypt( curpass, p->pw_passwd ), p->pw_passwd )) # else if (strcmp( curpass, p->pw_passwd )) # endif { debug( "password verify failed\n" ); V_RET_AUTH; } done: #endif /* !defined(USE_PAM) && !defined(_AIX) */ debug( "restrict %s ...\n", curuser ); #if defined(USE_PAM) || defined(_AIX) if (!(p = getpwnam( curuser ))) { logError( "getpwnam(%s) failed.\n", curuser ); V_RET_FAIL( 0 ); } #endif if (!p->pw_uid) { if (!rootok && !td->allowRootLogin) V_RET_FAIL( "Root logins are not allowed" ); return 1; /* don't deny root to log in */ } #ifdef USE_PAM debug( " pam_acct_mgmt() ...\n" ); pretc = pam_acct_mgmt( pamh, 0 ); reInitErrorLog(); debug( " pam_acct_mgmt() returned: %s\n", pam_strerror( pamh, pretc ) ); if (pretc == PAM_NEW_AUTHTOK_REQD) { pdata.usecur = FALSE; pdata.gconv = conv_interact; /* pam will have output a message already, so no prepareErrorGreet() */ if (gconv != conv_interact || pnopass) { pam_end( pamh, PAM_SUCCESS ); pamh = 0; gSendInt( V_CHTOK_AUTH ); /* this cannot auth the wrong user, as only classic auths get here */ while (!doPAMAuth( PAMService, &pdata )) if (pdata.abort) return 0; gSendInt( V_PRE_OK ); } else gSendInt( V_CHTOK ); for (;;) { debug( " pam_chauthtok() ...\n" ); pretc = pam_chauthtok( pamh, PAM_CHANGE_EXPIRED_AUTHTOK ); reInitErrorLog(); debug( " pam_chauthtok() returned: %s\n", pam_strerror( pamh, pretc ) ); if (pdata.abort) { pam_end( pamh, PAM_SUCCESS ); pamh = 0; return 0; } if (pretc == PAM_SUCCESS) break; /* effectively there is only PAM_AUTHTOK_ERR */ gSendInt( V_FAIL ); } if (curpass) free( curpass ); curpass = newpass; newpass = 0; } else if (pretc != PAM_SUCCESS) { pam_end( pamh, pretc ); pamh = 0; V_RET_AUTH; } #elif defined(_AIX) /* USE_PAM */ msg = NULL; if (loginrestrictions( curuser, ((td->displayType & d_location) == dForeign) ? S_RLOGIN : S_LOGIN, tty, &msg ) == -1) { debug( "loginrestrictions() - %s\n", msg ? msg : "error" ); loginfailed( curuser, hostname, tty ); prepareErrorGreet(); if (msg) { displayStr( V_MSG_ERR, msg ); free( msg ); } gSendInt( V_AUTH ); return 0; } if (msg) free( (void *)msg ); #endif /* USE_PAM || _AIX */ #ifndef _AIX # ifdef HAVE_SETUSERCONTEXT # ifdef HAVE_LOGIN_GETCLASS lc = login_getclass( p->pw_class ); # else lc = login_getpwclass( p ); # endif if (!lc) V_RET_FAIL( 0 ); p->pw_shell = login_getcapstr( lc, "shell", p->pw_shell, p->pw_shell ); # endif # ifndef USE_PAM /* restrict_expired */ # if defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || defined(USESHADOW) # if !defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || (!defined(HAVE_SETUSERCONTEXT) && defined(USESHADOW)) if (sp) # endif { # define DEFAULT_WARN (2L * 7L) /* Two weeks */ tim = time( NULL ) / 86400L; # ifdef HAVE_SETUSERCONTEXT quietlog = login_getcapbool( lc, "hushlogin", 0 ); warntime = login_getcaptime( lc, "warnexpire", DEFAULT_WARN * 86400L, DEFAULT_WARN * 86400L ) / 86400L; # else quietlog = 0; # ifdef USESHADOW warntime = sp->sp_warn != -1 ? sp->sp_warn : DEFAULT_WARN; # else warntime = DEFAULT_WARN; # endif # endif # ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE if (p->pw_expire) { expir = p->pw_expire / 86400L; # else if (sp->sp_expire != -1) { expir = sp->sp_expire; # endif if (tim > expir) { displayStr( V_MSG_ERR, "Your account has expired;" " please contact your system administrator" ); gSendInt( V_FAIL ); LC_RET0; } else if (tim > (expir - warntime) && !quietlog) { displayMsg( V_MSG_INFO, "Warning: your account will expire in %d day(s)", expir - tim ); } } # ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE if (p->pw_change) { expir = p->pw_change / 86400L; # else if (!sp->sp_lstchg) { displayStr( V_MSG_ERR, "You are required to change your password immediately" " (root enforced)" ); /* XXX todo password change */ gSendInt( V_FAIL ); LC_RET0; } else if (sp->sp_max != -1) { expir = sp->sp_lstchg + sp->sp_max; if (sp->sp_inact != -1 && tim > expir + sp->sp_inact) { displayStr( V_MSG_ERR, "Your account has expired;" " please contact your system administrator" ); gSendInt( V_FAIL ); LC_RET0; } # endif if (tim > expir) { displayStr( V_MSG_ERR, "You are required to change your password immediately" " (password aged)" ); /* XXX todo password change */ gSendInt( V_FAIL ); LC_RET0; } else if (tim > (expir - warntime) && !quietlog) { displayMsg( V_MSG_INFO, "Warning: your password will expire in %d day(s)", expir - tim ); } } } # endif /* HAVE_STRUCT_PASSWD_PW_EXPIRE || USESHADOW */ /* restrict_nologin */ # ifndef _PATH_NOLOGIN # define _PATH_NOLOGIN "/etc/nologin" # endif if (( # ifdef HAVE_SETUSERCONTEXT /* Do we ignore a nologin file? */ !login_getcapbool( lc, "ignorenologin", 0 )) && (!stat( (nolg = login_getcapstr( lc, "nologin", "", NULL )), &st ) || # endif !stat( (nolg = _PATH_NOLOGIN), &st ))) { if (st.st_size && (fd = open( nolg, O_RDONLY )) >= 0) { if ((buf = Malloc( st.st_size + 1 ))) { if (read( fd, buf, st.st_size ) == st.st_size) { close( fd ); buf[st.st_size] = 0; displayStr( V_MSG_ERR, buf ); free( buf ); gSendInt( V_FAIL ); LC_RET0; } free( buf ); } close( fd ); } displayStr( V_MSG_ERR, "Logins are not allowed at the moment.\nTry again later" ); gSendInt( V_FAIL ); LC_RET0; } /* restrict_time */ # if defined(HAVE_SETUSERCONTEXT) && defined(HAVE_AUTH_TIMEOK) if (!auth_timeok( lc, time( NULL ) )) { displayStr( V_MSG_ERR, "You are not allowed to login at the moment" ); gSendInt( V_FAIL ); LC_RET0; } # endif # ifdef HAVE_GETUSERSHELL for (;;) { if (!(s = getusershell())) { debug( "shell not in /etc/shells\n" ); endusershell(); V_RET_FAIL( "Your login shell is not listed in /etc/shells" ); } if (!strcmp( s, p->pw_shell )) { endusershell(); break; } } # endif # endif /* !USE_PAM */ /* restrict_nohome */ # ifdef HAVE_SETUSERCONTEXT if (login_getcapbool( lc, "requirehome", 0 )) { struct stat st; if (!*p->pw_dir || stat( p->pw_dir, &st ) || st.st_uid != p->pw_uid) { displayStr( V_MSG_ERR, "Home folder not available" ); gSendInt( V_FAIL ); LC_RET0; } } # endif #endif /* !_AIX */ return 1; } static const char *envvars[] = { "TZ", /* SYSV and SVR4, but never hurts */ #ifdef _AIX "AUTHSTATE", /* for kerberos */ #endif NULL }; #if defined(USE_PAM) && defined(HAVE_INITGROUPS) static int num_saved_gids; static gid_t *saved_gids; static int saveGids( void ) { num_saved_gids = getgroups( 0, 0 ); if (!(saved_gids = Malloc( sizeof(gid_t) * num_saved_gids ))) return 0; if (getgroups( num_saved_gids, saved_gids ) < 0) { logError( "saving groups failed: %m\n" ); return 0; } return 1; } static int restoreGids( void ) { if (setgroups( num_saved_gids, saved_gids ) < 0) { logError( "restoring groups failed: %m\n" ); return 0; } if (setgid( p->pw_gid ) < 0) { logError( "restoring gid failed: %m\n" ); return 0; } return 1; } #endif /* USE_PAM && HAVE_INITGROUPS */ static int resetGids( void ) { #ifdef HAVE_INITGROUPS if (setgroups( 0, &p->pw_gid /* anything */ ) < 0) { logError( "restoring groups failed: %m\n" ); return 0; } #endif if (setgid( 0 ) < 0) { logError( "restoring gid failed: %m\n" ); return 0; } return 1; } static int setGid( const char *name, int gid ) { if (setgid( gid ) < 0) { logError( "setgid(%d) (user %s) failed: %m\n", gid, name ); return 0; } #ifdef HAVE_INITGROUPS if (initgroups( name, gid ) < 0) { logError( "initgroups for %s failed: %m\n", name ); setgid( 0 ); return 0; } #endif /* QNX4 doesn't support multi-groups, no initgroups() */ return 1; } static int setUid( const char *name, int uid ) { if (setuid( uid ) < 0) { logError( "setuid(%d) (user %s) failed: %m\n", uid, name ); return 0; } return 1; } static int setUser( const char *name, int uid, int gid ) { if (setGid( name, gid )) { if (setUid( name, uid )) return 1; resetGids(); } return 0; } #if defined(SECURE_RPC) || defined(K5AUTH) static void nukeAuth( int len, const char *name ) { int i; for (i = 0; i < td->authNum; i++) if (td->authorizations[i]->name_length == len && !memcmp( td->authorizations[i]->name, name, len )) { memcpy( &td->authorizations[i], &td->authorizations[i+1], sizeof(td->authorizations[i]) * (--td->authNum - i) ); break; } } #endif static void mergeSessionArgs( int cansave ) { char *mfname; const char *fname; int i, needsave; mfname = 0; fname = ".dmrc"; if ((!curdmrc || newdmrc) && *dmrcDir) if (strApp( &mfname, dmrcDir, "/", curuser, fname, (char *)0 )) fname = mfname; needsave = 0; if (!curdmrc) { curdmrc = iniLoad( fname ); if (!curdmrc) { strDup( &curdmrc, "[Desktop]\nSession=default\n" ); needsave = 1; } } if (newdmrc) { curdmrc = iniMerge( curdmrc, newdmrc ); needsave = 1; } if (needsave && cansave) if (!iniSave( curdmrc, fname ) && errno == ENOENT && mfname) { for (i = 0; mfname[i]; i++) if (mfname[i] == '/') { mfname[i] = 0; mkdir( mfname, 0755 ); mfname[i] = '/'; } iniSave( curdmrc, mfname ); } if (mfname) free( mfname ); } static int createClientLog( const char *log ) { char randstr[32], *randstrp = 0, *lname; int lfd; for (;;) { struct expando macros[] = { { 'd', 0, td->name }, { 'u', 0, curuser }, { 'r', 0, randstrp }, { 0, 0, 0 } }; if (!(lname = expandMacros( log, macros ))) exit( 1 ); unlink( lname ); if ((lfd = open( lname, O_WRONLY|O_CREAT|O_EXCL, 0600 )) >= 0) { dup2( lfd, 1 ); dup2( lfd, 2 ); close( lfd ); free( lname ); return TRUE; } if (errno != EEXIST || !macros[2].uses) { free( lname ); return FALSE; } logInfo( "Session log file %s not usable, trying another one.\n", lname ); free( lname ); sprintf( randstr, "%d", secureRandom() ); randstrp = randstr; } }
static int chk_kerberos( const struct berval *sc, const struct berval * passwd, const struct berval * cred, const char **text ) { unsigned int i; int rtn; for( i=0; i<cred->bv_len; i++) { if(cred->bv_val[i] == '\0') { return LUTIL_PASSWD_ERR; /* NUL character in password */ } } if( cred->bv_val[i] != '\0' ) { return LUTIL_PASSWD_ERR; /* cred must behave like a string */ } for( i=0; i<passwd->bv_len; i++) { if(passwd->bv_val[i] == '\0') { return LUTIL_PASSWD_ERR; /* NUL character in password */ } } if( passwd->bv_val[i] != '\0' ) { return LUTIL_PASSWD_ERR; /* passwd must behave like a string */ } rtn = LUTIL_PASSWD_ERR; #ifdef HAVE_KRB5 /* HAVE_HEIMDAL_KRB5 */ { /* Portions: * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska H\xf6gskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ krb5_context context; krb5_error_code ret; krb5_creds creds; krb5_get_init_creds_opt get_options; krb5_verify_init_creds_opt verify_options; krb5_principal client, server; #ifdef notdef krb5_preauthtype pre_auth_types[] = {KRB5_PADATA_ENC_TIMESTAMP}; #endif ret = krb5_init_context( &context ); if (ret) { return LUTIL_PASSWD_ERR; } #ifdef notdef krb5_get_init_creds_opt_set_preauth_list(&get_options, pre_auth_types, 1); #endif krb5_get_init_creds_opt_init( &get_options ); krb5_verify_init_creds_opt_init( &verify_options ); ret = krb5_parse_name( context, passwd->bv_val, &client ); if (ret) { krb5_free_context( context ); return LUTIL_PASSWD_ERR; } ret = krb5_get_init_creds_password( context, &creds, client, cred->bv_val, NULL, NULL, 0, NULL, &get_options ); if (ret) { krb5_free_principal( context, client ); krb5_free_context( context ); return LUTIL_PASSWD_ERR; } { char *host = ldap_pvt_get_fqdn( NULL ); if( host == NULL ) { krb5_free_principal( context, client ); krb5_free_context( context ); return LUTIL_PASSWD_ERR; } ret = krb5_sname_to_principal( context, host, "ldap", KRB5_NT_SRV_HST, &server ); ber_memfree( host ); } if (ret) { krb5_free_principal( context, client ); krb5_free_context( context ); return LUTIL_PASSWD_ERR; } ret = krb5_verify_init_creds( context, &creds, server, NULL, NULL, &verify_options ); krb5_free_principal( context, client ); krb5_free_principal( context, server ); krb5_free_cred_contents( context, &creds ); krb5_free_context( context ); rtn = ret ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; } #elif defined(HAVE_KRB4) { /* Borrowed from Heimdal kpopper */ /* Portions: * Copyright (c) 1989 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ int status; char lrealm[REALM_SZ]; char tkt[MAXHOSTNAMELEN]; status = krb_get_lrealm(lrealm,1); if (status == KFAILURE) { return LUTIL_PASSWD_ERR; } snprintf(tkt, sizeof(tkt), "%s_slapd.%u", TKT_ROOT, (unsigned)getpid()); krb_set_tkt_string (tkt); status = krb_verify_user( passwd->bv_val, "", lrealm, cred->bv_val, 1, "ldap"); dest_tkt(); /* no point in keeping the tickets */ return status == KFAILURE ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; } #endif return rtn; }
int Verify (struct display *d, struct greet_info *greet, struct verify_info *verify) { struct passwd *p; login_cap_t *lc; auth_session_t *as; char *style, *shell, *home, *s, **argv; char path[MAXPATHLEN]; int authok; /* User may have specified an authentication style. */ if ((style = strchr(greet->name, ':')) != NULL) *style++ = '\0'; Debug ("Verify %s, style %s ...\n", greet->name, style ? style : "default"); p = getpwnam (greet->name); endpwent(); if (!p || strlen (greet->name) == 0) { Debug("getpwnam() failed.\n"); bzero(greet->password, strlen(greet->password)); return 0; } if ((lc = login_getclass(p->pw_class)) == NULL) { Debug("login_getclass() failed.\n"); bzero(greet->password, strlen(greet->password)); return 0; } if ((style = login_getstyle(lc, style, "xdm")) == NULL) { Debug("login_getstyle() failed.\n"); bzero(greet->password, strlen(greet->password)); return 0; } if ((as = auth_open()) == NULL) { Debug("auth_open() failed.\n"); login_close(lc); bzero(greet->password, strlen(greet->password)); return 0; } if (auth_setoption(as, "login", "yes") == -1) { Debug("auth_setoption() failed.\n"); login_close(lc); bzero(greet->password, strlen(greet->password)); return 0; } /* Set up state for no challenge, just check a response. */ auth_setstate(as, 0); auth_setdata(as, "", 1); auth_setdata(as, greet->password, strlen(greet->password) + 1); /* Build path of the auth script and call it */ snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style); auth_call(as, path, style, "-s", "response", greet->name, lc->lc_class, (void *)NULL); authok = auth_getstate(as); if ((authok & AUTH_ALLOW) == 0) { Debug("password verify failed\n"); bzero(greet->password, strlen(greet->password)); auth_close(as); login_close(lc); return 0; } /* Run the approval script */ if (!auth_approval(as, lc, greet->name, "auth-xdm")) { Debug("login not approved\n"); bzero(greet->password, strlen(greet->password)); auth_close(as); login_close(lc); return 0; } auth_close(as); login_close(lc); /* Check empty passwords against allowNullPasswd */ if (!greet->allow_null_passwd && strlen(greet->password) == 0) { Debug("empty password not allowed\n"); return 0; } /* Only accept root logins if allowRootLogin resource is set */ if (p->pw_uid == 0 && !greet->allow_root_login) { Debug("root logins not allowed\n"); bzero(greet->password, strlen(greet->password)); return 0; } /* * Shell must be in /etc/shells */ for (;;) { s = getusershell(); if (s == NULL) { /* did not found the shell in /etc/shells -> failure */ Debug("shell not in /etc/shells\n"); bzero(greet->password, strlen(greet->password)); endusershell(); return 0; } if (strcmp(s, p->pw_shell) == 0) { /* found the shell in /etc/shells */ endusershell(); break; } } #else /* !USE_BSDAUTH */ int Verify (struct display *d, struct greet_info *greet, struct verify_info *verify) { struct passwd *p; #ifdef USE_PAM pam_handle_t **pamhp = thepamhp(); #else #ifdef USESHADOW struct spwd *sp; #endif char *user_pass = NULL; #endif #ifdef __OpenBSD__ char *s; struct timeval tp; #endif char *shell, *home; char **argv; Debug ("Verify %s ...\n", greet->name); #if defined(sun) && defined(SVR4) /* Solaris: If CONSOLE is set to /dev/console in /etc/default/login, then root can only login on system console */ # define SOLARIS_LOGIN_DEFAULTS "/etc/default/login" if (strcmp(greet->name, "root") == 0) { char *console = NULL, *tmp = NULL; FILE *fs; if ((fs= fopen(SOLARIS_LOGIN_DEFAULTS, "r")) != NULL) { char str[120]; while (!feof(fs)) { fgets(str, 120, fs); if(str[0] == '#' || strlen(str) < 8) continue; if((tmp = strstr(str, "CONSOLE=")) != NULL) console = strdup((tmp+8)); } fclose(fs); if ( console != NULL && (strncmp(console, "/dev/console", 12) == 0) && (strncmp(d->name,":0",2) != 0) ) { Debug("Not on system console\n"); bzero(greet->password, strlen(greet->password)); XFree(console); return 0; } XFree(console); } else { Debug("Could not open %s\n", SOLARIS_LOGIN_DEFAULTS); } } #endif #ifndef USE_PAM p = getpwnam (greet->name); endpwent(); if (!p || strlen (greet->name) == 0) { Debug ("getpwnam() failed.\n"); bzero(greet->password, strlen(greet->password)); return 0; } else { #ifdef linux if (!strcmp(p->pw_passwd, "!") || !strcmp(p->pw_passwd, "*")) { Debug ("The account is locked, no login allowed.\n"); bzero(greet->password, strlen(greet->password)); return 0; } #endif user_pass = p->pw_passwd; } #endif #ifdef KERBEROS if(strcmp(greet->name, "root") != 0){ char name[ANAME_SZ]; char realm[REALM_SZ]; char *q; int ret; if(krb_get_lrealm(realm, 1)){ Debug ("Can't get Kerberos realm.\n"); } else { sprintf(krbtkfile, "%s.%s", TKT_ROOT, d->name); krb_set_tkt_string(krbtkfile); unlink(krbtkfile); ret = krb_verify_user(greet->name, "", realm, greet->password, 1, "rcmd"); if(ret == KSUCCESS){ chown(krbtkfile, p->pw_uid, p->pw_gid); Debug("kerberos verify succeeded\n"); if (k_hasafs()) { if (k_setpag() == -1) LogError ("setpag() failed for %s\n", greet->name); if((ret = k_afsklog(NULL, NULL)) != KSUCCESS) LogError("Warning %s\n", krb_get_err_text(ret)); } goto done; } else if(ret != KDC_PR_UNKNOWN && ret != SKDC_CANT){ /* failure */ Debug("kerberos verify failure %d\n", ret); krbtkfile[0] = '\0'; } } } #endif #ifndef USE_PAM #ifdef USESHADOW errno = 0; sp = getspnam(greet->name); if (sp == NULL) { Debug ("getspnam() failed, errno=%d. Are you root?\n", errno); } else { user_pass = sp->sp_pwdp; } #ifndef QNX4 endspent(); #endif /* QNX4 doesn't need endspent() to end shadow passwd ops */ #endif #if defined(ultrix) || defined(__ultrix__) if (authenticate_user(p, greet->password, NULL) < 0) #else if (strcmp (crypt (greet->password, user_pass), user_pass)) #endif { if(!greet->allow_null_passwd || strlen(p->pw_passwd) > 0) { Debug ("password verify failed\n"); bzero(greet->password, strlen(greet->password)); return 0; } /* else: null passwd okay */ } #ifdef KERBEROS done: #endif #ifdef __OpenBSD__ /* * Only accept root logins if allowRootLogin resource is set */ if ((p->pw_uid == 0) && !greet->allow_root_login) { Debug("root logins not allowed\n"); bzero(greet->password, strlen(greet->password)); return 0; } /* * Shell must be in /etc/shells */ for (;;) { s = getusershell(); if (s == NULL) { /* did not found the shell in /etc/shells -> failure */ Debug("shell not in /etc/shells\n"); bzero(greet->password, strlen(greet->password)); endusershell(); return 0; } if (strcmp(s, p->pw_shell) == 0) { /* found the shell in /etc/shells */ endusershell(); break; } } /* * Test for expired password */ if (p->pw_change || p->pw_expire) (void)gettimeofday(&tp, (struct timezone *)NULL); if (p->pw_change) { if (tp.tv_sec >= p->pw_change) { Debug("Password has expired.\n"); bzero(greet->password, strlen(greet->password)); return 0; } } if (p->pw_expire) { if (tp.tv_sec >= p->pw_expire) { Debug("account has expired.\n"); bzero(greet->password, strlen(greet->password)); return 0; } } #endif /* __OpenBSD__ */ bzero(user_pass, strlen(user_pass)); /* in case shadow password */ #else /* USE_PAM */ #define PAM_BAIL \ if (pam_error != PAM_SUCCESS) goto pam_failed; PAM_password = greet->password; pam_error = pam_start("xdm", greet->name, &PAM_conversation, pamhp); PAM_BAIL; pam_error = pam_set_item(*pamhp, PAM_TTY, d->name); PAM_BAIL; pam_error = pam_set_item(*pamhp, PAM_RHOST, ""); PAM_BAIL; pam_error = pam_authenticate(*pamhp, 0); PAM_BAIL; pam_error = pam_acct_mgmt(*pamhp, 0); /* really should do password changing, but it doesn't fit well */ PAM_BAIL; pam_error = pam_setcred(*pamhp, 0); PAM_BAIL; p = getpwnam (greet->name); endpwent(); if (!p || strlen (greet->name) == 0) { Debug ("getpwnam() failed.\n"); bzero(greet->password, strlen(greet->password)); return 0; } if (pam_error != PAM_SUCCESS) { pam_failed: pam_end(*pamhp, PAM_SUCCESS); *pamhp = NULL; return 0; } #undef PAM_BAIL #endif /* USE_PAM */ #endif /* USE_BSDAUTH */ Debug ("verify succeeded\n"); /* The password is passed to StartClient() for use by user-based authorization schemes. It is zeroed there. */ verify->uid = p->pw_uid; verify->gid = p->pw_gid; home = p->pw_dir; shell = p->pw_shell; argv = 0; if (d->session) argv = parseArgs (argv, d->session); if (greet->string) argv = parseArgs (argv, greet->string); if (!argv) argv = parseArgs (argv, "xsession"); verify->argv = argv; verify->userEnviron = userEnv (d, p->pw_uid == 0, greet->name, home, shell); Debug ("user environment:\n"); printEnv (verify->userEnviron); verify->systemEnviron = systemEnv (d, greet->name, home); Debug ("system environment:\n"); printEnv (verify->systemEnviron); Debug ("end of environments\n"); return 1; }