You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
288 lines
8.2 KiB
288 lines
8.2 KiB
7 years ago
|
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);
|