| diff -up nfs-utils-1.3.0/utils/gssd/gssd_proc.c.old nfs-utils-1.3.0/utils/gssd/gssd_proc.c |
| --- nfs-utils-1.3.0/utils/gssd/gssd_proc.c.old 2015-09-24 09:48:40.833593000 -0400 |
| +++ nfs-utils-1.3.0/utils/gssd/gssd_proc.c 2015-09-24 09:50:58.747069000 -0400 |
| @@ -1023,6 +1023,113 @@ change_identity(uid_t uid) |
| return 0; |
| } |
| |
| +AUTH * |
| +krb5_not_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, |
| + int *downcall_err, int *chg_err, CLIENT **rpc_clnt) |
| +{ |
| + AUTH *auth = NULL; |
| + gss_cred_id_t gss_cred; |
| + char **dname; |
| + int err, resp = -1; |
| + |
| + printerr(1, "krb5_not_machine_creds: uid %d tgtname %s\n", |
| + uid, tgtname); |
| + |
| + *chg_err = change_identity(uid); |
| + if (*chg_err) { |
| + printerr(0, "WARNING: failed to change identity: %s", |
| + strerror(*chg_err)); |
| + goto out; |
| + } |
| + |
| + /** Tell krb5 gss which credentials cache to use. |
| + * Try first to acquire credentials directly via GSSAPI |
| + */ |
| + err = gssd_acquire_user_cred(&gss_cred); |
| + if (err == 0) |
| + resp = create_auth_rpc_client(clp, tgtname, rpc_clnt, |
| + &auth, uid, |
| + AUTHTYPE_KRB5, gss_cred); |
| + |
| + /** if create_auth_rplc_client fails try the traditional |
| + * method of trolling for credentials |
| + */ |
| + for (dname = ccachesearch; resp != 0 && *dname != NULL; dname++) { |
| + err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, |
| + *dname); |
| + if (err == -EKEYEXPIRED) |
| + *downcall_err = -EKEYEXPIRED; |
| + else if (err == 0) |
| + resp = create_auth_rpc_client(clp, tgtname, rpc_clnt, |
| + &auth, uid,AUTHTYPE_KRB5, |
| + GSS_C_NO_CREDENTIAL); |
| + } |
| + |
| +out: |
| + return auth; |
| +} |
| + |
| +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(1, "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; |
| +} |
| + |
| /* |
| * this code uses the userland rpcsec gss library to create a krb5 |
| * context on behalf of the kernel |
| @@ -1035,40 +1142,13 @@ process_krb5_upcall(struct clnt_info *cl |
| AUTH *auth = NULL; |
| struct authgss_private_data pd; |
| gss_buffer_desc token; |
| - char **credlist = NULL; |
| - char **ccname; |
| - char **dirname; |
| - int create_resp = -1; |
| int err, downcall_err = -EACCES; |
| - gss_cred_id_t gss_cred; |
| OM_uint32 maj_stat, min_stat, lifetime_rec; |
| - pid_t pid; |
| + pid_t pid, childpid = -1; |
| gss_name_t gacceptor = GSS_C_NO_NAME; |
| gss_OID mech; |
| gss_buffer_desc acceptor = {0}; |
| |
| - pid = fork(); |
| - switch(pid) { |
| - case 0: |
| - /* Child: fall through to rest of function */ |
| - break; |
| - case -1: |
| - /* fork() failed! */ |
| - printerr(0, "WARNING: unable to fork() to handle upcall: %s\n", |
| - strerror(errno)); |
| - return; |
| - default: |
| - /* Parent: just wait on child to exit and return */ |
| - do { |
| - pid = wait(&err); |
| - } while(pid == -1 && errno != -ECHILD); |
| - |
| - if (WIFSIGNALED(err)) |
| - printerr(0, "WARNING: forked child was killed with signal %d\n", |
| - WTERMSIG(err)); |
| - return; |
| - } |
| - |
| printerr(1, "handling krb5 upcall (%s)\n", clp->dirname); |
| |
| token.length = 0; |
| @@ -1101,76 +1181,48 @@ process_krb5_upcall(struct clnt_info *cl |
| if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 && |
| service == NULL)) { |
| |
| - err = change_identity(uid); |
| - if (err) { |
| - printerr(0, "WARNING: failed to change identity: %s", |
| - strerror(err)); |
| - goto out_return_error; |
| - } |
| + /* already running as uid 0 */ |
| + if (uid == 0) |
| + goto no_fork; |
| + |
| + pid = fork(); |
| + switch(pid) { |
| + case 0: |
| + /* Child: fall through to rest of function */ |
| + childpid = getpid(); |
| + unsetenv("KRB5CCNAME"); |
| + printerr(1, "CHILD forked pid %d \n", childpid); |
| + break; |
| + case -1: |
| + /* fork() failed! */ |
| + printerr(0, "WARNING: unable to fork() to handle" |
| + "upcall: %s\n", strerror(errno)); |
| + return; |
| + default: |
| + /* Parent: just wait on child to exit and return */ |
| + do { |
| + pid = wait(&err); |
| + } while(pid == -1 && errno != -ECHILD); |
| |
| - /* Tell krb5 gss which credentials cache to use */ |
| - /* Try first to acquire credentials directly via GSSAPI */ |
| - err = gssd_acquire_user_cred(&gss_cred); |
| - if (!err) |
| - create_resp = create_auth_rpc_client(clp, tgtname, &rpc_clnt, &auth, uid, |
| - AUTHTYPE_KRB5, gss_cred); |
| - /* if create_auth_rplc_client fails try the traditional method of |
| - * trolling for credentials */ |
| - for (dirname = ccachesearch; create_resp != 0 && *dirname != NULL; dirname++) { |
| - err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname); |
| - if (err == -EKEYEXPIRED) |
| - downcall_err = -EKEYEXPIRED; |
| - else if (!err) |
| - create_resp = create_auth_rpc_client(clp, tgtname, &rpc_clnt, &auth, uid, |
| - AUTHTYPE_KRB5, GSS_C_NO_CREDENTIAL); |
| + if (WIFSIGNALED(err)) |
| + printerr(0, "WARNING: forked child was killed" |
| + "with signal %d\n", WTERMSIG(err)); |
| + return; |
| } |
| +no_fork: |
| + |
| + auth = krb5_not_machine_creds(clp, uid, tgtname, &downcall_err, |
| + &err, &rpc_clnt); |
| + if (err) |
| + goto out_return_error; |
| } |
| - if (create_resp != 0) { |
| + if (auth == NULL) { |
| if (uid == 0 && (root_uses_machine_creds == 1 || |
| service != NULL)) { |
| - int nocache = 0; |
| - int success = 0; |
| - 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_return_error; |
| - } |
| - 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 credentials 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 is 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_return_error; |
| - } |
| - } |
| - } while(!success); |
| + auth = krb5_use_machine_creds(clp, uid, tgtname, |
| + service, &rpc_clnt); |
| + if (auth == NULL) |
| + goto out_return_error; |
| } else { |
| printerr(1, "WARNING: Failed to create krb5 context " |
| "for user with uid %d for server %s\n", |
| @@ -1225,7 +1277,12 @@ out: |
| AUTH_DESTROY(auth); |
| if (rpc_clnt) |
| clnt_destroy(rpc_clnt); |
| - exit(0); |
| + |
| + pid = getpid(); |
| + if (pid == childpid) |
| + exit(0); |
| + else |
| + return; |
| |
| out_return_error: |
| do_error_downcall(fd, uid, downcall_err); |