int main(int argc, char **argv) { char pname[ANAME_SZ + 1], pinst[INST_SZ + 1]; CREDENTIALS cred; int ret; ret = tf_init(tkt_string(), R_TKT_FIL); if (ret != 0) { printf("Error initializing ticket file \"%s\".\n", tkt_string()); return ret; } memset(&cred, 0, sizeof(cred)); ret = tf_get_pname(pname); if (ret != 0) { printf("Error reading names from \"%s\".\n", tkt_string()); return ret; } ret = tf_get_pinst(pinst); if (ret != 0) { printf("Error reading names from \"%s\".\n", tkt_string()); return ret; } ret = tf_get_cred(&cred); if (ret != 0) { printf("Error reading creds from \"%s\".\n", tkt_string()); return ret; } printf("%lu\n", (unsigned long) cred.lifetime); tf_close(); return 0; }
/* Called at startup to grab user, instance, and realm information from the user's ticketfile (remember, name.inst@realm). Since we're using tf_get_pname(), this should work even if your kerberos username isn't the same as your local username. We grab the ticket at startup time so that even if your ticketfile dies while the screen's locked we'll still have the information to unlock it. Problems: the password dialog currently displays local username, so if you have some non-standard name/instance when you run xscreensaver, you'll need to remember what it was when unlocking, or else you lose. Also, we use des_string_to_key(), so if you have an AFS password (encrypted with ka_StringToKey()), you'll lose. Get a kerberos password; it isn't that hard. Like the original lock_init, we return false if something went wrong. We don't use the arguments we're given, though. */ Bool kerberos_lock_init (int argc, char **argv, Bool verbose_p) { # ifdef HAVE_DARWIN KLBoolean found; return ((klNoErr == (KLCacheHasValidTickets (NULL, kerberosVersion_Any, &found, &princ, NULL))) && found); # else /* !HAVE_DARWIN */ /* Perhaps we should be doing it the Mac way (above) all the time? The following code assumes Unix-style file-based Kerberos credentials cache, which Mac OS X doesn't use. But is there any real reason to do it this way at all, even on other Unixen? */ int k_errno; memset(name, 0, sizeof(name)); memset(inst, 0, sizeof(inst)); /* find out where the user's keeping his tickets. squirrel it away for later use. */ tk_file = tkt_string(); /* open ticket file or die trying. */ if ((k_errno = tf_init(tk_file, R_TKT_FIL))) { return False; } /* same with principal and instance names */ if ((k_errno = tf_get_pname(name)) || (k_errno = tf_get_pinst(inst))) { return False; } /* close the ticketfile to release the lock on it. */ tf_close(); /* figure out what realm we're authenticated to. this ought to be the local realm, but it pays to be sure. */ if ((k_errno = krb_get_tf_realm(tk_file, realm))) { return False; } /* last-minute sanity check on what we got. */ if ((strlen(name)+strlen(inst)+strlen(realm)+3) > (REALM_SZ + ANAME_SZ + INST_SZ + 3)) { return False; } /* success */ return True; # endif /* !HAVE_DARWIN */ }
int krb_get_cred( char *service, /* Service name */ char *instance, /* Instance */ char *realm, /* Auth domain */ CREDENTIALS *c /* Credentials struct */ ) { int tf_status; /* return value of tf function calls */ struct timeval local_time; int kinited = 0; char env[16]; BOOL prompt; GetEnvironmentVariable("KERBEROSLOGIN_NEVER_PROMPT",env, sizeof(env)); prompt = (GetLastError() == ERROR_ENVVAR_NOT_FOUND); c->pname[0] = c->pinst[0] = '\0'; check_cache: gettimeofday(&local_time, 0); /* Open ticket file and lock it for shared reading */ if ((tf_status = tf_init(TKT_FILE, R_TKT_FIL)) != KSUCCESS) { goto cache_checked; } /* Copy principal's name and instance into the CREDENTIALS struc c */ if (((tf_status = tf_get_pname(c->pname)) != KSUCCESS) || ((tf_status = tf_get_pinst(c->pinst)) != KSUCCESS)) { goto cache_checked; } /* Search for requested service credentials and copy into c */ while ((tf_status = tf_get_cred(c)) == KSUCCESS) { /* Is this the right ticket? */ if (!service || (strcmp(c->service,service) == 0) && (!instance || strcmp(c->instance,instance) == 0) && (!realm || strcmp(c->realm,realm) == 0)) { // Hey, is this a valid ticket? Let's check before we return. if (((long)((c->issue_date + c->lifetime * 5L * 60L) - (long)local_time.tv_sec) >= 0) && ( 0 == com_addr(c))) { break; // we're OK } } } cache_checked: tf_close(); // If we are requesting a tgt, prompt for it if (tf_status != KSUCCESS && !kinited && strncmp(service, "krbtgt", ANAME_SZ) == 0 && prompt) { static int (*pLeash_kinit_dlg_ex)(HWND hParent, LPLSH_DLGINFO_EX lpdlginfoex) = 0; static DWORD (*pLeash_get_default_use_krb4)() = 0; kinited = 1; if ( !m_hLeashDLL ) { m_hLeashDLL = LoadLibrary(LEASHDLL); if ( m_hLeashDLL ) { (FARPROC)pLeash_kinit_dlg_ex=GetProcAddress(m_hLeashDLL,"Leash_kinit_dlg_ex"); (FARPROC)pLeash_get_default_use_krb4=GetProcAddress(m_hLeashDLL,"Leash_get_default_use_krb4"); } } if ( pLeash_get_default_use_krb4 && pLeash_kinit_dlg_ex ) { LSH_DLGINFO_EX dlginfo; int success; // copy in the existing username and realm char * pTmp = calloc(1, strlen(c->pname) + strlen(c->pinst) + 2); strcpy(pTmp, c->pname); if (c->pname[0] != 0 && c->pinst[0] != 0) { strcat(pTmp, "/"); strcat(pTmp, c->pinst); } memset(&dlginfo, 0, sizeof(LSH_DLGINFO_EX)); dlginfo.size = sizeof(LSH_DLGINFO_EX); dlginfo.dlgtype = DLGTYPE_PASSWD; dlginfo.title = dlginfo.in.title; strcpy(dlginfo.in.title,"Kerberos 4 - Obtain Tickets"); dlginfo.username = dlginfo.in.username; strcpy(dlginfo.in.username,pTmp); dlginfo.realm = dlginfo.in.realm; strcpy(dlginfo.in.realm,realm); dlginfo.use_defaults = 1; success = pLeash_kinit_dlg_ex(GetDesktopWindow(), &dlginfo); free(pTmp); if (success) goto check_cache; } } if (tf_status == EOF) return (GC_NOTKT); return(tf_status); }
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; }