krb5_error_code krb5int_tgtname(krb5_context context, const krb5_data *server, const krb5_data *client, krb5_principal *tgtprinc) { return krb5_build_principal_ext(context, tgtprinc, client->length, client->data, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, server->length, server->data, 0); }
struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { char svrnam[MAILTMPLEN],cltnam[MAILTMPLEN]; krb5_context ctx; krb5_timestamp now; krb5_principal service; krb5_ccache ccache; krb5_error_code code; krb5_creds *crd = (krb5_creds *) memset (fs_get (sizeof (krb5_creds)),0, sizeof (krb5_creds)); struct passwd *ret = NIL; if (*pass) { /* only if password non-empty */ /* make service name */ sprintf (svrnam,"%.80s@%.512s", (char *) mail_parameters (NIL,GET_SERVICENAME,NIL), tcp_serverhost ()); /* make client name with principal */ sprintf (cltnam,"%.80s/%.80s",pw->pw_name, (char *) mail_parameters (NIL,GET_SERVICENAME,NIL)); /* get a context */ if (!krb5_init_context (&ctx)) { /* get time, client and server principals */ if (!krb5_timeofday (ctx,&now) && /* Normally, kerb_cp_svr_name (defined/set in env_unix.c) is NIL, so * only the user name is used as a client principal. A few sites want * to have separate client principals for different services, but many * other sites vehemently object... */ !krb5_parse_name (ctx,kerb_cp_svr_name ? cltnam : pw->pw_name, &crd->client) && !krb5_parse_name (ctx,svrnam,&service) && !krb5_build_principal_ext(ctx,&crd->server, krb5_princ_realm (ctx,crd->client)->length, krb5_princ_realm (ctx,crd->client)->data, KRB5_TGS_NAME_SIZE,KRB5_TGS_NAME, krb5_princ_realm (ctx,crd->client)->length, krb5_princ_realm (ctx,crd->client)->data, 0)) { /* expire in 3 minutes */ crd->times.endtime = now + (3 * 60); if (krb5_cc_resolve (ctx,"MEMORY:pwk",&ccache) || krb5_cc_initialize (ctx,ccache,crd->client)) ccache = 0; if (!krb5_get_in_tkt_with_password (ctx,NIL,NIL,NIL,NIL,pass,ccache, crd,0) && !krb5_verify_init_creds (ctx,crd,service,0,ccache ? &ccache : 0,0)) ret = pw; krb5_free_creds (ctx,crd);/* flush creds and service principal */ krb5_free_principal (ctx,service); } krb5_free_context (ctx); /* don't need context any more */ } } return ret; }
bool v5::getTgtFromCcache (krb5_context context, krb5_creds *creds) { krb5_ccache ccache; krb5_creds mcreds; krb5_principal principal, tgt_principal; bool ret; memset(&ccache, 0, sizeof(ccache)); ret = FALSE; if (krb5_cc_default(context, &ccache) == 0) { memset(&principal, 0, sizeof(principal)); if (krb5_cc_get_principal(context, ccache, &principal) == 0) { memset(&tgt_principal, 0, sizeof(tgt_principal)); if (krb5_build_principal_ext(context, &tgt_principal, getPrincipalRealmLength(principal), getPrincipalRealmData(principal), KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, getPrincipalRealmLength(principal), getPrincipalRealmData(principal), 0) == 0) { memset(creds, 0, sizeof(*creds)); memset(&mcreds, 0, sizeof(mcreds)); mcreds.client = principal; mcreds.server = tgt_principal; if (krb5_cc_retrieve_cred(context, ccache, 0, &mcreds, creds) == 0) { ret = TRUE; } else { memset(creds, 0, sizeof(*creds)); } krb5_free_principal(context, tgt_principal); } krb5_free_principal(context, principal); } krb5_cc_close(context, ccache); } return ret; }
/* * Test whether anonymous authentication works. If this doesn't, we need to * skip the tests of anonymous FAST. */ static bool anon_fast_works(void) { krb5_context ctx; krb5_error_code retval; krb5_principal princ = NULL; char *realm; krb5_creds creds; krb5_get_init_creds_opt *opts = NULL; /* Construct the anonymous principal name. */ retval = krb5_init_context(&ctx); if (retval != 0) bail("cannot initialize Kerberos"); retval = krb5_get_default_realm(ctx, &realm); if (retval != 0) bail("cannot get default realm"); retval = krb5_build_principal_ext(ctx, &princ, strlen(realm), realm, strlen(KRB5_WELLKNOWN_NAME), KRB5_WELLKNOWN_NAME, strlen(KRB5_ANON_NAME), KRB5_ANON_NAME, NULL); if (retval != 0) bail("cannot construct anonymous principal"); krb5_free_default_realm(ctx, realm); /* Obtain the credentials. */ memset(&creds, 0, sizeof(creds)); retval = krb5_get_init_creds_opt_alloc(ctx, &opts); if (retval != 0) bail("cannot create credential options"); krb5_get_init_creds_opt_set_anonymous(opts, 1); krb5_get_init_creds_opt_set_tkt_life(opts, 60); retval = krb5_get_init_creds_password(ctx, &creds, princ, NULL, NULL, NULL, 0, NULL, opts); /* Clean up. */ if (princ != NULL) krb5_free_principal(ctx, princ); if (opts != NULL) krb5_get_init_creds_opt_free(ctx, opts); krb5_free_cred_contents(ctx, &creds); return (retval == 0); }
/* Get a TGT for use at the remote host */ krb5_error_code KRB5_CALLCONV krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, char *rhost, krb5_principal client, krb5_principal server, krb5_ccache cc, int forwardable, krb5_data *outbuf) /* Should forwarded TGT also be forwardable? */ { krb5_replay_data replaydata; krb5_data * scratch = 0; krb5_address **addrs = NULL; krb5_error_code retval; krb5_creds creds, tgt; krb5_creds *pcreds; krb5_flags kdcoptions; int close_cc = 0; int free_rhost = 0; krb5_enctype enctype = 0; krb5_keyblock *session_key; krb5_boolean old_use_conf_ktypes = context->use_conf_ktypes; memset((char *)&creds, 0, sizeof(creds)); memset((char *)&tgt, 0, sizeof(creds)); if (cc == 0) { if ((retval = krb5int_cc_default(context, &cc))) goto errout; close_cc = 1; } retval = krb5_auth_con_getkey (context, auth_context, &session_key); if (retval) goto errout; if (session_key) { enctype = session_key->enctype; krb5_free_keyblock (context, session_key); session_key = NULL; } else if (server) { /* must server be non-NULL when rhost is given? */ /* Try getting credentials to see what the remote side supports. Not bulletproof, just a heuristic. */ krb5_creds in, *out = 0; memset (&in, 0, sizeof(in)); retval = krb5_copy_principal (context, server, &in.server); if (retval) goto punt; retval = krb5_copy_principal (context, client, &in.client); if (retval) goto punt; retval = krb5_get_credentials (context, 0, cc, &in, &out); if (retval) goto punt; /* Got the credentials. Okay, now record the enctype and throw them away. */ enctype = out->keyblock.enctype; krb5_free_creds (context, out); punt: krb5_free_cred_contents (context, &in); } if ((retval = krb5_copy_principal(context, client, &creds.client))) goto errout; if ((retval = krb5_build_principal_ext(context, &creds.server, client->realm.length, client->realm.data, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, client->realm.length, client->realm.data, 0))) goto errout; /* fetch tgt directly from cache */ context->use_conf_ktypes = 1; retval = krb5_cc_retrieve_cred (context, cc, KRB5_TC_SUPPORTED_KTYPES, &creds, &tgt); context->use_conf_ktypes = old_use_conf_ktypes; if (retval) goto errout; /* tgt->client must be equal to creds.client */ if (!krb5_principal_compare(context, tgt.client, creds.client)) { /* Solaris Kerberos */ char *r_name = NULL; char *t_name = NULL; krb5_error_code r_err, t_err; t_err = krb5_unparse_name(context, tgt.client, &t_name); r_err = krb5_unparse_name(context, creds.client, &r_name); krb5_set_error_message(context, KRB5_PRINC_NOMATCH, dgettext(TEXT_DOMAIN, "Requested principal and ticket don't match: Requested principal is '%s' and TGT principal is '%s'"), r_err ? "unknown" : r_name, t_err ? "unknown" : t_name); if (r_name) krb5_free_unparsed_name(context, r_name); if (t_name) krb5_free_unparsed_name(context, t_name); retval = KRB5_PRINC_NOMATCH; goto errout; } if (!tgt.ticket.length) { retval = KRB5_NO_TKT_SUPPLIED; goto errout; } if (tgt.addresses && *tgt.addresses) { if (rhost == NULL) { if (krb5_princ_type(context, server) != KRB5_NT_SRV_HST) { retval = KRB5_FWD_BAD_PRINCIPAL; goto errout; } if (krb5_princ_size(context, server) < 2){ retval = KRB5_CC_BADNAME; goto errout; } rhost = malloc(server->data[1].length+1); if (!rhost) { retval = ENOMEM; goto errout; } free_rhost = 1; /* Solaris Kerberos */ (void) memcpy(rhost, server->data[1].data, server->data[1].length); rhost[server->data[1].length] = '\0'; } retval = krb5_os_hostaddr(context, rhost, &addrs); if (retval) goto errout; } creds.keyblock.enctype = enctype; creds.times = tgt.times; creds.times.starttime = 0; kdcoptions = flags2options(tgt.ticket_flags)|KDC_OPT_FORWARDED; if (!forwardable) /* Reset KDC_OPT_FORWARDABLE */ kdcoptions &= ~(KDC_OPT_FORWARDABLE); if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions, addrs, &creds, &pcreds))) { if (enctype) { creds.keyblock.enctype = 0; if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions, addrs, &creds, &pcreds))) goto errout; } else goto errout; } retval = krb5_mk_1cred(context, auth_context, pcreds, &scratch, &replaydata); krb5_free_creds(context, pcreds); /* * Solaris Kerberos: changed this logic from the MIT 1.2.1 version to be * more robust. */ if (scratch) { if (retval) krb5_free_data(context, scratch); else { *outbuf = *scratch; krb5_xfree(scratch); } } errout: if (addrs) krb5_free_addresses(context, addrs); /* Solaris Kerberos */ if (close_cc) (void) krb5_cc_close(context, cc); if (free_rhost) free(rhost); krb5_free_cred_contents(context, &creds); krb5_free_cred_contents(context, &tgt); return retval; }
/* * Get a ticket granting ticket and stuff it in the cache */ static const char * get_tgt( char * keytab_name, char * principal_name) { krb5_context context; krb5_error_code ret; krb5_principal client = NULL, server = NULL; krb5_creds creds; krb5_keytab keytab; krb5_ccache ccache; krb5_timestamp now; #ifdef KRB5_HEIMDAL_INCLUDES krb5_data tgtname = { KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME }; #else krb5_data tgtname = { 0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME }; #endif static char *error = NULL; if (error != NULL) { amfree(error); error = NULL; } if ((ret = krb5_init_context(&context)) != 0) { error = vstrallocf(_("error initializing krb5 context: %s"), error_message(ret)); return (error); } /*krb5_init_ets(context);*/ if(!keytab_name) { error = vstrallocf(_("error -- no krb5 keytab defined")); return(error); } if(!principal_name) { error = vstrallocf(_("error -- no krb5 principal defined")); return(error); } /* * Resolve keytab file into a keytab object */ if ((ret = krb5_kt_resolve(context, keytab_name, &keytab)) != 0) { error = vstrallocf(_("error resolving keytab %s: %s"), keytab_name, error_message(ret)); return (error); } /* * Resolve the amanda service held in the keytab into a principal * object */ ret = krb5_parse_name(context, principal_name, &client); if (ret != 0) { error = vstrallocf(_("error parsing %s: %s"), principal_name, error_message(ret)); return (error); } #ifdef KRB5_HEIMDAL_INCLUDES ret = krb5_build_principal_ext(context, &server, krb5_realm_length(*krb5_princ_realm(context, client)), krb5_realm_data(*krb5_princ_realm(context, client)), tgtname.length, tgtname.data, krb5_realm_length(*krb5_princ_realm(context, client)), krb5_realm_data(*krb5_princ_realm(context, client)), 0); #else ret = krb5_build_principal_ext(context, &server, krb5_princ_realm(context, client)->length, krb5_princ_realm(context, client)->data, tgtname.length, tgtname.data, krb5_princ_realm(context, client)->length, krb5_princ_realm(context, client)->data, 0); #endif if (ret != 0) { error = vstrallocf(_("error while building server name: %s"), error_message(ret)); return (error); } ret = krb5_timeofday(context, &now); if (ret != 0) { error = vstrallocf(_("error getting time of day: %s"), error_message(ret)); return (error); } memset(&creds, 0, SIZEOF(creds)); creds.times.starttime = 0; creds.times.endtime = now + AMANDA_TKT_LIFETIME; creds.client = client; creds.server = server; /* * Get a ticket for the service, using the keytab */ ret = krb5_get_in_tkt_with_keytab(context, 0, NULL, NULL, NULL, keytab, 0, &creds, 0); if (ret != 0) { error = vstrallocf(_("error getting ticket for %s: %s"), principal_name, error_message(ret)); goto cleanup2; } if ((ret = krb5_cc_default(context, &ccache)) != 0) { error = vstrallocf(_("error initializing ccache: %s"), error_message(ret)); goto cleanup; } if ((ret = krb5_cc_initialize(context, ccache, client)) != 0) { error = vstrallocf(_("error initializing ccache: %s"), error_message(ret)); goto cleanup; } if ((ret = krb5_cc_store_cred(context, ccache, &creds)) != 0) { error = vstrallocf(_("error storing creds in ccache: %s"), error_message(ret)); /* FALLTHROUGH */ } krb5_cc_close(context, ccache); cleanup: krb5_free_cred_contents(context, &creds); cleanup2: #if 0 krb5_free_principal(context, client); krb5_free_principal(context, server); #endif krb5_free_context(context); return (error); }
/******************************************************************* check on Kerberos authentication ********************************************************************/ static BOOL krb5_auth(char *this_user,char *password) { krb5_data tgtname = { 0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME }; krb5_context kcontext; krb5_principal kprinc; krb5_principal server; krb5_creds kcreds; int options = 0; krb5_address **addrs = (krb5_address **)0; krb5_preauthtype *preauth = NULL; krb5_keytab keytab = NULL; krb5_timestamp now; krb5_ccache ccache = NULL; int retval; char *name; if ( retval=krb5_init_context(&kcontext)) { return(False); } if ( retval = krb5_timeofday(kcontext, &now) ) { return(False); } if ( retval = krb5_cc_default(kcontext, &ccache) ) { return(False); } if ( retval = krb5_parse_name(kcontext, this_user, &kprinc) ) { return(False); } memset((char *)&kcreds, 0, sizeof(kcreds)); kcreds.client = kprinc; if ((retval = krb5_build_principal_ext(kcontext, &server, krb5_princ_realm(kcontext, kprinc)->length, krb5_princ_realm(kcontext, kprinc)->data, tgtname.length, tgtname.data, krb5_princ_realm(kcontext, kprinc)->length, krb5_princ_realm(kcontext, kprinc)->data, 0))) { return(False); } kcreds.server = server; retval = krb5_get_in_tkt_with_password(kcontext, options, addrs, NULL, preauth, password, 0, &kcreds, 0); if ( retval ) { return(False); } return(True); }
int main(int argc, const char **argv) { krb5_context ctx; krb5_ccache ccache; krb5_creds mcreds, creds; krb5_keytab keytab; krb5_principal server; krb5_verify_init_creds_opt opts; int ret; ctx = NULL; ret = krb5_init_context(&ctx); if (ret != 0) { crit("error initializing Kerberos: %s", error_message(ret)); return ret; } ccache = NULL; ret = krb5_cc_default(ctx, &ccache); if (ret != 0) { crit("error resolving ccache: %s", error_message(ret)); return ret; } keytab = NULL; ret = krb5_kt_default(ctx, &keytab); if (ret != 0) { crit("error resolving keytab: %s", error_message(ret)); return ret; } server = NULL; memset(&mcreds, 0, sizeof(mcreds)); ret = krb5_cc_get_principal(ctx, ccache, &mcreds.client); if (ret != 0) { crit("error reading client name from ccache: %s", error_message(ret)); return ret; } ret = krb5_build_principal_ext(ctx, &mcreds.server, v5_princ_realm_length(mcreds.client), v5_princ_realm_contents(mcreds.client), KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, v5_princ_realm_length(mcreds.client), v5_princ_realm_contents(mcreds.client), 0); if (ret != 0) { crit("error building ticket granting server name: %s", error_message(ret)); return ret; } ret = krb5_cc_retrieve_cred(ctx, ccache, 0, &mcreds, &creds); if (ret != 0) { crit("error reading ccache: %s", error_message(ret)); return ret; } krb5_cc_close(ctx, ccache); krb5_verify_init_creds_opt_init(&opts); ret = krb5_verify_init_creds(ctx, &creds, server, keytab, NULL, &opts); if (ret != 0) { crit("error verifying creds: %s", error_message(ret)); } else { printf("OK\n"); } krb5_free_context(ctx); return ret; }
/** * @brief * Get a TGT for use at the remote host. * * @param[in] context - The Kerberos context. * @param[in] auth_context - Authentication context * @param[in] client - Principal to be copied * @param[in] server - Server of type krb5_principal * @param[in] cc - Credential cache handle * @param[out] outbuf - Replay cache data (NULL if not needed) * * @return krb5_error_code * @retval 0 - success * @retval !=0 - failure */ static krb5_error_code fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, krb5_principal client, krb5_principal server, krb5_ccache cc, krb5_data outbuf) { krb5_replay_data replaydata; krb5_data *scratch = 0; krb5_address **addrs = 0; krb5_flags kdcoptions; krb5_error_code retval; krb5_creds creds, tgt; krb5_creds *pcreds; int free_rhost = 0; char *rhost; memset((char *)&creds, 0, sizeof(creds)); memset((char *)&tgt, 0, sizeof(creds)); if (krb5_princ_type(context, server) != KRB5_NT_SRV_HST) return KRB5_FWD_BAD_PRINCIPAL; if (krb5_princ_size(context, server) < 2) return KRB5_CC_BADNAME; rhost = malloc(server->data[1].length+1); if (!rhost) return ENOMEM; free_rhost = 1; memcpy(rhost, server->data[1].data, server->data[1].length); rhost[server->data[1].length] = '\0'; retval = krb5_os_hostaddr(context, rhost, &addrs); if (retval) goto errout; if ((retval = krb5_copy_principal(context, client, &creds.client))) goto errout; if ((retval = krb5_build_principal_ext(context, &creds.server, client->realm.length, client->realm.data, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, client->realm.length, client->realm.data, 0))) goto errout; /* fetch tgt directly from cache */ retval = krb5_cc_retrieve_cred(context, cc, KRB5_TC_SUPPORTED_KTYPES, &creds, &tgt); if (retval) goto errout; /* tgt->client must be equal to creds.client */ if (!krb5_principal_compare(context, tgt.client, creds.client)) { retval = KRB5_PRINC_NOMATCH; goto errout; } if (!tgt.ticket.length) { retval = KRB5_NO_TKT_SUPPLIED; goto errout; } kdcoptions = flags2options(tgt.ticket_flags)| KDC_OPT_FORWARDED; if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions, addrs, &creds, &pcreds))) goto errout; retval = krb5_mk_1cred(context, auth_context, pcreds, &scratch, &replaydata); krb5_free_creds(context, pcreds); if (retval) { if (scratch) krb5_free_data(context, scratch); } else { *outbuf = *scratch; free(scratch); } errout: if (addrs) krb5_free_addresses(context, addrs); if (free_rhost) free(rhost); krb5_free_cred_contents(context, &creds); krb5_free_cred_contents(context, &tgt); return retval; }
/* * Find a keytab entry to use for a given target hostname. * Tries to find the most appropriate keytab to use given the * name of the host we are trying to connect with. */ static int find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname, krb5_keytab_entry *kte, const char **svcnames) { krb5_error_code code; char **realmnames = NULL; char myhostname[NI_MAXHOST], targethostname[NI_MAXHOST]; char myhostad[NI_MAXHOST + 1]; int i, j, retval; char *default_realm = NULL; char *realm; char *k5err = NULL; int tried_all = 0, tried_default = 0; krb5_principal princ; /* Get full target hostname */ retval = get_full_hostname(hostname, targethostname, sizeof(targethostname)); if (retval) goto out; /* Get full local hostname */ retval = gethostname(myhostname, sizeof(myhostname)); if (retval) { k5err = gssd_k5_err_msg(context, retval); printerr(1, "%s while getting local hostname\n", k5err); gsh_free(k5err); goto out; } /* Compute the active directory machine name HOST$ */ strcpy(myhostad, myhostname); for (i = 0; myhostad[i] != 0; ++i) myhostad[i] = toupper(myhostad[i]); myhostad[i] = '$'; myhostad[i + 1] = 0; retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname)); if (retval) goto out; code = krb5_get_default_realm(context, &default_realm); if (code) { retval = code; k5err = gssd_k5_err_msg(context, code); printerr(1, "%s while getting default realm name\n", k5err); gsh_free(k5err); goto out; } /* * Get the realm name(s) for the target hostname. * In reality, this function currently only returns a * single realm, but we code with the assumption that * someday it may actually return a list. */ code = krb5_get_host_realm(context, targethostname, &realmnames); if (code) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s while getting realm(s) for host '%s'\n", k5err, targethostname); gsh_free(k5err); retval = code; goto out; } /* * Try the "appropriate" realm first, and if nothing found for that * realm, try the default realm (if it hasn't already been tried). */ i = 0; realm = realmnames[i]; while (1) { if (realm == NULL) { tried_all = 1; if (!tried_default) realm = default_realm; } if (tried_all && tried_default) break; if (strcmp(realm, default_realm) == 0) tried_default = 1; for (j = 0; svcnames[j] != NULL; j++) { char spn[300]; /* * The special svcname "$" means 'try the active * directory machine account' */ if (strcmp(svcnames[j], "$") == 0) { snprintf(spn, sizeof(spn), "%s@%s", myhostad, realm); code = krb5_build_principal_ext(context, &princ, strlen(realm), realm, strlen(myhostad), myhostad, NULL); } else { snprintf(spn, sizeof(spn), "%s/%s@%s", svcnames[j], myhostname, realm); code = krb5_build_principal_ext(context, &princ, strlen(realm), realm, strlen(svcnames [j]), svcnames[j], strlen(myhostname), myhostname, NULL); } if (code) { k5err = gssd_k5_err_msg(context, code); printerr(1, "%s while building principal for '%s'\n", k5err, spn); gsh_free(k5err); continue; } code = krb5_kt_get_entry(context, kt, princ, 0, 0, kte); krb5_free_principal(context, princ); if (code) { k5err = gssd_k5_err_msg(context, code); printerr(3, "%s while getting keytab entry for '%s'\n", k5err, spn); gsh_free(k5err); } else { printerr(3, "Success getting keytab entry for '%s'\n", spn); retval = 0; goto out; } retval = code; } /* * Nothing found with our hostname instance, now look for * names with any instance (they must have an instance) */ for (j = 0; svcnames[j] != NULL; j++) { int found = 0; if (strcmp(svcnames[j], "$") == 0) continue; code = gssd_search_krb5_keytab(context, kt, realm, svcnames[j], &found, kte); if (!code && found) { printerr(3, "Success getting keytab entry for " "%s/*@%s\n", svcnames[j], realm); retval = 0; goto out; } } if (!tried_all) { i++; realm = realmnames[i]; } } out: if (default_realm) k5_free_default_realm(context, default_realm); if (realmnames) krb5_free_host_realm(context, realmnames); return retval; }
/* * PAM test callback to check whether we created a ticket cache and the ticket * cache is for the correct user. */ static void check_cache(pam_handle_t *pamh, const struct script_config *config, void *data) { struct extra *extra = data; const char *cache, *file; struct stat st; char *prefix; krb5_error_code code; krb5_context ctx = NULL; krb5_ccache ccache = NULL; krb5_principal princ = NULL; krb5_principal tgtprinc = NULL; krb5_creds in, out; char *principal = NULL; /* Check cache naming, ownership, and permissions. */ cache = pam_getenv(pamh, "KRB5CCNAME"); ok(cache != NULL, "KRB5CCNAME is set in PAM environment"); if (cache == NULL) return; basprintf(&prefix, "FILE:/tmp/krb5cc_%lu_", (unsigned long) getuid()); diag("KRB5CCNAME = %s", cache); ok(strncmp(prefix, cache, strlen(prefix)) == 0, "cache file name prefix is correct"); free(prefix); file = cache + strlen("FILE:"); is_int(0, stat(file, &st), "cache exists"); is_int(getuid(), st.st_uid, "...with correct UID"); is_int(getgid(), st.st_gid, "...with correct GID"); is_int(0600, (st.st_mode & 0777), "...with correct permissions"); /* Check the existence of the ticket cache and its principal. */ code = krb5_init_context(&ctx); if (code != 0) bail("cannot create Kerberos context"); code = krb5_cc_resolve(ctx, cache, &ccache); is_int(0, code, "able to resolve Kerberos ticket cache"); code = krb5_cc_get_principal(ctx, ccache, &princ); is_int(0, code, "able to get principal"); code = krb5_unparse_name(ctx, princ, &principal); is_int(0, code, "...and principal is valid"); is_string(config->extra[0], principal, "...and matches our principal"); /* Retrieve the krbtgt for the realm and check properties. */ code = krb5_build_principal_ext(ctx, &tgtprinc, strlen(extra->realm), extra->realm, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, strlen(extra->realm), extra->realm, NULL); if (code != 0) bail("cannot create krbtgt principal name"); memset(&in, 0, sizeof(in)); memset(&out, 0, sizeof(out)); in.server = tgtprinc; in.client = princ; code = krb5_cc_retrieve_cred(ctx, ccache, KRB5_TC_MATCH_SRV_NAMEONLY, &in, &out); is_int(0, code, "able to get krbtgt credentials"); ok(out.times.endtime > time(NULL) + 30 * 60, "...good for 30 minutes"); krb5_free_cred_contents(ctx, &out); /* Close things and release memory. */ krb5_free_principal(ctx, tgtprinc); krb5_free_unparsed_name(ctx, principal); krb5_free_principal(ctx, princ); krb5_cc_close(ctx, ccache); krb5_free_context(ctx); }
static int krb5_auth(void *instance, REQUEST *request) { rlm_krb5_t *inst = instance; int ret; static char tgs_name[] = KRB5_TGS_NAME; krb5_data tgtname = { 0, KRB5_TGS_NAME_SIZE, tgs_name }; krb5_creds kcreds; krb5_ccache ccache; /* MEMORY: + unsigned int (20) + NULL */ char cache_name[28]; krb5_context context = *(inst->context); /* copy data */ const char *user, *pass; /* * We can only authenticate user requests which HAVE * a User-Name attribute. */ if (!request->username) { radlog(L_AUTH, "rlm_krb5: Attribute \"User-Name\" is required for authentication."); return RLM_MODULE_INVALID; } /* * We can only authenticate user requests which HAVE * a User-Password attribute. */ if (!request->password) { radlog(L_AUTH, "rlm_krb5: Attribute \"User-Password\" is required for authentication."); return RLM_MODULE_INVALID; } /* * Ensure that we're being passed a plain-text password, * and not anything else. */ if (request->password->attribute != PW_USER_PASSWORD) { radlog(L_AUTH, "rlm_krb5: Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->name); return RLM_MODULE_INVALID; } user = request->username->vp_strvalue; pass = request->password->vp_strvalue; /* * Generate a unique cache_name. */ snprintf(cache_name, sizeof(cache_name), "MEMORY:%u", request->number); ret = krb5_cc_resolve(context, cache_name, &ccache); if (ret) { radlog(L_AUTH, "rlm_krb5: [%s] krb5_cc_resolve(): %s", user, error_message(ret)); return RLM_MODULE_REJECT; } /* * Actually perform the authentication. */ memset((char *)&kcreds, 0, sizeof(kcreds)); ret = krb5_parse_name(context, user, &kcreds.client); if (ret) { radlog(L_AUTH, "rlm_krb5: [%s] krb5_parse_name failed: %s", user, error_message(ret)); return RLM_MODULE_REJECT; } ret = krb5_cc_initialize(context, ccache, kcreds.client); if (ret) { radlog(L_AUTH, "rlm_krb5: [%s] krb5_cc_initialize(): %s", user, error_message(ret)); return RLM_MODULE_REJECT; } /* * MIT krb5 verification. */ ret = krb5_build_principal_ext(context, &kcreds.server, krb5_princ_realm(context, kcreds.client)->length, krb5_princ_realm(context, kcreds.client)->data, tgtname.length, tgtname.data, krb5_princ_realm(context, kcreds.client)->length, krb5_princ_realm(context, kcreds.client)->data, 0); if (ret) { radlog(L_AUTH, "rlm_krb5: [%s] krb5_build_principal_ext failed: %s", user, error_message(ret)); krb5_cc_destroy(context, ccache); return RLM_MODULE_REJECT; } ret = krb5_get_in_tkt_with_password(context, 0, NULL, NULL, NULL, pass, ccache, &kcreds, 0); if (ret) { radlog(L_AUTH, "rlm_krb5: [%s] krb5_g_i_t_w_p failed: %s", user, error_message(ret)); krb5_free_cred_contents(context, &kcreds); krb5_cc_destroy(context, ccache); return RLM_MODULE_REJECT; } /* * Now verify the KDC's identity. */ ret = verify_krb5_tgt(context, inst, user, ccache); krb5_free_cred_contents(context, &kcreds); krb5_cc_destroy(context, ccache); return ret; }
static krb5_error_code krb5_validate_or_renew_creds(krb5_context context, krb5_creds *creds, krb5_principal client, krb5_ccache ccache, char *in_tkt_service, int validate) { krb5_error_code ret; krb5_creds in_creds; /* only client and server need to be filled in */ krb5_creds *out_creds = 0; /* for check before dereferencing below */ krb5_creds **tgts; memset((char *)&in_creds, 0, sizeof(krb5_creds)); in_creds.server = NULL; tgts = NULL; in_creds.client = client; if (in_tkt_service) { /* this is ugly, because so are the data structures involved. I'm in the library, so I'm going to manipulate the data structures directly, otherwise, it will be worse. */ if ((ret = krb5_parse_name(context, in_tkt_service, &in_creds.server))) goto cleanup; /* stuff the client realm into the server principal. realloc if necessary */ if (in_creds.server->realm.length < in_creds.client->realm.length) if ((in_creds.server->realm.data = (char *) realloc(in_creds.server->realm.data, in_creds.client->realm.length)) == NULL) { ret = ENOMEM; goto cleanup; } in_creds.server->realm.length = in_creds.client->realm.length; memcpy(in_creds.server->realm.data, in_creds.client->realm.data, in_creds.client->realm.length); } else { if ((ret = krb5_build_principal_ext(context, &in_creds.server, in_creds.client->realm.length, in_creds.client->realm.data, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, in_creds.client->realm.length, in_creds.client->realm.data, 0))) goto cleanup; } if (validate) ret = krb5_get_cred_from_kdc_validate(context, ccache, &in_creds, &out_creds, &tgts); else ret = krb5_get_cred_from_kdc_renew(context, ccache, &in_creds, &out_creds, &tgts); /* ick. copy the struct contents, free the container */ if (out_creds) { *creds = *out_creds; krb5_xfree(out_creds); } cleanup: if (in_creds.server) krb5_free_principal(context, in_creds.server); if (tgts) krb5_free_tgt_creds(context, tgts); return(ret); }
int main(int argc, char **argv) { krb5_context context; krb5_keytab kt; krb5_keytab_entry ktent; krb5_encrypt_block eblock; krb5_creds my_creds; krb5_get_init_creds_opt *opt; kadm5_principal_ent_rec princ_ent; krb5_principal princ, server; char pw[16]; char *whoami, *principal, *authprinc, *authpwd; krb5_data pwdata; void *handle; int ret, test, encnum; unsigned int i; whoami = argv[0]; if (argc < 2 || argc > 4) { fprintf(stderr, "Usage: %s principal [authuser] [authpwd]\n", whoami); exit(1); } principal = argv[1]; authprinc = (argc > 2) ? argv[2] : argv[0]; authpwd = (argc > 3) ? argv[3] : NULL; /* * Setup. Initialize data structures, open keytab, open connection * to kadm5 server. */ memset(&context, 0, sizeof(context)); kadm5_init_krb5_context(&context); ret = krb5_parse_name(context, principal, &princ); if (ret) { com_err(whoami, ret, "while parsing principal name %s", principal); exit(1); } if((ret = krb5_build_principal_ext(context, &server, krb5_princ_realm(kcontext, princ)->length, krb5_princ_realm(kcontext, princ)->data, tgtname.length, tgtname.data, krb5_princ_realm(kcontext, princ)->length, krb5_princ_realm(kcontext, princ)->data, 0))) { com_err(whoami, ret, "while building server name"); exit(1); } ret = krb5_kt_default(context, &kt); if (ret) { com_err(whoami, ret, "while opening keytab"); exit(1); } ret = kadm5_init(context, authprinc, authpwd, KADM5_ADMIN_SERVICE, NULL, KADM5_STRUCT_VERSION, KADM5_API_VERSION_4, NULL, &handle); if (ret) { com_err(whoami, ret, "while initializing connection"); exit(1); } /* these pw's don't need to be secure, just different every time */ SRAND((RAND_TYPE)time((void *) NULL)); pwdata.data = pw; pwdata.length = sizeof(pw); /* * For each test: * * For each enctype in the test, construct a random password/key. * Assign all keys to principal with kadm5_setkey_principal. Add * each key to the keytab, and acquire an initial ticket with the * keytab (XXX can I specify the kvno explicitly?). If * krb5_get_init_creds_keytab succeeds, then the keys were set * successfully. */ for (test = 0; tests[test] != NULL; test++) { krb5_keyblock *testp = tests[test]; kadm5_key_data *extracted; int n_extracted, match; printf("+ Test %d:\n", test); for (encnum = 0; testp[encnum].magic != -1; encnum++) { for (i = 0; i < sizeof(pw); i++) pw[i] = (RAND() % 26) + '0'; /* XXX */ krb5_use_enctype(context, &eblock, testp[encnum].enctype); ret = krb5_string_to_key(context, &eblock, &testp[encnum], &pwdata, NULL); if (ret) { com_err(whoami, ret, "while converting string to key"); exit(1); } } /* now, encnum == # of keyblocks in testp */ ret = kadm5_setkey_principal(handle, princ, testp, encnum); if (ret) { com_err(whoami, ret, "while setting keys"); exit(1); } ret = kadm5_get_principal(handle, princ, &princ_ent, KADM5_KVNO); if (ret) { com_err(whoami, ret, "while retrieving principal"); exit(1); } ret = kadm5_get_principal_keys(handle, princ, 0, &extracted, &n_extracted); if (ret) { com_err(whoami, ret, "while extracting keys"); exit(1); } for (encnum = 0; testp[encnum].magic != -1; encnum++) { printf("+ enctype %d\n", testp[encnum].enctype); for (match = 0; match < n_extracted; match++) { if (extracted[match].key.enctype == testp[encnum].enctype) break; } if (match >= n_extracted) { com_err(whoami, KRB5_WRONG_ETYPE, "while matching enctypes"); exit(1); } if (extracted[match].key.length != testp[encnum].length || memcmp(extracted[match].key.contents, testp[encnum].contents, testp[encnum].length) != 0) { com_err(whoami, KRB5_KDB_NO_MATCHING_KEY, "verifying keys"); exit(1); } memset(&ktent, 0, sizeof(ktent)); ktent.principal = princ; ktent.key = testp[encnum]; ktent.vno = princ_ent.kvno; ret = krb5_kt_add_entry(context, kt, &ktent); if (ret) { com_err(whoami, ret, "while adding keytab entry"); exit(1); } memset(&my_creds, 0, sizeof(my_creds)); my_creds.client = princ; my_creds.server = server; ktypes[0] = testp[encnum].enctype; ret = krb5_get_init_creds_opt_alloc(context, &opt); if (ret) { com_err(whoami, ret, "while allocating gic opts"); exit(1); } krb5_get_init_creds_opt_set_etype_list(opt, ktypes, 1); ret = krb5_get_init_creds_keytab(context, &my_creds, princ, kt, 0, NULL /* in_tkt_service */, opt); krb5_get_init_creds_opt_free(context, opt); if (ret) { com_err(whoami, ret, "while acquiring initial ticket"); exit(1); } krb5_free_cred_contents(context, &my_creds); /* since I can't specify enctype explicitly ... */ ret = krb5_kt_remove_entry(context, kt, &ktent); if (ret) { com_err(whoami, ret, "while removing keytab entry"); exit(1); } } (void)kadm5_free_kadm5_key_data(context, n_extracted, extracted); } ret = krb5_kt_close(context, kt); if (ret) { com_err(whoami, ret, "while closing keytab"); exit(1); } ret = kadm5_destroy(handle); if (ret) { com_err(whoami, ret, "while closing kadmin connection"); exit(1); } krb5_free_principal(context, princ); krb5_free_principal(context, server); krb5_free_context(context); return 0; }
int do_command(krb5_context context, krb5_keytab keytab, krb5_principal me, char *princ, char *cmd, char *cmddir) { char *p; char *answer; static char answer_exec[] = "Cannot execute command."; static char answer_priv[] = "You are not privileged to execute this command."; static char answer_regexp[] = "Command doesn't match any allowed regexp."; int result; if (debug) syslog(LOG_DEBUG, "Principal %s is trying to execute command %s", princ, cmd); /* Replace \n with \0 */ p = cmd; while (*p != '\0' && *p != '\n') p++; *p = '\0'; if (gethelp(cmd) == 0) return 0; if ((result = chk_user_cmd(princ, cmd)) != 0) { switch(result) { case CHK_GRP: answer = answer_priv; break; case CHK_REGEXP: answer = answer_regexp; break; default: answer = answer_exec; } if (debug) syslog(LOG_DEBUG, "%s", answer); if (write(1, answer, strlen(answer)) == -1) printf("Failed write to stdout.\n"); return 0; } else { char *localcmd, *pathenv; char ccname[255]; krb5_ccache ccache; krb5_creds creds; krb5_principal tgtserver; krb5_error_code retval; krb5_get_init_creds_opt opts; pathenv = malloc((strlen(cmddir) + 6) * sizeof(char)); if (pathenv == NULL) { syslog(LOG_ERR, "Not enough memory (env)"); exit(1); } sprintf(pathenv, "PATH=%s", cmddir); preauth = preauth_list; #ifdef __osf__ sprintf(ccname, "FILE:/tmp/afsadm_%d", getpid()); #else snprintf(ccname, 255, "FILE:/tmp/afsadm_%d", getpid()); #endif if (retval = krb5_cc_resolve(context, ccname, &ccache)) { syslog(LOG_ERR, "%s while resolving ccache", error_message(retval)); exit(1); } #ifdef __osf__ sprintf(ccname, "KRB5CCNAME=FILE:/tmp/afsadm_%d", getpid()); #else snprintf(ccname, 255, "KRB5CCNAME=FILE:/tmp/afsadm_%d", getpid()); #endif putenv(ccname); if (retval = krb5_cc_initialize(context, ccache, me)) { syslog(LOG_ERR, "%s while initialize ccache", error_message(retval)); exit(1); } memset((char *)&creds, 0, sizeof(creds)); creds.client = me; krb5_data *realm = krb5_princ_realm(context, me); if ((retval = krb5_build_principal_ext(context, &tgtserver, realm->length, realm->data, tgtname.length, tgtname.data, realm->length, realm->data, 0))) { syslog(LOG_ERR, "%s while building server name", error_message(retval)); krb5_cc_destroy(context, ccache); exit(1); } creds.server = tgtserver; krb5_get_init_creds_opt_init(&opts); opts.preauth_list = preauth; if (retval = krb5_get_init_creds_keytab(context, &creds, me, keytab, 0, NULL, &opts)) { syslog(LOG_ERR, "%s while getting tgt", error_message(retval)); krb5_cc_destroy(context, ccache); exit(1); } if (retval = krb5_cc_store_cred(context, ccache, &creds)) { syslog(LOG_ERR, "%s while saving credentials to ccache", error_message(retval)); krb5_cc_destroy(context, ccache); exit(1); } if (k_hasafs()) k_setpag(); localcmd = malloc(sizeof(char) * (strlen(cmd) + strlen(cmddir) + 2)); if (localcmd == NULL) { syslog(LOG_ERR, "Not enough memory (cmdpath malloc)"); exit(1); } sprintf(localcmd, "%s/%s", cmddir, cmd); syslog(LOG_INFO, "Principal %s : system(%s)", princ, localcmd); /* Set PATH to dircmd !!!! */ putenv(pathenv); //system("/usr/bin/id -a; aklog"); if (system("aklog") == -1) printf("Cannot execute aklog.\n"); result = system(localcmd); syslog(LOG_INFO, "Principal %s : system(%s) returns with %d", princ, localcmd, result); free(pathenv); free(localcmd); if (k_hasafs()) k_unlog(); krb5_cc_destroy(context, ccache); return 0; } }