--- sys/rpc/rpcsec_gss.h.orig 2012-10-14 17:39:45.000000000 -0400 +++ sys/rpc/rpcsec_gss.h 2012-12-20 17:19:58.000000000 -0500 @@ -153,9 +153,9 @@ typedef AUTH *rpc_gss_secfind_ftype(CLIE rpc_gss_service_t service); typedef void rpc_gss_secpurge_ftype(CLIENT *clnt); typedef AUTH *rpc_gss_seccreate_ftype(CLIENT *clnt, struct ucred *cred, - const char *principal, const char *mechanism, - rpc_gss_service_t service, const char *qop, - rpc_gss_options_req_t *options_req, + const char *clnt_principal, const char *principal, + const char *mechanism, rpc_gss_service_t service, + const char *qop, rpc_gss_options_req_t *options_req, rpc_gss_options_ret_t *options_ret); typedef bool_t rpc_gss_set_defaults_ftype(AUTH *auth, rpc_gss_service_t service, const char *qop); @@ -183,6 +183,7 @@ typedef bool_t rpc_gss_get_principal_nam const char *domain); typedef int rpc_gss_svc_max_data_length_ftype(struct svc_req *req, int max_tp_unit_len); +typedef void rpc_gss_refresh_auth_ftype(AUTH *auth); struct rpc_gss_entries { rpc_gss_secfind_ftype *rpc_gss_secfind; @@ -204,6 +205,7 @@ struct rpc_gss_entries { rpc_gss_clear_callback_ftype *rpc_gss_clear_callback; rpc_gss_get_principal_name_ftype *rpc_gss_get_principal_name; rpc_gss_svc_max_data_length_ftype *rpc_gss_svc_max_data_length; + rpc_gss_refresh_auth_ftype *rpc_gss_refresh_auth; }; extern struct rpc_gss_entries rpc_gss_entries; @@ -229,16 +231,17 @@ rpc_gss_secpurge_call(CLIENT *clnt) } static __inline AUTH * -rpc_gss_seccreate_call(CLIENT *clnt, struct ucred *cred, const char *principal, - const char *mechanism, rpc_gss_service_t service, const char *qop, +rpc_gss_seccreate_call(CLIENT *clnt, struct ucred *cred, + const char *clnt_principal, const char *principal, const char *mechanism, + rpc_gss_service_t service, const char *qop, rpc_gss_options_req_t *options_req, rpc_gss_options_ret_t *options_ret) { AUTH *ret = NULL; if (rpc_gss_entries.rpc_gss_seccreate != NULL) ret = (*rpc_gss_entries.rpc_gss_seccreate)(clnt, cred, - principal, mechanism, service, qop, options_req, - options_ret); + clnt_principal, principal, mechanism, service, qop, + options_req, options_ret); return (ret); } @@ -406,14 +409,29 @@ rpc_gss_svc_max_data_length_call(struct return (ret); } +static __inline void +rpc_gss_refresh_auth_call(AUTH *auth) +{ + + if (rpc_gss_entries.rpc_gss_refresh_auth != NULL) + (*rpc_gss_entries.rpc_gss_refresh_auth)(auth); +} + AUTH *rpc_gss_secfind(CLIENT *clnt, struct ucred *cred, const char *principal, gss_OID mech_oid, rpc_gss_service_t service); void rpc_gss_secpurge(CLIENT *clnt); -#endif +void rpc_gss_refresh_auth(AUTH *auth); +AUTH *rpc_gss_seccreate(CLIENT *clnt, struct ucred *cred, + const char *clnt_principal, const char *principal, + const char *mechanism, rpc_gss_service_t service, + const char *qop, rpc_gss_options_req_t *options_req, + rpc_gss_options_ret_t *options_ret); +#else /* !_KERNEL */ AUTH *rpc_gss_seccreate(CLIENT *clnt, struct ucred *cred, const char *principal, const char *mechanism, rpc_gss_service_t service, const char *qop, rpc_gss_options_req_t *options_req, rpc_gss_options_ret_t *options_ret); +#endif /* _KERNEL */ bool_t rpc_gss_set_defaults(AUTH *auth, rpc_gss_service_t service, const char *qop); int rpc_gss_max_data_length(AUTH *handle, int max_tp_unit_len); --- sys/rpc/rpcsec_gss/rpcsec_gss.c.orig 2012-10-14 17:39:45.000000000 -0400 +++ sys/rpc/rpcsec_gss/rpcsec_gss.c 2012-12-21 16:31:40.000000000 -0500 @@ -82,6 +82,8 @@ __FBSDID("$FreeBSD: head/sys/rpc/rpcsec_ #include #include +#include + #include "rpcsec_gss_int.h" static void rpc_gss_nextverf(AUTH*); @@ -122,6 +124,7 @@ struct rpc_gss_data { AUTH *gd_auth; /* link back to AUTH */ struct ucred *gd_ucred; /* matching local cred */ char *gd_principal; /* server principal name */ + char *gd_clntprincipal; /* client principal name */ rpc_gss_options_req_t gd_options; /* GSS context options */ enum rpcsec_gss_state gd_state; /* connection state */ gss_buffer_desc gd_verf; /* save GSS_S_COMPLETE @@ -153,7 +156,7 @@ static struct sx rpc_gss_lock; static int rpc_gss_count; static AUTH *rpc_gss_seccreate_int(CLIENT *, struct ucred *, const char *, - gss_OID, rpc_gss_service_t, u_int, rpc_gss_options_req_t *, + const char *, gss_OID, rpc_gss_service_t, u_int, rpc_gss_options_req_t *, rpc_gss_options_ret_t *); static void @@ -251,8 +254,8 @@ again: /* * We missed in the cache - create a new association. */ - auth = rpc_gss_seccreate_int(clnt, cred, principal, mech_oid, service, - GSS_C_QOP_DEFAULT, NULL, NULL); + auth = rpc_gss_seccreate_int(clnt, cred, NULL, principal, mech_oid, + service, GSS_C_QOP_DEFAULT, NULL, NULL); if (!auth) return (NULL); @@ -304,9 +307,10 @@ rpc_gss_secpurge(CLIENT *clnt) } AUTH * -rpc_gss_seccreate(CLIENT *clnt, struct ucred *cred, const char *principal, - const char *mechanism, rpc_gss_service_t service, const char *qop, - rpc_gss_options_req_t *options_req, rpc_gss_options_ret_t *options_ret) +rpc_gss_seccreate(CLIENT *clnt, struct ucred *cred, const char *clnt_principal, + const char *principal, const char *mechanism, rpc_gss_service_t service, + const char *qop, rpc_gss_options_req_t *options_req, + rpc_gss_options_ret_t *options_ret) { gss_OID oid; u_int qop_num; @@ -324,13 +328,33 @@ rpc_gss_seccreate(CLIENT *clnt, struct u qop_num = GSS_C_QOP_DEFAULT; } - return (rpc_gss_seccreate_int(clnt, cred, principal, oid, service, - qop_num, options_req, options_ret)); + return (rpc_gss_seccreate_int(clnt, cred, clnt_principal, principal, + oid, service, qop_num, options_req, options_ret)); +} + +void +rpc_gss_refresh_auth(AUTH *auth) +{ + struct rpc_gss_data *gd; + rpc_gss_options_ret_t options; + + gd = AUTH_PRIVATE(auth); + /* + * If the state != ESTABLISHED, try and initialize + * the authenticator again. This will happen if the + * user's credentials have expired. It may succeed now, + * if they have done a kinit or similar. + */ + if (gd->gd_state != RPCSEC_GSS_ESTABLISHED) { + memset(&options, 0, sizeof (options)); + (void) rpc_gss_init(auth, &options); + } } static AUTH * -rpc_gss_seccreate_int(CLIENT *clnt, struct ucred *cred, const char *principal, - gss_OID mech_oid, rpc_gss_service_t service, u_int qop_num, +rpc_gss_seccreate_int(CLIENT *clnt, struct ucred *cred, + const char *clnt_principal, const char *principal, gss_OID mech_oid, + rpc_gss_service_t service, u_int qop_num, rpc_gss_options_req_t *options_req, rpc_gss_options_ret_t *options_ret) { AUTH *auth; @@ -379,6 +403,10 @@ rpc_gss_seccreate_int(CLIENT *clnt, stru gd->gd_auth = auth; gd->gd_ucred = crdup(cred); gd->gd_principal = strdup(principal, M_RPC); + if (clnt_principal != NULL) + gd->gd_clntprincipal = strdup(clnt_principal, M_RPC); + else + gd->gd_clntprincipal = NULL; if (options_req) { @@ -719,6 +747,8 @@ rpc_gss_init(AUTH *auth, rpc_gss_options OM_uint32 maj_stat, min_stat, call_stat; const char *mech; struct rpc_callextra ext; + gss_OID mech_oid; + gss_OID_set mechlist; rpc_gss_log_debug("in rpc_gss_refresh()"); @@ -745,6 +775,65 @@ rpc_gss_init(AUTH *auth, rpc_gss_options gd->gd_cred.gc_proc = RPCSEC_GSS_INIT; gd->gd_cred.gc_seq = 0; + /* + * For KerberosV, if there is a client principal name, that implies + * that this is a host based initiator credential in the default + * keytab file. For this case, it is necessary to do a + * gss_acquire_cred(). When this is done, the gssd daemon will + * do the equivalent of "kinit -k" to put a TGT for the name in + * the credential cache file for the gssd daemon. + */ + if (gd->gd_clntprincipal != NULL && + rpc_gss_mech_to_oid("kerberosv5", &mech_oid) && + gd->gd_mech == mech_oid) { + /* Get rid of any old credential. */ + if (gd->gd_options.my_cred != GSS_C_NO_CREDENTIAL) { + gss_release_cred(&min_stat, &gd->gd_options.my_cred); + gd->gd_options.my_cred = GSS_C_NO_CREDENTIAL; + } + + /* + * The mechanism must be set to KerberosV for acquisition + * of credentials to work reliably. + */ + maj_stat = gss_create_empty_oid_set(&min_stat, &mechlist); + if (maj_stat != GSS_S_COMPLETE) { + options_ret->major_status = maj_stat; + options_ret->minor_status = min_stat; + goto out; + } + maj_stat = gss_add_oid_set_member(&min_stat, gd->gd_mech, + &mechlist); + if (maj_stat != GSS_S_COMPLETE) { + options_ret->major_status = maj_stat; + options_ret->minor_status = min_stat; + gss_release_oid_set(&min_stat, &mechlist); + goto out; + } + + principal_desc.value = (void *)gd->gd_clntprincipal; + principal_desc.length = strlen(gd->gd_clntprincipal); + maj_stat = gss_import_name(&min_stat, &principal_desc, + GSS_C_NT_HOSTBASED_SERVICE, &name); + if (maj_stat != GSS_S_COMPLETE) { + options_ret->major_status = maj_stat; + options_ret->minor_status = min_stat; + gss_release_oid_set(&min_stat, &mechlist); + goto out; + } + /* Acquire the credentials. */ + maj_stat = gss_acquire_cred(&min_stat, name, 0, + mechlist, GSS_C_INITIATE, + &gd->gd_options.my_cred, NULL, NULL); + gss_release_name(&min_stat, &name); + gss_release_oid_set(&min_stat, &mechlist); + if (maj_stat != GSS_S_COMPLETE) { + options_ret->major_status = maj_stat; + options_ret->minor_status = min_stat; + goto out; + } + } + principal_desc.value = (void *)gd->gd_principal; principal_desc.length = strlen(gd->gd_principal); maj_stat = gss_import_name(&min_stat, &principal_desc, @@ -1036,6 +1125,8 @@ rpc_gss_destroy(AUTH *auth) CLNT_RELEASE(gd->gd_clnt); crfree(gd->gd_ucred); free(gd->gd_principal, M_RPC); + if (gd->gd_clntprincipal != NULL) + free(gd->gd_clntprincipal, M_RPC); if (gd->gd_verf.value) xdr_free((xdrproc_t) xdr_gss_buffer_desc, (char *) &gd->gd_verf); --- sys/fs/nfs/nfs.h.orig 2012-12-08 17:52:44.000000000 -0500 +++ sys/fs/nfs/nfs.h 2012-12-20 17:19:58.000000000 -0500 @@ -466,6 +466,7 @@ struct nfssockreq { u_int32_t nr_prog; u_int32_t nr_vers; struct __rpc_client *nr_client; + AUTH *nr_auth; }; /* --- sys/fs/nfs/nfs_commonkrpc.c.orig 2012-12-08 17:52:44.000000000 -0500 +++ sys/fs/nfs/nfs_commonkrpc.c 2012-12-20 21:03:22.000000000 -0500 @@ -102,7 +102,6 @@ static int nfs_bufpackets = 4; static int nfs_reconnects; static int nfs3_jukebox_delay = 10; static int nfs_skip_wcc_data_onerr = 1; -static int nfs_keytab_enctype = ETYPE_DES_CBC_CRC; SYSCTL_DECL(_vfs_nfs); @@ -114,8 +113,6 @@ SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs3_juke "Number of seconds to delay a retry after receiving EJUKEBOX"); SYSCTL_INT(_vfs_nfs, OID_AUTO, skip_wcc_data_onerr, CTLFLAG_RW, &nfs_skip_wcc_data_onerr, 0, "Disable weak cache consistency checking when server returns an error"); -SYSCTL_INT(_vfs_nfs, OID_AUTO, keytab_enctype, CTLFLAG_RW, &nfs_keytab_enctype, 0, - "Encryption type for the keytab entry used by nfs"); static void nfs_down(struct nfsmount *, struct thread *, const char *, int, int); @@ -393,9 +390,6 @@ nfs_getauth(struct nfssockreq *nrp, int { rpc_gss_service_t svc; AUTH *auth; -#ifdef notyet - rpc_gss_options_req_t req_options; -#endif switch (secflavour) { case RPCSEC_GSS_KRB5: @@ -411,28 +405,16 @@ nfs_getauth(struct nfssockreq *nrp, int svc = rpc_gss_svc_integrity; else svc = rpc_gss_svc_privacy; -#ifdef notyet - req_options.req_flags = GSS_C_MUTUAL_FLAG; - req_options.time_req = 0; - req_options.my_cred = GSS_C_NO_CREDENTIAL; - req_options.input_channel_bindings = NULL; - req_options.enc_type = nfs_keytab_enctype; - - auth = rpc_gss_secfind_call(nrp->nr_client, cred, - clnt_principal, srv_principal, mech_oid, svc, - &req_options); -#else - /* - * Until changes to the rpcsec_gss code are committed, - * there is no support for host based initiator - * principals. As such, that case cannot yet be handled. - */ + if (clnt_principal == NULL) auth = rpc_gss_secfind_call(nrp->nr_client, cred, srv_principal, mech_oid, svc); - else - auth = NULL; -#endif + else { + auth = rpc_gss_seccreate_call(nrp->nr_client, cred, + clnt_principal, srv_principal, "kerberosv5", + svc, NULL, NULL, NULL); + return (auth); + } if (auth != NULL) return (auth); /* fallthrough */ @@ -506,7 +488,7 @@ newnfs_request(struct nfsrv_descript *nd struct rpc_callextra ext; enum clnt_stat stat; struct nfsreq *rep = NULL; - char *srv_principal = NULL; + char *srv_principal = NULL, *clnt_principal = NULL; sigset_t oldset; struct ucred *authcred; @@ -569,6 +551,7 @@ newnfs_request(struct nfsrv_descript *nd */ if (nmp->nm_krbnamelen > 0) { usegssname = 1; + clnt_principal = nmp->nm_krbname; } else if (nmp->nm_uid != (uid_t)-1) { KASSERT(nmp->nm_sockreq.nr_cred != NULL, ("newnfs_request: NULL nr_cred")); @@ -624,10 +607,19 @@ newnfs_request(struct nfsrv_descript *nd if (nd->nd_procnum == NFSPROC_NULL) auth = authnone_create(); - else if (usegssname) - auth = nfs_getauth(nrp, secflavour, nmp->nm_krbname, - srv_principal, NULL, authcred); - else + else if (usegssname) { + /* + * For this case, the authenticator is held in the + * nfssockreq structure, so don't release the reference count + * held on it. --> Don't AUTH_DESTROY() it in this function. + */ + if (nrp->nr_auth == NULL) + nrp->nr_auth = nfs_getauth(nrp, secflavour, + clnt_principal, srv_principal, NULL, authcred); + else + rpc_gss_refresh_auth_call(nrp->nr_auth); + auth = nrp->nr_auth; + } else auth = nfs_getauth(nrp, secflavour, NULL, srv_principal, NULL, authcred); crfree(authcred); @@ -777,7 +769,8 @@ tryagain: } if (error) { m_freem(nd->nd_mreq); - AUTH_DESTROY(auth); + if (usegssname == 0) + AUTH_DESTROY(auth); if (rep != NULL) FREE((caddr_t)rep, M_NFSDREQ); if (set_sigset) @@ -987,7 +980,8 @@ tryagain: #endif m_freem(nd->nd_mreq); - AUTH_DESTROY(auth); + if (usegssname == 0) + AUTH_DESTROY(auth); if (rep != NULL) FREE((caddr_t)rep, M_NFSDREQ); if (set_sigset) @@ -996,7 +990,8 @@ tryagain: nfsmout: mbuf_freem(nd->nd_mrep); mbuf_freem(nd->nd_mreq); - AUTH_DESTROY(auth); + if (usegssname == 0) + AUTH_DESTROY(auth); if (rep != NULL) FREE((caddr_t)rep, M_NFSDREQ); if (set_sigset) --- sys/fs/nfsclient/nfs_clvfsops.c.orig 2012-12-09 17:23:51.000000000 -0500 +++ sys/fs/nfsclient/nfs_clvfsops.c 2012-12-21 09:26:35.000000000 -0500 @@ -1449,6 +1449,8 @@ bad: nfscl_clientrelease(clp); newnfs_disconnect(&nmp->nm_sockreq); crfree(nmp->nm_sockreq.nr_cred); + if (nmp->nm_sockreq.nr_auth != NULL) + AUTH_DESTROY(nmp->nm_sockreq.nr_auth); mtx_destroy(&nmp->nm_sockreq.nr_mtx); mtx_destroy(&nmp->nm_mtx); if (nmp->nm_clp != NULL) { @@ -1511,7 +1513,8 @@ nfs_unmount(struct mount *mp, int mntfla newnfs_disconnect(&nmp->nm_sockreq); crfree(nmp->nm_sockreq.nr_cred); FREE(nmp->nm_nam, M_SONAME); - + if (nmp->nm_sockreq.nr_auth != NULL) + AUTH_DESTROY(nmp->nm_sockreq.nr_auth); mtx_destroy(&nmp->nm_sockreq.nr_mtx); mtx_destroy(&nmp->nm_mtx); TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) --- sys/kgssapi/gss_impl.c.orig 2012-12-17 18:54:42.000000000 -0500 +++ sys/kgssapi/gss_impl.c 2012-12-21 09:17:00.000000000 -0500 @@ -286,6 +286,7 @@ kgssapi_modevent(module_t mod, int type, switch (type) { case MOD_LOAD: + rpc_gss_entries.rpc_gss_refresh_auth = rpc_gss_refresh_auth; rpc_gss_entries.rpc_gss_secfind = rpc_gss_secfind; rpc_gss_entries.rpc_gss_secpurge = rpc_gss_secpurge; rpc_gss_entries.rpc_gss_seccreate = rpc_gss_seccreate; --- usr.sbin/gssd/gssd.c.orig 2012-12-22 18:44:29.000000000 -0500 +++ usr.sbin/gssd/gssd.c 2012-12-22 18:45:39.000000000 -0500 @@ -72,6 +72,7 @@ static char pref_realm[1024]; static void gssd_load_mech(void); static int find_ccache_file(const char *, uid_t, char *); static int is_a_valid_tgt_cache(const char *, uid_t, int *, time_t *); +static krb5_error_code gssd_get_cc_from_keytab(const char *); extern void gssd_1(struct svc_req *rqstp, SVCXPRT *transp); extern int gssd_syscall(char *path); @@ -308,7 +309,15 @@ gssd_init_sec_context_1_svc(init_sec_con int gotone; memset(result, 0, sizeof(*result)); - if (ccfile_dirlist[0] != '\0' && argp->cred == 0) { + if (argp->cred != 0 && argp->uid == 0) { + /* + * These credentials are for a host based initiator name + * in a keytab file, which should now have credentials + * in /tmp/krb5cc_gssd, because gss_acquire_cred() did + * the equivalent of "kinit -k". + */ + setenv("KRB5CCNAME", "FILE:/tmp/krb5cc_gssd", TRUE); + } else if (ccfile_dirlist[0] != '\0' && argp->cred == 0) { /* * For the "-s" case and no credentials provided as an * argument, search the directory list for an appropriate @@ -331,6 +340,7 @@ gssd_init_sec_context_1_svc(init_sec_con result->major_status = GSS_S_CREDENTIALS_EXPIRED; return (TRUE); } + setenv("KRB5CCNAME", ccname, TRUE); } else { /* * If there wasn't a "-s" option or the credentials have @@ -347,8 +357,8 @@ gssd_init_sec_context_1_svc(init_sec_con } snprintf(ccname, sizeof(ccname), "FILE:/tmp/krb5cc_%d", (int) argp->uid); + setenv("KRB5CCNAME", ccname, TRUE); } - setenv("KRB5CCNAME", ccname, TRUE); if (argp->cred) { cred = gssd_find_resource(argp->cred); @@ -593,9 +603,44 @@ gssd_acquire_cred_1_svc(acquire_cred_arg gss_cred_id_t cred; char ccname[PATH_MAX + 5 + 1], *cp, *cp2; int gotone; + krb5_error_code kret; + gss_buffer_desc namebuf; + uint32_t minstat; memset(result, 0, sizeof(*result)); - if (ccfile_dirlist[0] != '\0' && argp->desired_name == 0) { + if (argp->desired_name) { + desired_name = gssd_find_resource(argp->desired_name); + if (!desired_name) { + result->major_status = GSS_S_BAD_NAME; + return (TRUE); + } + } + + if (argp->desired_name != 0 && argp->uid == 0 && + argp->cred_usage == GSS_C_INITIATE) { + /* This is a host based initiator name in the keytab file. */ + setenv("KRB5CCNAME", "FILE:/tmp/krb5cc_gssd", TRUE); + result->major_status = gss_display_name(&result->minor_status, + desired_name, &namebuf, NULL); + if (result->major_status != GSS_S_COMPLETE) + return (TRUE); + if (namebuf.length > PATH_MAX + 5) { + result->minor_status = 0; + result->major_status = GSS_S_FAILURE; + return (TRUE); + } + memcpy(ccname, namebuf.value, namebuf.length); + ccname[namebuf.length] = '\0'; + if ((cp = strchr(ccname, '@')) != NULL) + *cp = '/'; + kret = gssd_get_cc_from_keytab(ccname); + gss_release_buffer(&minstat, &namebuf); + if (kret != 0) { + result->minor_status = kret; + result->major_status = GSS_S_FAILURE; + return (TRUE); + } + } else if (ccfile_dirlist[0] != '\0' && argp->desired_name == 0) { /* * For the "-s" case and no name provided as an * argument, search the directory list for an appropriate @@ -618,6 +663,7 @@ gssd_acquire_cred_1_svc(acquire_cred_arg result->major_status = GSS_S_CREDENTIALS_EXPIRED; return (TRUE); } + setenv("KRB5CCNAME", ccname, TRUE); } else { /* * If there wasn't a "-s" option or the name has @@ -635,15 +681,7 @@ gssd_acquire_cred_1_svc(acquire_cred_arg } snprintf(ccname, sizeof(ccname), "FILE:/tmp/krb5cc_%d", (int) argp->uid); - } - setenv("KRB5CCNAME", ccname, TRUE); - - if (argp->desired_name) { - desired_name = gssd_find_resource(argp->desired_name); - if (!desired_name) { - result->major_status = GSS_S_BAD_NAME; - return (TRUE); - } + setenv("KRB5CCNAME", ccname, TRUE); } result->major_status = gss_acquire_cred(&result->minor_status, @@ -915,3 +953,54 @@ is_a_valid_tgt_cache(const char *filepat return (ret); } +/* + * This function attempts to do essentially a "kinit -k" for the principal + * name provided as the argument, so that there will be a TGT in the + * credential cache. + */ +static krb5_error_code +gssd_get_cc_from_keytab(const char *name) +{ + krb5_error_code ret, opt_ret, princ_ret, cc_ret, kt_ret, cred_ret; + krb5_context context; + krb5_principal principal; + krb5_keytab kt; + krb5_creds cred; + krb5_get_init_creds_opt *opt; + krb5_deltat start_time = 0; + krb5_ccache ccache; + + ret = krb5_init_context(&context); + if (ret != 0) + return (ret); + princ_ret = ret = krb5_parse_name(context, name, &principal); + if (ret == 0) + opt_ret = ret = krb5_get_init_creds_opt_alloc(context, &opt); + if (ret == 0) + cc_ret = ret = krb5_cc_default(context, &ccache); + if (ret == 0) + ret = krb5_cc_initialize(context, ccache, principal); + if (ret == 0) { + krb5_get_init_creds_opt_set_default_flags(context, "gssd", + krb5_principal_get_realm(context, principal), opt); + kt_ret = ret = krb5_kt_default(context, &kt); + } + if (ret == 0) + cred_ret = ret = krb5_get_init_creds_keytab(context, &cred, + principal, kt, start_time, NULL, opt); + if (ret == 0) + ret = krb5_cc_store_cred(context, ccache, &cred); + if (kt_ret == 0) + krb5_kt_close(context, kt); + if (cc_ret == 0) + krb5_cc_close(context, ccache); + if (opt_ret == 0) + krb5_get_init_creds_opt_free(context, opt); + if (princ_ret == 0) + krb5_free_principal(context, principal); + if (cred_ret == 0) + krb5_free_cred_contents(context, &cred); + krb5_free_context(context); + return (ret); +} +