static void set_tkt_string(uid_t uid) { char buf[128]; snprintf(buf, sizeof(buf), "%s%u", TKT_ROOT, (unsigned)uid); krb_set_tkt_string(buf); #if 0 /* pam_set_data+pam_get_data are not guaranteed to work, grr. */ pam_set_data(pamh, "KRBTKFILE", strdup(t), cleanup); if (pam_get_data(pamh, "KRBTKFILE", (const void**)&tkt) == PAM_SUCCESS) { pam_putenv(pamh, var); } #endif /* We don't want to inherit this variable. * If we still do, it must have a sane value. */ if (getenv("KRBTKFILE") != 0) { char *var = malloc(sizeof(buf)); snprintf(var, sizeof(buf), "KRBTKFILE=%s", tkt_string()); putenv(var); /* free(var); XXX */ } }
static void set_krbtkfile(uid_t uid) { snprintf (krbtkfile, sizeof(krbtkfile), "%s%d", TKT_ROOT, (unsigned)uid); krb_set_tkt_string (krbtkfile); correct_tkfilename = 1; }
int kerb4_verify(struct passwd *pw, char *pass, sudo_auth *auth) { char tkfile[sizeof(_PATH_SUDO_TIMEDIR) + 4 + MAX_UID_T_LEN]; char *realm = (char *) auth->data; int error; /* * Set the ticket file to be in sudo sudo timedir so we don't * wipe out other (real) kerberos tickets. */ (void) snprintf(tkfile, sizeof(tkfile), "%s/tkt%u", _PATH_SUDO_TIMEDIR, (unsigned int) pw->pw_uid); (void) krb_set_tkt_string(tkfile); /* Convert the password to a ticket given. */ error = krb_get_pw_in_tkt(pw->pw_name, "", realm, "krbtgt", realm, DEFAULT_TKT_LIFE, pass); switch (error) { case INTK_OK: dest_tkt(); /* we are done with the temp ticket */ return AUTH_SUCCESS; break; case INTK_BADPW: case KDC_PR_UNKNOWN: break; default: (void) fprintf(stderr, "Warning: Kerberos error: %s\n", krb_err_txt[error]); } return AUTH_FAILURE; }
int rkinit(char *host, char *r_krealm, rkinit_info *info, int timeout) { int status; int version = 0; char phost[MAXHOSTNAMELEN]; jmp_buf timeout_env; struct sigaction osa; char origtktfilename[MAXPATHLEN]; /* original ticket file name */ char tktfilename[MAXPATHLEN]; /* temporary client ticket file */ BCLEAR(phost); BCLEAR(origtktfilename); BCLEAR(tktfilename); BCLEAR(timeout_env); initialize_rkin_error_table(); status = rki_setup_rpc(host); if (status) return(status); /* The alarm handler longjmps us to here. */ status = setjmp(timeout_env); if (status == 0) { strcpy(origtktfilename, tkt_string()); sprintf(tktfilename, "/tmp/tkt_rkinit.%lu", (unsigned long)getpid()); krb_set_tkt_string(tktfilename); if (timeout) rki_setup_timer(timeout_env, &osa); status = rki_choose_version(&version); if (status == RKINIT_SUCCESS) status = rki_get_tickets(version, host, r_krealm, info); } if (timeout) rki_restore_timer(&osa); dest_tkt(); krb_set_tkt_string(origtktfilename); rki_cleanup_rpc(); return(status); }
static int krb4_init(void *context) { static int cleanup_registered = 0; Authctxt *authctxt = (Authctxt *)context; const char *tkt_root = TKT_ROOT; struct stat st; int fd; if (!authctxt->krb4_ticket_file) { /* Set unique ticket string manually since we're still root. */ authctxt->krb4_ticket_file = xmalloc(MAXPATHLEN); #ifdef AFS if (lstat("/ticket", &st) != -1) tkt_root = "/ticket/"; #endif /* AFS */ snprintf(authctxt->krb4_ticket_file, MAXPATHLEN, "%s%u_%ld", tkt_root, authctxt->pw->pw_uid, (long)getpid()); krb_set_tkt_string(authctxt->krb4_ticket_file); } /* Register ticket cleanup in case of fatal error. */ if (!cleanup_registered) { fatal_add_cleanup(krb4_cleanup_proc, authctxt); cleanup_registered = 1; } /* Try to create our ticket file. */ if ((fd = mkstemp(authctxt->krb4_ticket_file)) != -1) { close(fd); return (1); } /* Ticket file exists - make sure user owns it (just passed ticket). */ if (lstat(authctxt->krb4_ticket_file, &st) != -1) { if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) && st.st_uid == authctxt->pw->pw_uid) return (1); } /* Failure - cancel cleanup function, leaving ticket for inspection. */ log("WARNING: bad ticket file %s", authctxt->krb4_ticket_file); fatal_remove_cleanup(krb4_cleanup_proc, authctxt); cleanup_registered = 0; xfree(authctxt->krb4_ticket_file); authctxt->krb4_ticket_file = NULL; return (0); }
static void set_spec_krbtkfile(void) { int fd; #ifdef KRB4 snprintf (krbtkfile, sizeof(krbtkfile), "%s_XXXXXX", TKT_ROOT); fd = mkstemp(krbtkfile); close(fd); unlink(krbtkfile); krb_set_tkt_string (krbtkfile); #endif #ifdef KRB5 snprintf(krb5ccname, sizeof(krb5ccname),"FILE:/tmp/krb5cc_XXXXXX"); fd=mkstemp(krb5ccname+5); close(fd); unlink(krb5ccname+5); #endif }
/******************************************************************* 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 void UpdateDefaultCache (void) { cc_string_t name; cc_int32 cc_err = ccNoError; cc_context_t cc_context = NULL; cc_int32 cc_version; cc_err = cc_initialize (&cc_context, ccapi_version_3, &cc_version, NULL); if (cc_err == ccNoError) { cc_err = cc_context_get_default_ccache_name (cc_context, &name); } if (cc_err == ccNoError) { krb_set_tkt_string ((char*) name -> data); cc_string_release (name); } if (cc_context != NULL) cc_context_release (cc_context); }
/* * pg_krb4_init -- initialization performed before any Kerberos calls are made * * For v4, all we need to do is make sure the library routines get the right * ticket file if we want them to see a special one. (They will open the file * themselves.) */ static void pg_krb4_init() { char *realm; static int init_done = 0; if (init_done) return; init_done = 1; /* * If the user set PGREALM, then we use a ticket file with a special * name: <usual-ticket-file-name>@<PGREALM-value> */ if ((realm = getenv("PGREALM"))) { char tktbuf[MAXPGPATH]; (void) snprintf(tktbuf, sizeof(tktbuf), "%s@%s", tkt_string(), realm); krb_set_tkt_string(tktbuf); } }
static int _pam_krb5_v4_init(krb5_context ctx, struct _pam_krb5_stash *stash, struct _pam_krb5_user_info *user, struct _pam_krb5_options *options, char *sname, char *sinstance, char *password, int *result) { char name[ANAME_SZ + 1], instance[INST_SZ + 1], realm[REALM_SZ + 1]; char pname[ANAME_SZ + 1], pinstance[INST_SZ + 1]; char tktfile[PATH_MAX]; char *saved_tktstring; int life, i, fd; struct stat st; /* Convert the krb5 version of the principal's name to a v4 principal * name. This may involve changing "host" to "rcmd" and so on, so let * libkrb5 handle it. */ memset(name, '\0', sizeof(name)); memset(instance, '\0', sizeof(instance)); memset(realm, '\0', sizeof(realm)); i = krb5_524_conv_principal(ctx, user->principal_name, name, instance, realm); if (i != 0) { if (result) { *result = i; } return PAM_SERVICE_ERR; } if (options->debug) { debug("converted principal to '%s%s%s%s@'%s'", name, strlen(instance) ? "'.'" : "'", instance, strlen(instance) ? "'" : "", realm); } #ifdef HAVE_KRB_TIME_TO_LIFE /* Convert the ticket lifetime of the v5 credentials into a v4 * lifetime, which is the X coordinate along a curve where Y is the * actual length. Again, this is magic. */ life = krb_time_to_life(stash->v5creds.times.starttime, stash->v5creds.times.endtime); #else /* No life_to_time() function means that we have to estimate the * intended lifetime, in 5-minute increments. We also have a maximum * value to contend with, because the lifetime is expressed in a single * byte. */ life = stash->v5creds.times.endtime - stash->v5creds.times.starttime; life /= (60 * 5); if (life > 0xff) { life = 0xff; } #endif /* Create the ticket file. One of two things will happen here. Either * libkrb[4] will just use the file, and we're safer because it * wouldn't have used O_EXCL to do so, or it will nuke the file and * reopen it with O_EXCL. In the latter case, the descriptor we have * will become useless, so we don't actually use it for anything. */ #ifdef HAVE_LONG_LONG snprintf(tktfile, sizeof(tktfile), "%s/tkt%llu_XXXXXX", options->ccache_dir, options->user_check ? (unsigned long long) user->uid : (unsigned long long) getuid()); #else snprintf(tktfile, sizeof(tktfile), "%s/tkt%lu_XXXXXX", options->ccache_dir, options->user_check ? (unsigned long) user->uid : (unsigned long) getuid()); #endif fd = mkstemp(tktfile); if (fd == -1) { if (result) { *result = errno; } return PAM_SERVICE_ERR; } if (fchown(fd, getuid(), getgid()) != 0) { warn("error setting permissions on \"%s\" (%s), attempting " "to continue", tktfile, strerror(errno)); } if (options->debug) { debug("preparing to place v4 credentials in '%s'", tktfile); } /* Save the old default ticket file name, and set the default to use * our just-created empty file. */ saved_tktstring = xstrdup(tkt_string()); krb_set_tkt_string(tktfile); /* Get the initial credentials. */ i = krb_get_pw_in_tkt(name, instance, realm, sname, sinstance ? sinstance : realm, life, password); if (result) { *result = i; } /* Restore the original default ticket file name. */ krb_set_tkt_string(saved_tktstring); xstrfree(saved_tktstring); saved_tktstring = NULL; /* If we got credentials, read them from the file, and then remove the * file. */ if (i == 0) { i = tf_init(tktfile, R_TKT_FIL); if (i == 0) { i = tf_get_pname(pname); if (i == 0) { i = tf_get_pinst(pinstance); if (i == 0) { i = tf_get_cred(&stash->v4creds); if (i == 0) { tf_close(); unlink(tktfile); close(fd); return PAM_SUCCESS; } else { warn("error reading creds " "from '%s': %d (%s)", tktfile, i, v5_error_message(i)); } } else { warn("error reading instance from '%s'" ": %d (%s)", tktfile, i, v5_error_message(i)); } } else { warn("error reading principal name from '%s'" ": %d (%s)", tktfile, i, v5_error_message(i)); } tf_close(); } else { const char *tferror; switch (i) { case NO_TKT_FIL: tferror = "no ticket file"; break; case TKT_FIL_ACC: tferror = "ticket file had wrong permissions"; break; case TKT_FIL_LCK: tferror = "error locking ticket file"; break; default: tferror = strerror(errno); break; } warn("error opening '%s' for reading: %s", tktfile, tferror); if ((i == TKT_FIL_ACC) && (options->debug)) { if (stat(tktfile, &st) == 0) { debug("file owner is %lu:%lu, " "we are effective %lu:%lu, " "real %lu:%lu", (unsigned long) st.st_uid, (unsigned long) st.st_gid, (unsigned long) geteuid(), (unsigned long) getegid(), (unsigned long) getuid(), (unsigned long) getgid()); } } } } unlink(tktfile); close(fd); return PAM_AUTH_ERR; }
/* * Retrieval from credentials cache */ int KRB5_CALLCONV krb_get_cred ( char* service, char* instance, char* realm, CREDENTIALS* creds) { int kerr = KSUCCESS; cc_int32 cc_err = ccNoError; cc_credentials_t theCreds = NULL; cc_credentials_iterator_t iterator = NULL; cc_context_t cc_context = NULL; cc_int32 cc_version; cc_ccache_t ccache = NULL; #ifdef USE_LOGIN_LIBRARY // If we are requesting a tgt, prompt for it if (strncmp (service, KRB_TICKET_GRANTING_TICKET, ANAME_SZ) == 0) { OSStatus err; char *cacheName; KLPrincipal outPrincipal; err = __KLInternalAcquireInitialTicketsForCache (TKT_FILE, kerberosVersion_V4, NULL, &outPrincipal, &cacheName); if (err == klNoErr) { krb_set_tkt_string (cacheName); // Tickets for the krb4 principal went here KLDisposeString (cacheName); KLDisposePrincipal (outPrincipal); } else { return GC_NOTKT; } } #endif /* USE_LOGIN_LIBRARY */ cc_err = cc_initialize (&cc_context, ccapi_version_3, &cc_version, NULL); if (cc_err == ccNoError) { cc_err = cc_context_open_ccache (cc_context, TKT_FILE, &ccache); } if (cc_err == ccNoError) { cc_err = cc_ccache_new_credentials_iterator (ccache, &iterator); } if (cc_err == ccNoError) { for (;;) { /* get next creds */ cc_err = cc_credentials_iterator_next (iterator, &theCreds); if (cc_err == ccIteratorEnd) { kerr = GC_NOTKT; break; } if (cc_err != ccNoError) { kerr = KFAILURE; break; } /* version, service, instance, realm check */ if ((theCreds -> data -> version == cc_credentials_v4) && (strcmp (theCreds -> data -> credentials.credentials_v4 -> service, service) == 0) && (strcmp (theCreds -> data -> credentials.credentials_v4 -> service_instance, instance) == 0) && (strcmp (theCreds -> data -> credentials.credentials_v4 -> realm, realm) == 0)) { /* Match! */ strcpy (creds -> service, service); strcpy (creds -> instance, instance); strcpy (creds -> realm, realm); memmove (creds -> session, theCreds -> data -> credentials.credentials_v4 -> session_key, sizeof (C_Block)); creds -> lifetime = theCreds -> data -> credentials.credentials_v4 -> lifetime; creds -> kvno = theCreds -> data -> credentials.credentials_v4 -> kvno; creds -> ticket_st.length = theCreds -> data -> credentials.credentials_v4 -> ticket_size; memmove (creds -> ticket_st.dat, theCreds -> data -> credentials.credentials_v4 -> ticket, creds -> ticket_st.length); creds -> issue_date = theCreds -> data -> credentials.credentials_v4 -> issue_date; strcpy (creds -> pname, theCreds -> data -> credentials.credentials_v4 -> principal); strcpy (creds -> pinst, theCreds -> data -> credentials.credentials_v4 -> principal_instance); creds -> stk_type = theCreds -> data -> credentials.credentials_v4 -> string_to_key_type; cc_credentials_release (theCreds); kerr = KSUCCESS; break; } else { cc_credentials_release (theCreds); } } } if (iterator != NULL) cc_credentials_iterator_release (iterator); if (ccache != NULL) cc_ccache_release (ccache); if (cc_context != NULL) cc_context_release (cc_context); if (kerr != KSUCCESS) return kerr; if (cc_err != ccNoError) return GC_NOTKT; else return KSUCCESS; }
int get_tickets(int version) { rkinit_info info; AUTH_DAT auth_dat; int status; char errmsg[BUFSIZ]; /* error message for client */ rkinitd_intkt_info rii; SBCLEAR(info); SBCLEAR(auth_dat); BCLEAR(errmsg); SBCLEAR(rii); rpc_get_rkinit_info(&info); /* * The validate_user routine makes sure that the principal in question * is allowed to log in as username, and if so, does a setuid(localuid). * If there is an access violation or an error in setting the uid, * an error is returned and the string errmsg is initialized with * an error message that will be sent back to the client. */ status = validate_user(info.aname, info.inst, info.realm, info.username, errmsg); if (status != RKINIT_SUCCESS) { rpc_send_error(errmsg); exit(0); } else rpc_send_success(); /* * If the name of a ticket file was specified, set it; otherwise, * just use the default. */ if (strlen(info.tktfilename)) krb_set_tkt_string(info.tktfilename); /* * Call internal kerberos library routine so that we can supply * our own ticket decryption routine. */ /* * We need a setjmp here because krb_get_in_tkt ignores the * return value of decrypt_tkt. Thus if we want any of its * return values to reach the client, we have to jump out of * the routine. */ if (setjmp(rii.env) == 0) { status = krb_get_in_tkt(info.aname, info.inst, info.realm, info.sname, info.sinst, info.lifetime, NULL, decrypt_tkt, (char *)&rii); if (status) { strcpy(errmsg, krb_err_txt[status]); rpc_send_error(errmsg); } else rpc_send_success(); } else rpc_send_error(errbuf); return(RKINIT_SUCCESS); }
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; } }
char * /* R: allocated response string */ auth_krb4 ( /* PARAMETERS */ const char *login, /* I: plaintext authenticator */ const char *password, /* I: plaintext password */ const char *service, const char *realm_in /* END PARAMETERS */ ) { /* VARIABLES */ char aname[ANAME_SZ]; /* Kerberos principal */ const char *realm; /* Kerberos realm to authenticate in */ int rc; /* return code */ char tf_name[TF_NAME_LEN]; /* Ticket file name */ char *instance, *user_specified; KTEXT_ST ticket; AUTH_DAT kdata; /* END VARIABLES */ /* * Make sure we have a password. If this is NULL the call * to krb_get_pw_in_tkt below would try to prompt for * one interactively. */ if (password == NULL) { syslog(LOG_ERR, "auth_krb4: NULL password?"); return strdup("NO saslauthd internal error"); } if (krbtf_name(tf_name, sizeof(tf_name)) != 0) { syslog(LOG_ERR, "auth_krb4: could not generate ticket file name"); return strdup("NO saslauthd internal error"); } krb_set_tkt_string(tf_name); strncpy(aname, login, ANAME_SZ-1); aname[ANAME_SZ-1] = '\0'; instance = ""; if (config) { char keyname[1024]; snprintf(keyname, sizeof(keyname), "krb4_%s_instance", service); instance = cfile_getstring(config, keyname, ""); } user_specified = strchr(aname, '.'); if (user_specified) { if (instance && instance[0]) { /* sysadmin specified a (mandatory) instance */ if (strcmp(user_specified + 1, instance)) { return strdup("NO saslauthd principal name error"); } /* nuke instance from "aname"-- matches what's already in "instance" */ *user_specified = '\0'; } else { /* sysadmin has no preference, so we shift * instance name from "aname" to "instance" */ *user_specified = '\0'; instance = user_specified + 1; } } if(realm_in && *realm_in != '\0') { realm = realm_in; } else { realm = default_realm; } rc = krb_get_pw_in_tkt(aname, instance, realm, KRB_TICKET_GRANTING_TICKET, realm, 1, password); if (rc == INTK_BADPW || rc == KDC_PR_UNKNOWN) { return strdup("NO"); } else if (rc != KSUCCESS) { syslog(LOG_ERR, "ERROR: auth_krb4: krb_get_pw_in_tkt: %s", krb_get_err_text(rc)); return strdup("NO saslauthd internal error"); } /* if the TGT wasn't spoofed, it should entitle us to an rcmd ticket... */ rc = krb_mk_req(&ticket, verify_principal, myhostname, default_realm, 0); if (rc != KSUCCESS) { syslog(LOG_ERR, "ERROR: auth_krb4: krb_get_pw_in_tkt: %s", krb_get_err_text(rc)); dest_tkt(); return strdup("NO saslauthd internal error"); } /* .. and that ticket should match our secret host key */ rc = krb_rd_req(&ticket, verify_principal, myhostname, 0, &kdata, srvtabname); if (rc != RD_AP_OK) { syslog(LOG_ERR, "ERROR: auth_krb4: krb_rd_req:%s", krb_get_err_text(rc)); dest_tkt(); return strdup("NO saslauthd internal error"); } dest_tkt(); return strdup("OK"); }
/* Called to see if the user's typed password is valid. We do this by asking the kerberos server for a ticket and checking to see if it gave us one. We need to move the ticketfile first, or otherwise we end up updating the user's tkfile with new tickets. This would break services like zephyr that like to stay authenticated, and it would screw with AFS authentication at some sites. So, we do a quick, painful hack with a tmpfile. */ Bool kerberos_passwd_valid_p (const char *typed_passwd, Bool verbose_p) { # ifdef HAVE_DARWIN return (klNoErr == KLAcquireNewInitialTicketsWithPassword (princ, NULL, typed_passwd, NULL)); # else /* !HAVE_DARWIN */ /* See comments in kerberos_lock_init -- should we do it the Mac Way on all systems? */ C_Block mitkey; Bool success; char *newtkfile; int fh = -1; /* temporarily switch to a new ticketfile. I'm not using tmpnam() because it isn't entirely portable. this could probably be fixed with autoconf. */ newtkfile = malloc(80 * sizeof(char)); memset(newtkfile, 0, sizeof(newtkfile)); sprintf(newtkfile, "/tmp/xscrn-%i.XXXXXX", getpid()); if( (fh = mkstemp(newtkfile)) < 0) { free(newtkfile); return(False); } if( fchmod(fh, 0600) < 0) { free(newtkfile); return(False); } krb_set_tkt_string(newtkfile); /* encrypt the typed password. if you have an AFS password instead of a kerberos one, you lose *right here*. If you want to use AFS passwords, you can use ka_StringToKey() instead. As always, ymmv. */ des_string_to_key(typed_passwd, mitkey); if (krb_get_in_tkt(name, inst, realm, "krbtgt", realm, DEFAULT_TKT_LIFE, key_to_key, NULL, (char *) mitkey) != 0) { success = False; } else { success = True; } /* quickly block out the tempfile and password to prevent snooping, then restore the old ticketfile and cleean up a bit. */ dest_tkt(); krb_set_tkt_string(tk_file); free(newtkfile); memset(mitkey, 0, sizeof(mitkey)); close(fh); /* #### tom: should the file be removed? */ /* Did we verify successfully? */ return success; # endif /* !HAVE_DARWIN */ }
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; }
static int v4_save(krb5_context ctx, struct _pam_krb5_stash *stash, struct _pam_krb5_user_info *userinfo, struct _pam_krb5_options *options, uid_t uid, gid_t gid, const char **ccname, int clone_cc) { char name[ANAME_SZ + 1], instance[INST_SZ + 1], realm[REALM_SZ + 1]; char tktfile[PATH_MAX]; char *saved_tktstring; int i, fd; struct stat st; if (ccname != NULL) { *ccname = NULL; } /* Convert the v5 principal name into v4 notation. */ memset(name, '\0', sizeof(name)); memset(instance, '\0', sizeof(instance)); memset(realm, '\0', sizeof(realm)); if (stash->v5creds.client != NULL) { /* Use the client principal of the creds we have, which we * can assume are always correct, even if "external" somehow * got us to the point where the principal name in "userinfo" * is incorrect. */ i = krb5_524_conv_principal(ctx, stash->v5creds.client, name, instance, realm); } else { /* Use the parsed principal as a fallback. We should never * really get here, but just in case. */ i = krb5_524_conv_principal(ctx, userinfo->principal_name, name, instance, realm); } if (i != 0) { warn("error converting %s to a Kerberos IV principal " "(shouldn't happen)", userinfo->unparsed_name); return PAM_SERVICE_ERR; } /* Create a new ticket file. */ #ifdef HAVE_LONG_LONG snprintf(tktfile, sizeof(tktfile), "%s/tkt%llu_XXXXXX", options->ccache_dir, options->user_check ? (unsigned long long) userinfo->uid : (unsigned long long) getuid()); #else snprintf(tktfile, sizeof(tktfile), "%s/tkt%lu_XXXXXX", options->ccache_dir, options->user_check ? (unsigned long) userinfo->uid : (unsigned long) getuid()); #endif fd = mkstemp(tktfile); if (fd == -1) { warn("error creating unique Kerberos IV ticket file " "(shouldn't happen)"); return PAM_SERVICE_ERR; } if (fchown(fd, getuid(), getgid()) != 0) { warn("error setting permissions on \"%s\" (%s), attempting " "to continue", tktfile, strerror(errno)); } if (options->debug) { debug("saving v4 tickets to '%s'", tktfile); } /* Open the ticket file. */ saved_tktstring = xstrdup(tkt_string()); krb_set_tkt_string(tktfile); i = tf_init(tktfile, W_TKT_FIL); if (i != 0) { const char *tferror; switch (i) { case NO_TKT_FIL: tferror = "no ticket file"; break; case TKT_FIL_ACC: tferror = "ticket file had wrong permissions"; break; case TKT_FIL_LCK: tferror = "error locking ticket file"; break; default: tferror = strerror(errno); break; } warn("error opening ticket file '%s': %s", tktfile, tferror); if ((i == TKT_FIL_ACC) && (options->debug)) { if (stat(tktfile, &st) == 0) { debug("file owner is %lu:%lu, " "we are effective %lu:%lu, " "real %lu:%lu", (unsigned long) st.st_uid, (unsigned long) st.st_gid, (unsigned long) geteuid(), (unsigned long) getegid(), (unsigned long) getuid(), (unsigned long) getgid()); } } krb_set_tkt_string(saved_tktstring); xstrfree(saved_tktstring); unlink(tktfile); close(fd); return PAM_SERVICE_ERR; } /* Store the user's name. */ if (v4_in_tkt(name, instance, realm) != 0) { warn("error initializing ticket file '%s'", tktfile); tf_close(); krb_set_tkt_string(saved_tktstring); xstrfree(saved_tktstring); unlink(tktfile); close(fd); return PAM_SERVICE_ERR; } /* Store the v4 credentials. */ if (v4_save_credentials(KRB5_TGS_NAME, realm, realm, stash->v4creds.session, stash->v4creds.lifetime, stash->v4creds.kvno, &stash->v4creds.ticket_st, stash->v4creds.issue_date) != 0) { warn("error saving tickets to '%s'", tktfile); tf_close(); krb_set_tkt_string(saved_tktstring); xstrfree(saved_tktstring); unlink(tktfile); close(fd); return PAM_SERVICE_ERR; } /* Close the new file. */ tf_close(); xstrfree(saved_tktstring); close(fd); /* Save the new file's name in the stash, and optionally return it to * the caller. */ if (_pam_krb5_stash_push_v4(ctx, stash, options, tktfile) == 0) { /* Generate a *new* ticket file with the same contents as this * one. */ if (clone_cc) { _pam_krb5_stash_clone_v4(stash, uid, gid); } krb_set_tkt_string(stash->v4tktfiles->name); if (ccname != NULL) { *ccname = stash->v4tktfiles->name; } } return PAM_SUCCESS; }
static void store_tickets(struct passwd *pwd, int ticket_newfiles, int ticket_store, int token_install) { char cc_file[MAXPATHLEN]; krb5_ccache ccache_store; #ifdef KRB524 int get_krb4_ticket = 0; char krb4_ticket_file[MAXPATHLEN]; #endif if (ticket_newfiles) snprintf(cc_file, sizeof(cc_file), "FILE:/tmp/krb5cc_%d", pwd->pw_uid); else snprintf(cc_file, sizeof(cc_file), "%s", krb5_cc_default_name(context)); if (ticket_store) { ret = krb5_cc_resolve(context, cc_file, &ccache_store); if (ret != 0) { krb5_syslog(context, LOG_ERR, ret, "krb5_cc_gen_new"); exit(1); } ret = krb5_cc_copy_cache(context, ccache, ccache_store); if (ret != 0) krb5_syslog(context, LOG_ERR, ret, "krb5_cc_copy_cache"); chown(krb5_cc_get_name(context, ccache_store), pwd->pw_uid, pwd->pw_gid); fprintf(back, BI_SETENV " KRB5CCNAME %s:%s\n", krb5_cc_get_type(context, ccache_store), krb5_cc_get_name(context, ccache_store)); #ifdef KRB524 get_krb4_ticket = krb5_config_get_bool_default (context, NULL, get_krb4_ticket, "libdefaults", "krb4_get_tickets", NULL); if (get_krb4_ticket) { CREDENTIALS c; krb5_creds cred; krb5_cc_cursor cursor; ret = krb5_cc_start_seq_get(context, ccache, &cursor); if (ret != 0) { krb5_syslog(context, LOG_ERR, ret, "start seq"); exit(1); } ret = krb5_cc_next_cred(context, ccache, &cursor, &cred); if (ret != 0) { krb5_syslog(context, LOG_ERR, ret, "next cred"); exit(1); } ret = krb5_cc_end_seq_get(context, ccache, &cursor); if (ret != 0) { krb5_syslog(context, LOG_ERR, ret, "end seq"); exit(1); } ret = krb524_convert_creds_kdc_ccache(context, ccache, &cred, &c); if (ret != 0) { krb5_syslog(context, LOG_ERR, ret, "convert"); } else { snprintf(krb4_ticket_file, sizeof(krb4_ticket_file), "%s%d", TKT_ROOT, pwd->pw_uid); krb_set_tkt_string(krb4_ticket_file); tf_setup(&c, c.pname, c.pinst); chown(krb4_ticket_file, pwd->pw_uid, pwd->pw_gid); } } #endif } /* Need to chown the ticket file */ #ifdef KRB524 if (get_krb4_ticket) fprintf(back, BI_SETENV " KRBTKFILE %s\n", krb4_ticket_file); #endif }
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; }