AUTH * krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, char *service, CLIENT **rpc_clnt) { AUTH *auth = NULL; char **credlist = NULL; char **ccname; int nocache = 0; int success = 0; printerr(2, "krb5_use_machine_creds: uid %d tgtname %s\n", uid, tgtname); do { gssd_refresh_krb5_machine_credential(clp->servername, NULL, service); /* * Get a list of credential cache names and try each * of them until one works or we've tried them all */ if (gssd_get_krb5_machine_cred_list(&credlist)) { printerr(0, "ERROR: No credentials found " "for connection to server %s\n", clp->servername); goto out; } for (ccname = credlist; ccname && *ccname; ccname++) { gssd_setup_krb5_machine_gss_ccache(*ccname); if ((create_auth_rpc_client(clp, tgtname, rpc_clnt, &auth, uid, AUTHTYPE_KRB5, GSS_C_NO_CREDENTIAL)) == 0) { /* Success! */ success++; break; } printerr(2, "WARNING: Failed to create machine krb5" "context with cred cache %s for server %s\n", *ccname, clp->servername); } gssd_free_krb5_machine_cred_list(credlist); if (!success) { if(nocache == 0) { nocache++; printerr(2, "WARNING: Machine cache prematurely" "expired or corrupted trying to" "recreate cache for server %s\n", clp->servername); } else { printerr(1, "WARNING: Failed to create machine" "krb5 context with any credentials" "cache for server %s\n", clp->servername); goto out; } } } while(!success); out: return auth; }
/* * Return an array of pointers to names of credential cache files * which can be used to try to create gss contexts with a server. * * Returns: * 0 => list is attached * nonzero => error */ int gssd_get_krb5_machine_cred_list(char ***list) { char **l; int listinc = 10; int listsize = listinc; int i = 0; int retval; struct gssd_k5_kt_princ *ple; /* Assume failure */ retval = -1; *list = (char **) NULL; if ((l = (char **) malloc(listsize * sizeof(char *))) == NULL) { retval = ENOMEM; goto out; } /* Need to serialize list if we ever become multi-threaded! */ for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { if (ple->ccname) { /* Make sure cred is up-to-date before returning it */ retval = gssd_refresh_krb5_machine_credential(NULL, ple); if (retval) continue; if (i + 1 > listsize) { listsize += listinc; l = (char **) realloc(l, listsize * sizeof(char *)); if (l == NULL) { retval = ENOMEM; goto out; } } if ((l[i++] = strdup(ple->ccname)) == NULL) { retval = ENOMEM; goto out; } } } if (i > 0) { l[i] = NULL; *list = l; retval = 0; goto out; } out: return retval; }
static inline void nfs_rpc_callback_setup_gss(rpc_call_channel_t *chan, nfs_client_cred_t *cred) { AUTH *auth; char hprinc[MAXPATHLEN]; int32_t code = 0; assert(cred->flavor == RPCSEC_GSS); /* MUST RFC 3530bis, section 3.3.3 */ chan->gss_sec.svc = cred->auth_union.auth_gss.svc; chan->gss_sec.qop = cred->auth_union.auth_gss.qop; /* the GSSAPI k5 mech needs to find an unexpired credential * for nfs/hostname in an accessible k5ccache */ code = gssd_refresh_krb5_machine_credential( host_name, NULL, nfs_param.krb5_param.svc.principal); if (code) { LogWarn(COMPONENT_NFS_CB, "gssd_refresh_krb5_machine_credential " "failed (%d:%d)", code, errno); goto out; } if (! format_host_principal(chan, hprinc, sizeof(hprinc))) { LogCrit(COMPONENT_NFS_CB, "format_host_principal failed"); goto out; } chan->gss_sec.cred = GSS_C_NO_CREDENTIAL; chan->gss_sec.req_flags = 0; if (chan->gss_sec.svc != RPCSEC_GSS_SVC_NONE) { /* no more lipkey, spkm3 */ chan->gss_sec.mech = (gss_OID) &krb5oid; chan->gss_sec.req_flags = GSS_C_MUTUAL_FLAG; /* XXX */ auth = authgss_create_default(chan->clnt, hprinc, &chan->gss_sec); /* authgss_create and authgss_create_default return NULL on * failure, don't assign NULL to clnt->cl_auth */ if (auth) chan->auth = auth; } out: return; }
static inline void nfs_rpc_cb_init_ccache(const char *ccache) { int code = 0; mkdir(ccache, 700); /* XXX */ ccachesearch[0] = nfs_param.krb5_param.ccache_dir; code = gssd_refresh_krb5_machine_credential( host_name, NULL, nfs_param.krb5_param.svc.principal); if (code) { LogWarn(COMPONENT_INIT, "gssd_refresh_krb5_machine_credential " "failed (%d:%d)", code, errno); goto out; } out: return; }