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