Blame SOURCES/nfs-utils-1.3.0-gssd-tgt-flood.patch

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