* [PATCH 1/2] gssd: have process_krb5_upcall fork before handling upcall
2013-10-03 18:42 [PATCH 0/2] gssd: allow it to work with KEYRING: credcaches Jeff Layton
@ 2013-10-03 18:42 ` Jeff Layton
2013-10-03 18:56 ` Jeff Layton
2013-10-03 18:42 ` [PATCH 2/2] gssd: switch real uid instead of just fsuid when looking for user creds Jeff Layton
1 sibling, 1 reply; 4+ messages in thread
From: Jeff Layton @ 2013-10-03 18:42 UTC (permalink / raw)
To: steved; +Cc: linux-nfs
In order to handle KEYRING: caches, we need to be able to switch the
real UID of the process to the designated one, but that opens the door
to allowing gssd to be killed or reniced during the window where we've
switched credentials.
Change gssd to fork before trying to handle each upcall. The child will
do the work to establish the context and the parent task will just wait
for it to exit. It's still possible for the child to be killed or
reniced, but that would only affect a single upcall instead of the
entire daemon.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
utils/gssd/gssd_main_loop.c | 3 ++-
utils/gssd/gssd_proc.c | 19 ++++++++++++++++++-
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c
index ccf7fe5..7b0f568 100644
--- a/utils/gssd/gssd_main_loop.c
+++ b/utils/gssd/gssd_main_loop.c
@@ -40,7 +40,8 @@
#include <sys/socket.h>
#include <sys/poll.h>
#include <netinet/in.h>
-
+#include <sys/types.h>
+#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index e58c341..1a58809 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -982,6 +982,23 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
int err, downcall_err = -EACCES;
gss_cred_id_t gss_cred;
OM_uint32 maj_stat, min_stat, lifetime_rec;
+ pid_t pid;
+
+ 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 */
+ wait(&err);
+ return;
+ }
printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
@@ -1121,7 +1138,7 @@ out:
AUTH_DESTROY(auth);
if (rpc_clnt)
clnt_destroy(rpc_clnt);
- return;
+ exit(0);
out_return_error:
do_error_downcall(fd, uid, downcall_err);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH 2/2] gssd: switch real uid instead of just fsuid when looking for user creds
2013-10-03 18:42 [PATCH 0/2] gssd: allow it to work with KEYRING: credcaches Jeff Layton
2013-10-03 18:42 ` [PATCH 1/2] gssd: have process_krb5_upcall fork before handling upcall Jeff Layton
@ 2013-10-03 18:42 ` Jeff Layton
1 sibling, 0 replies; 4+ messages in thread
From: Jeff Layton @ 2013-10-03 18:42 UTC (permalink / raw)
To: steved; +Cc: linux-nfs
The part of process_krb5_upcall that handles non-machine user creds
first tries to query GSSAPI for credentials. If that fails, it then
falls back to trawling through likely credcache locations to find them
and then points $KRB5CCNAME at it before proceeding. There are a number
of bugs in this code that this patch attempts to address.
The code that queries GSSAPI for credentials does it as root and that
almost universally fails to do anything useful unless we happen to be
looking for non-machine root creds. Because of this, gssd almost always
falls back to having to search for credcaches "manually" and then set
$KRB5CCNAME if and when they are found. The code that handles credential
switching is in create_auth_rpc_client, so it's too late to be of any
use here.
Worse yet, the GSSAPI code that handles finding credcaches does it based
on the return from getuid(), so just switching the fsuid or even euid is
insufficient. You must switch the real uid.
This code moves the credential switching into process_krb5_upcall and
makes it use setuid() instead of setfsuid(). That's of course
irreversible so we can't switch back to root after doing so. No matter
though since it's probably safer to do all of this as an unprivileged
user anyway.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
utils/gssd/gssd_main_loop.c | 3 +--
utils/gssd/gssd_proc.c | 28 ++++++++++++----------------
2 files changed, 13 insertions(+), 18 deletions(-)
diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c
index 7b0f568..ccf7fe5 100644
--- a/utils/gssd/gssd_main_loop.c
+++ b/utils/gssd/gssd_main_loop.c
@@ -40,8 +40,7 @@
#include <sys/socket.h>
#include <sys/poll.h>
#include <netinet/in.h>
-#include <sys/types.h>
-#include <sys/wait.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index 1a58809..4856d08 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -67,6 +67,8 @@
#include <errno.h>
#include <gssapi/gssapi.h>
#include <netdb.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#include "gssd.h"
#include "err_util.h"
@@ -832,7 +834,6 @@ create_auth_rpc_client(struct clnt_info *clp,
CLIENT *rpc_clnt = NULL;
struct rpc_gss_sec sec;
AUTH *auth = NULL;
- uid_t save_uid = -1;
int retval = -1;
OM_uint32 min_stat;
char rpc_errmsg[1024];
@@ -841,16 +842,6 @@ create_auth_rpc_client(struct clnt_info *clp,
struct sockaddr *addr = (struct sockaddr *) &clp->addr;
socklen_t salen;
- /* Create the context as the user (not as root) */
- save_uid = geteuid();
- if (setfsuid(uid) != 0) {
- printerr(0, "WARNING: Failed to setfsuid for "
- "user with uid %d\n", uid);
- goto out_fail;
- }
- printerr(2, "creating context using fsuid %d (save_uid %d)\n",
- uid, save_uid);
-
sec.qop = GSS_C_QOP_DEFAULT;
sec.svc = RPCSEC_GSS_SVC_NONE;
sec.cred = cred;
@@ -949,11 +940,6 @@ create_auth_rpc_client(struct clnt_info *clp,
out:
if (sec.cred != GSS_C_NO_CREDENTIAL)
gss_release_cred(&min_stat, &sec.cred);
- /* Restore euid to original value */
- if (((int)save_uid != -1) && (setfsuid(save_uid) != (int)uid)) {
- printerr(0, "WARNING: Failed to restore fsuid"
- " to uid %d from %d\n", save_uid, uid);
- }
return retval;
out_fail:
@@ -1031,6 +1017,16 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
service ? service : "<null>");
if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
service == NULL)) {
+
+ /* Create the context as the user (not as root) */
+ if (setuid(uid) != 0) {
+ printerr(0, "WARNING: Failed to setuid for "
+ "user with uid %d\n", uid);
+ goto out_return_error;
+ }
+
+ printerr(2, "creating context using real uid %d\n", uid);
+
/* Tell krb5 gss which credentials cache to use */
/* Try first to acquire credentials directly via GSSAPI */
err = gssd_acquire_user_cred(uid, &gss_cred);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 4+ messages in thread