* [round2 PATCH 1/7] svcgssd: add client's principal name to downcall information
[not found] ` <20090520151651.2986.29621.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
@ 2009-05-20 15:20 ` Kevin Coffman
2009-05-20 15:20 ` [round2 PATCH 2/7] gssd: refactor update_client_list() Kevin Coffman
` (7 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Kevin Coffman @ 2009-05-20 15:20 UTC (permalink / raw)
To: steved; +Cc: linux-nfs
From: Olga Kornievskaia <aglo@citi.umich.edu>
This patch adds the krb5 hostbased principal, name which the
nfs client used to authenticate, to the svcgssd downcall
information. This information is needed for the callback
authentication.
When estabishing the callback, nfsd will pass the principal
name in the upcall to the gssd. gssd will acquire a service
ticket for the specified principal name.
Signed-off-by: Olga Kornievskaia <aglo@citi.umich.edu>
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
utils/gssd/svcgssd_proc.c | 94 ++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 87 insertions(+), 7 deletions(-)
diff --git a/utils/gssd/svcgssd_proc.c b/utils/gssd/svcgssd_proc.c
index 6f2ba61..f1bfbef 100644
--- a/utils/gssd/svcgssd_proc.c
+++ b/utils/gssd/svcgssd_proc.c
@@ -56,6 +56,7 @@
#include "gss_util.h"
#include "err_util.h"
#include "context.h"
+#include "gss_oids.h"
extern char * mech2file(gss_OID mech);
#define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.rpcsec.context/channel"
@@ -73,7 +74,7 @@ struct svc_cred {
static int
do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
gss_OID mech, gss_buffer_desc *context_token,
- int32_t endtime)
+ int32_t endtime, char *client_name)
{
FILE *f;
int i;
@@ -98,9 +99,10 @@ do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
qword_printint(f, cred->cr_gid);
qword_printint(f, cred->cr_ngroups);
printerr(2, "mech: %s, hndl len: %d, ctx len %d, timeout: %d (%d from now), "
- "uid: %d, gid: %d, num aux grps: %d:\n",
+ "clnt: %s, uid: %d, gid: %d, num aux grps: %d:\n",
fname, out_handle->length, context_token->length,
endtime, endtime - time(0),
+ client_name ? client_name : "<null>",
cred->cr_uid, cred->cr_gid, cred->cr_ngroups);
for (i=0; i < cred->cr_ngroups; i++) {
qword_printint(f, cred->cr_groups[i]);
@@ -108,6 +110,8 @@ do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
}
qword_print(f, fname);
qword_printhex(f, context_token->value, context_token->length);
+ if (client_name)
+ qword_print(f, client_name);
err = qword_eol(f);
if (err) {
printerr(1, "WARNING: error writing to downcall channel "
@@ -307,6 +311,75 @@ print_hexl(const char *description, unsigned char *cp, int length)
}
#endif
+static int
+get_krb5_hostbased_name (gss_buffer_desc *name, char **hostbased_name)
+{
+ char *p, *sname = NULL;
+ if (strchr(name->value, '@') && strchr(name->value, '/')) {
+ if ((sname = calloc(name->length, 1)) == NULL) {
+ printerr(0, "ERROR: get_krb5_hostbased_name failed "
+ "to allocate %d bytes\n", name->length);
+ return -1;
+ }
+ /* read in name and instance and replace '/' with '@' */
+ sscanf(name->value, "%[^@]", sname);
+ p = strrchr(sname, '/');
+ if (p == NULL) { /* The '@' preceeded the '/' */
+ free(sname);
+ return -1;
+ }
+ *p = '@';
+ }
+ *hostbased_name = sname;
+ return 0;
+}
+
+static int
+get_hostbased_client_name(gss_name_t client_name, gss_OID mech,
+ char **hostbased_name)
+{
+ u_int32_t maj_stat, min_stat;
+ gss_buffer_desc name;
+ gss_OID name_type = GSS_C_NO_OID;
+ char *cname;
+ int res = -1;
+
+ *hostbased_name = NULL; /* preset in case we fail */
+
+ /* Get the client's gss authenticated name */
+ maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type);
+ if (maj_stat != GSS_S_COMPLETE) {
+ pgsserr("get_hostbased_client_name: gss_display_name",
+ maj_stat, min_stat, mech);
+ goto out_err;
+ }
+ if (name.length >= 0xffff) { /* don't overflow */
+ printerr(0, "ERROR: get_hostbased_client_name: "
+ "received gss_name is too long (%d bytes)\n",
+ name.length);
+ goto out_rel_buf;
+ }
+
+ /* For Kerberos, transform the NT_KRB5_PRINCIPAL name to
+ * an NT_HOSTBASED_SERVICE name */
+ if (g_OID_equal(&krb5oid, mech)) {
+ if (get_krb5_hostbased_name(&name, &cname) == 0)
+ *hostbased_name = cname;
+ }
+
+ /* No support for SPKM3, just print a warning (for now) */
+ if (g_OID_equal(&spkm3oid, mech)) {
+ printerr(1, "WARNING: get_hostbased_client_name: "
+ "no hostbased_name support for SPKM3\n");
+ }
+
+ res = 0;
+out_rel_buf:
+ gss_release_buffer(&min_stat, &name);
+out_err:
+ return res;
+}
+
void
handle_nullreq(FILE *f) {
/* XXX initialize to a random integer to reduce chances of unnecessary
@@ -325,7 +398,7 @@ handle_nullreq(FILE *f) {
null_token = {.value = NULL};
u_int32_t ret_flags;
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
- gss_name_t client_name;
+ gss_name_t client_name = NULL;
gss_OID mech = GSS_C_NO_OID;
u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0;
u_int32_t ignore_min_stat;
@@ -334,6 +407,7 @@ handle_nullreq(FILE *f) {
static int lbuflen = 0;
static char *cp;
int32_t ctx_endtime;
+ char *hostbased_name = NULL;
printerr(1, "handling null request\n");
@@ -396,11 +470,13 @@ handle_nullreq(FILE *f) {
if (get_ids(client_name, mech, &cred)) {
/* get_ids() prints error msg */
maj_stat = GSS_S_BAD_NAME; /* XXX ? */
- gss_release_name(&ignore_min_stat, &client_name);
goto out_err;
}
- gss_release_name(&ignore_min_stat, &client_name);
-
+ if (get_hostbased_client_name(client_name, mech, &hostbased_name)) {
+ /* get_hostbased_client_name() prints error msg */
+ maj_stat = GSS_S_BAD_NAME; /* XXX ? */
+ goto out_err;
+ }
/* Context complete. Pass handle_seq in out_handle to use
* for context lookup in the kernel. */
@@ -419,7 +495,8 @@ handle_nullreq(FILE *f) {
/* We no longer need the gss context */
gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok);
- do_svc_downcall(&out_handle, &cred, mech, &ctx_token, ctx_endtime);
+ do_svc_downcall(&out_handle, &cred, mech, &ctx_token, ctx_endtime,
+ hostbased_name);
continue_needed:
send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
&out_handle, &out_tok);
@@ -428,6 +505,9 @@ out:
free(ctx_token.value);
if (out_tok.value != NULL)
gss_release_buffer(&ignore_min_stat, &out_tok);
+ if (client_name)
+ gss_release_name(&ignore_min_stat, &client_name);
+ free(hostbased_name);
printerr(1, "finished handling null request\n");
return;
^ permalink raw reply related [flat|nested] 13+ messages in thread* [round2 PATCH 2/7] gssd: refactor update_client_list()
[not found] ` <20090520151651.2986.29621.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
2009-05-20 15:20 ` [round2 PATCH 1/7] svcgssd: add client's principal name to downcall information Kevin Coffman
@ 2009-05-20 15:20 ` Kevin Coffman
2009-05-20 15:20 ` [round2 PATCH 3/7] gssd: add upcall support for callback authentication Kevin Coffman
` (6 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Kevin Coffman @ 2009-05-20 15:20 UTC (permalink / raw)
To: steved; +Cc: linux-nfs
From: Olga Kornievskaia <aglo@citi.umich.edu>
Split out the processing for a pipe to a separate routine. The next
patch adds a new pipe to be processed.
Signed-off-by: Olga Kornievskaia <aglo@citi.umich.edu>
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
utils/gssd/gssd_main_loop.c | 3 +--
utils/gssd/gssd_proc.c | 28 +++++++++++++++++++++-------
2 files changed, 22 insertions(+), 9 deletions(-)
diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c
index 917b662..397fd14 100644
--- a/utils/gssd/gssd_main_loop.c
+++ b/utils/gssd/gssd_main_loop.c
@@ -132,8 +132,7 @@ gssd_run()
while (dir_changed) {
dir_changed = 0;
if (update_client_list()) {
- printerr(0, "ERROR: couldn't update "
- "client list\n");
+ /* Error msg is already printed */
exit(1);
}
}
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index 02239d2..0fc0c42 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -478,25 +478,25 @@ find_client(char *dirname)
return 0;
}
-/* Used to read (and re-read) list of clients, set up poll array. */
-int
-update_client_list(void)
+static int
+process_pipedir(char *pipe_name)
{
struct dirent **namelist;
int i, j;
- if (chdir(pipefs_nfsdir) < 0) {
+ if (chdir(pipe_name) < 0) {
printerr(0, "ERROR: can't chdir to %s: %s\n",
- pipefs_nfsdir, strerror(errno));
+ pipe_name, strerror(errno));
return -1;
}
- j = scandir(pipefs_nfsdir, &namelist, NULL, alphasort);
+ j = scandir(pipe_name, &namelist, NULL, alphasort);
if (j < 0) {
printerr(0, "ERROR: can't scandir %s: %s\n",
- pipefs_nfsdir, strerror(errno));
+ pipe_name, strerror(errno));
return -1;
}
+
update_old_clients(namelist, j);
for (i=0; i < j; i++) {
if (i < FD_ALLOC_BLOCK
@@ -507,9 +507,23 @@ update_client_list(void)
}
free(namelist);
+
return 0;
}
+/* Used to read (and re-read) list of clients, set up poll array. */
+int
+update_client_list(void)
+{
+ int retval = -1;
+
+ retval = process_pipedir(pipefs_nfsdir);
+ if (retval)
+ printerr(0, "ERROR: processing %s\n", pipefs_nfsdir);
+
+ return retval;
+}
+
static int
do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
gss_buffer_desc *context_token)
^ permalink raw reply related [flat|nested] 13+ messages in thread* [round2 PATCH 3/7] gssd: add upcall support for callback authentication
[not found] ` <20090520151651.2986.29621.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
2009-05-20 15:20 ` [round2 PATCH 1/7] svcgssd: add client's principal name to downcall information Kevin Coffman
2009-05-20 15:20 ` [round2 PATCH 2/7] gssd: refactor update_client_list() Kevin Coffman
@ 2009-05-20 15:20 ` Kevin Coffman
2009-05-20 15:20 ` [round2 PATCH 4/7] gssd: print full client directory being handled Kevin Coffman
` (5 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Kevin Coffman @ 2009-05-20 15:20 UTC (permalink / raw)
To: steved; +Cc: linux-nfs
Change the processing so that all subdirectories within the rpc_pipefs
directory are treated equally. Any "clnt" directories that show up
within any of them are processed. (As suggested by Bruce Fields.)
Note that the callback authentication will create a new "nfs4d_cb"
subdirectory. Only new kernels (2.6.29) will create this new directory.
(The need for this directory will go away with NFSv4.1 where the
callback can be done on the same connection as the fore-channel.)
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
utils/gssd/gssd.c | 6 ---
utils/gssd/gssd.h | 9 ++++
utils/gssd/gssd_main_loop.c | 88 ++++++++++++++++++++++++++++++++++++++-----
utils/gssd/gssd_proc.c | 89 +++++++++++++++++++++++++++----------------
4 files changed, 143 insertions(+), 49 deletions(-)
diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c
index f6949db..a8a3fd9 100644
--- a/utils/gssd/gssd.c
+++ b/utils/gssd/gssd.c
@@ -56,7 +56,6 @@
#include "krb5_util.h"
char pipefs_dir[PATH_MAX] = GSSD_PIPEFS_DIR;
-char pipefs_nfsdir[PATH_MAX] = GSSD_PIPEFS_DIR;
char keytabfile[PATH_MAX] = GSSD_DEFAULT_KEYTAB_FILE;
char ccachedir[PATH_MAX] = GSSD_DEFAULT_CRED_DIR;
char *ccachesearch[GSSD_MAX_CCACHE_SEARCH + 1];
@@ -159,11 +158,6 @@ main(int argc, char *argv[])
if (preferred_realm == NULL)
gssd_k5_get_default_realm(&preferred_realm);
- snprintf(pipefs_nfsdir, sizeof(pipefs_nfsdir), "%s/%s",
- pipefs_dir, GSSD_SERVICE_NAME);
- if (pipefs_nfsdir[sizeof(pipefs_nfsdir)-1] != '\0')
- errx(1, "pipefs_nfsdir path name too long");
-
if ((progname = strrchr(argv[0], '/')))
progname++;
else
diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h
index 3c52f46..3c53a88 100644
--- a/utils/gssd/gssd.h
+++ b/utils/gssd/gssd.h
@@ -60,7 +60,6 @@ enum {AUTHTYPE_KRB5, AUTHTYPE_SPKM3, AUTHTYPE_LIPKEY};
extern char pipefs_dir[PATH_MAX];
-extern char pipefs_nfsdir[PATH_MAX];
extern char keytabfile[PATH_MAX];
extern char *ccachesearch[];
extern int use_memcache;
@@ -86,6 +85,14 @@ struct clnt_info {
struct sockaddr_storage addr;
};
+TAILQ_HEAD(topdirs_list_head, topdirs_info) topdirs_list;
+
+struct topdirs_info {
+ TAILQ_ENTRY(topdirs_info) list;
+ char *dirname;
+ int fd;
+};
+
void init_client_list(void);
int update_client_list(void);
void handle_krb5_upcall(struct clnt_info *clp);
diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c
index 397fd14..b5117c5 100644
--- a/utils/gssd/gssd_main_loop.c
+++ b/utils/gssd/gssd_main_loop.c
@@ -49,6 +49,7 @@
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
+#include <dirent.h>
#include "gssd.h"
#include "err_util.h"
@@ -98,12 +99,85 @@ scan_poll_results(int ret)
}
};
+static int
+topdirs_add_entry(struct dirent *dent)
+{
+ struct topdirs_info *tdi;
+
+ tdi = calloc(sizeof(struct topdirs_info), 1);
+ if (tdi == NULL) {
+ printerr(0, "ERROR: Couldn't allocate struct topdirs_info\n");
+ return -1;
+ }
+ tdi->dirname = malloc(PATH_MAX);
+ if (tdi->dirname == NULL) {
+ printerr(0, "ERROR: Couldn't allocate directory name\n");
+ free(tdi);
+ return -1;
+ }
+ snprintf(tdi->dirname, PATH_MAX, "%s/%s", pipefs_dir, dent->d_name);
+ tdi->fd = open(tdi->dirname, O_RDONLY);
+ if (tdi->fd != -1) {
+ fcntl(tdi->fd, F_SETSIG, DNOTIFY_SIGNAL);
+ fcntl(tdi->fd, F_NOTIFY,
+ DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT);
+ }
+
+ TAILQ_INSERT_HEAD(&topdirs_list, tdi, list);
+ return 0;
+}
+
+static void
+topdirs_free_list(void)
+{
+ struct topdirs_info *tdi;
+
+ TAILQ_FOREACH(tdi, &topdirs_list, list) {
+ free(tdi->dirname);
+ if (tdi->fd != -1)
+ close(tdi->fd);
+ TAILQ_REMOVE(&topdirs_list, tdi, list);
+ free(tdi);
+ }
+}
+
+static int
+topdirs_init_list(void)
+{
+ DIR *pipedir;
+ struct dirent *dent;
+ int ret;
+
+ TAILQ_INIT(&topdirs_list);
+
+ pipedir = opendir(pipefs_dir);
+ if (pipedir == NULL) {
+ printerr(0, "ERROR: could not open rpc_pipefs directory '%s': "
+ "%s\n", pipefs_dir, strerror(errno));
+ return -1;
+ }
+ for (dent = readdir(pipedir); dent != NULL; dent = readdir(pipedir)) {
+ if (dent->d_type != DT_DIR ||
+ strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0) {
+ continue;
+ }
+ ret = topdirs_add_entry(dent);
+ if (ret)
+ goto out_err;
+ }
+ closedir(pipedir);
+ return 0;
+out_err:
+ topdirs_free_list();
+ return -1;
+}
+
void
gssd_run()
{
int ret;
struct sigaction dn_act;
- int fd;
sigset_t set;
/* Taken from linux/Documentation/dnotify.txt: */
@@ -117,13 +191,8 @@ gssd_run()
sigaddset(&set, DNOTIFY_SIGNAL);
sigprocmask(SIG_UNBLOCK, &set, NULL);
- if ((fd = open(pipefs_nfsdir, O_RDONLY)) == -1) {
- printerr(0, "ERROR: failed to open %s: %s\n",
- pipefs_nfsdir, strerror(errno));
- exit(1);
- }
- fcntl(fd, F_SETSIG, DNOTIFY_SIGNAL);
- fcntl(fd, F_NOTIFY, DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT);
+ if (topdirs_init_list() != 0)
+ return;
init_client_list();
@@ -150,6 +219,7 @@ gssd_run()
scan_poll_results(ret);
}
}
- close(fd);
+ topdirs_free_list();
+
return;
}
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index 0fc0c42..d56865c 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -83,20 +83,20 @@
* linked list of struct clnt_info which associates a clntXXX directory
* with an index into pollarray[], and other basic data about that client.
*
- * Directory structure: created by the kernel nfs client
- * {pipefs_nfsdir}/clntXX : one per rpc_clnt struct in the kernel
- * {pipefs_nfsdir}/clntXX/krb5 : read uid for which kernel wants
+ * Directory structure: created by the kernel
+ * {rpc_pipefs}/{dir}/clntXX : one per rpc_clnt struct in the kernel
+ * {rpc_pipefs}/{dir}/clntXX/krb5 : read uid for which kernel wants
* a context, write the resulting context
- * {pipefs_nfsdir}/clntXX/info : stores info such as server name
+ * {rpc_pipefs}/{dir}/clntXX/info : stores info such as server name
*
* Algorithm:
- * Poll all {pipefs_nfsdir}/clntXX/krb5 files. When ready, data read
- * is a uid; performs rpcsec_gss context initialization protocol to
+ * Poll all {rpc_pipefs}/{dir}/clntXX/krb5 files. When data is ready,
+ * read and process; performs rpcsec_gss context initialization protocol to
* get a cred for that user. Writes result to corresponding krb5 file
* in a form the kernel code will understand.
* In addition, we make sure we are notified whenever anything is
- * created or destroyed in {pipefs_nfsdir} or in an of the clntXX directories,
- * and rescan the whole {pipefs_nfsdir} when this happens.
+ * created or destroyed in {rpc_pipefs} or in any of the clntXX directories,
+ * and rescan the whole {rpc_pipefs} when this happens.
*/
struct pollfd * pollarray;
@@ -232,11 +232,19 @@ read_service_info(char *info_file_name, char **servicename, char **servername,
sscanf(p, "port: %127s\n", cb_port);
/* check service, program, and version */
- if(memcmp(service, "nfs", 3)) return -1;
+ if (memcmp(service, "nfs", 3) != 0)
+ return -1;
*prog = atoi(program + 1); /* skip open paren */
*vers = atoi(version);
- if((*prog != 100003) || ((*vers != 2) && (*vers != 3) && (*vers != 4)))
- goto fail;
+
+ if (strlen(service) == 3 ) {
+ if ((*prog != 100003) || ((*vers != 2) && (*vers != 3) &&
+ (*vers != 4)))
+ goto fail;
+ } else if (memcmp(service, "nfs4_cb", 7) == 0) {
+ if (*vers != 1)
+ goto fail;
+ }
if (cb_port[0] != '\0') {
port = atoi(cb_port);
@@ -315,19 +323,18 @@ out:
static int
process_clnt_dir_files(struct clnt_info * clp)
{
- char kname[32];
- char sname[32];
- char info_file_name[32];
+ char name[PATH_MAX];
+ char info_file_name[PATH_MAX];
if (clp->krb5_fd == -1) {
- snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname);
- clp->krb5_fd = open(kname, O_RDWR);
+ snprintf(name, sizeof(name), "%s/krb5", clp->dirname);
+ clp->krb5_fd = open(name, O_RDWR);
}
if (clp->spkm3_fd == -1) {
- snprintf(sname, sizeof(sname), "%s/spkm3", clp->dirname);
- clp->spkm3_fd = open(sname, O_RDWR);
+ snprintf(name, sizeof(name), "%s/spkm3", clp->dirname);
+ clp->spkm3_fd = open(name, O_RDWR);
}
- if((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
+ if ((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
return -1;
snprintf(info_file_name, sizeof(info_file_name), "%s/info",
clp->dirname);
@@ -384,17 +391,18 @@ insert_clnt_poll(struct clnt_info *clp)
}
static void
-process_clnt_dir(char *dir)
+process_clnt_dir(char *dir, char *pdir)
{
struct clnt_info * clp;
if (!(clp = insert_new_clnt()))
goto fail_destroy_client;
- if (!(clp->dirname = calloc(strlen(dir) + 1, 1))) {
+ /* An extra for the '/', and an extra for the null */
+ if (!(clp->dirname = calloc(strlen(dir) + strlen(pdir) + 2, 1))) {
goto fail_destroy_client;
}
- memcpy(clp->dirname, dir, strlen(dir));
+ sprintf(clp->dirname, "%s/%s", pdir, dir);
if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
printerr(0, "ERROR: can't open %s: %s\n",
clp->dirname, strerror(errno));
@@ -438,16 +446,24 @@ init_client_list(void)
* directories, since the DNOTIFY could have been in there.
*/
static void
-update_old_clients(struct dirent **namelist, int size)
+update_old_clients(struct dirent **namelist, int size, char *pdir)
{
struct clnt_info *clp;
void *saveprev;
int i, stillhere;
+ char fname[PATH_MAX];
for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
+ /* only compare entries in the global list that are from the
+ * same pipefs parent directory as "pdir"
+ */
+ if (strncmp(clp->dirname, pdir, strlen(pdir)) != 0) continue;
+
stillhere = 0;
for (i=0; i < size; i++) {
- if (!strcmp(clp->dirname, namelist[i]->d_name)) {
+ snprintf(fname, sizeof(fname), "%s/%s",
+ pdir, namelist[i]->d_name);
+ if (strcmp(clp->dirname, fname) == 0) {
stillhere = 1;
break;
}
@@ -468,13 +484,16 @@ update_old_clients(struct dirent **namelist, int size)
/* Search for a client by directory name, return 1 if found, 0 otherwise */
static int
-find_client(char *dirname)
+find_client(char *dirname, char *pdir)
{
struct clnt_info *clp;
+ char fname[PATH_MAX];
- for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
- if (!strcmp(clp->dirname, dirname))
+ for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
+ snprintf(fname, sizeof(fname), "%s/%s", pdir, dirname);
+ if (strcmp(clp->dirname, fname) == 0)
return 1;
+ }
return 0;
}
@@ -497,12 +516,12 @@ process_pipedir(char *pipe_name)
return -1;
}
- update_old_clients(namelist, j);
+ update_old_clients(namelist, j, pipe_name);
for (i=0; i < j; i++) {
if (i < FD_ALLOC_BLOCK
&& !strncmp(namelist[i]->d_name, "clnt", 4)
- && !find_client(namelist[i]->d_name))
- process_clnt_dir(namelist[i]->d_name);
+ && !find_client(namelist[i]->d_name, pipe_name))
+ process_clnt_dir(namelist[i]->d_name, pipe_name);
free(namelist[i]);
}
@@ -516,11 +535,15 @@ int
update_client_list(void)
{
int retval = -1;
+ struct topdirs_info *tdi;
- retval = process_pipedir(pipefs_nfsdir);
- if (retval)
- printerr(0, "ERROR: processing %s\n", pipefs_nfsdir);
+ TAILQ_FOREACH(tdi, &topdirs_list, list) {
+ retval = process_pipedir(tdi->dirname);
+ if (retval)
+ printerr(1, "WARNING: error processing %s\n",
+ tdi->dirname);
+ }
return retval;
}
^ permalink raw reply related [flat|nested] 13+ messages in thread* [round2 PATCH 4/7] gssd: print full client directory being handled
[not found] ` <20090520151651.2986.29621.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (2 preceding siblings ...)
2009-05-20 15:20 ` [round2 PATCH 3/7] gssd: add upcall support for callback authentication Kevin Coffman
@ 2009-05-20 15:20 ` Kevin Coffman
2009-05-20 15:21 ` [round2 PATCH 5/7] gssd: handle new client upcall Kevin Coffman
` (4 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Kevin Coffman @ 2009-05-20 15:20 UTC (permalink / raw)
To: steved; +Cc: linux-nfs
From: Olga Kornievskaia <aglo@citi.umich.edu>
For convenience, add the full name of the upcall pipe being processed.
(Distinquishes between "normal" upcall, and a callback upcall.)
Signed-off-by: Olga Kornievskaia <aglo@citi.umich.edu>
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
utils/gssd/gssd_proc.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index d56865c..edf30be 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -853,7 +853,7 @@ handle_krb5_upcall(struct clnt_info *clp)
char **dirname;
int create_resp = -1;
- printerr(1, "handling krb5 upcall\n");
+ printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
token.length = 0;
token.value = NULL;
@@ -968,7 +968,7 @@ handle_spkm3_upcall(struct clnt_info *clp)
struct authgss_private_data pd;
gss_buffer_desc token;
- printerr(2, "handling spkm3 upcall\n");
+ printerr(2, "handling spkm3 upcall (%s)\n", clp->dirname);
token.length = 0;
token.value = NULL;
^ permalink raw reply related [flat|nested] 13+ messages in thread* [round2 PATCH 5/7] gssd: handle new client upcall
[not found] ` <20090520151651.2986.29621.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (3 preceding siblings ...)
2009-05-20 15:20 ` [round2 PATCH 4/7] gssd: print full client directory being handled Kevin Coffman
@ 2009-05-20 15:21 ` Kevin Coffman
2009-05-20 15:21 ` [round2 PATCH 6/7] gssd: process target= attribute in new upcall Kevin Coffman
` (3 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Kevin Coffman @ 2009-05-20 15:21 UTC (permalink / raw)
To: steved; +Cc: linux-nfs
From: Olga Kornievskaia <aglo@citi.umich.edu>
Add support for handling the new client-side upcall. The kernel,
beginning with 2.6.29, will attempt to use a new pipe, "gssd",
which can be used for upcalls for all gss mechanisms.
The new upcall is text-based with an <attribute>=<value> format.
Attribute/value pairs are separated by a space, and terminated
with a new-line character.
The intial version has two required attributes,
mech=<gss_mechanism_name> and uid=<user's_UID_number>, and two
optional attributes, target=<gss_target_name> and service=<value>.
Future kernels may add new attribute/value pairs.
Signed-off-by: Olga Kornievskaia <aglo@citi.umich.edu>
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
utils/gssd/gssd.h | 3 +
utils/gssd/gssd_main_loop.c | 11 +++
utils/gssd/gssd_proc.c | 185 ++++++++++++++++++++++++++++++++++++-------
3 files changed, 168 insertions(+), 31 deletions(-)
diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h
index 3c53a88..465c305 100644
--- a/utils/gssd/gssd.h
+++ b/utils/gssd/gssd.h
@@ -82,6 +82,8 @@ struct clnt_info {
int krb5_poll_index;
int spkm3_fd;
int spkm3_poll_index;
+ int gssd_fd;
+ int gssd_poll_index;
struct sockaddr_storage addr;
};
@@ -97,6 +99,7 @@ void init_client_list(void);
int update_client_list(void);
void handle_krb5_upcall(struct clnt_info *clp);
void handle_spkm3_upcall(struct clnt_info *clp);
+void handle_gssd_upcall(struct clnt_info *clp);
int gssd_acquire_cred(char *server_name);
void gssd_run(void);
diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c
index b5117c5..f1a68d3 100644
--- a/utils/gssd/gssd_main_loop.c
+++ b/utils/gssd/gssd_main_loop.c
@@ -74,6 +74,17 @@ scan_poll_results(int ret)
for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
{
+ i = clp->gssd_poll_index;
+ if (i >= 0 && pollarray[i].revents) {
+ if (pollarray[i].revents & POLLHUP)
+ dir_changed = 1;
+ if (pollarray[i].revents & POLLIN)
+ handle_gssd_upcall(clp);
+ pollarray[clp->gssd_poll_index].revents = 0;
+ ret--;
+ if (!ret)
+ break;
+ }
i = clp->krb5_poll_index;
if (i >= 0 && pollarray[i].revents) {
if (pollarray[i].revents & POLLHUP)
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index edf30be..f969829 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -73,6 +73,7 @@
#include "krb5_util.h"
#include "context.h"
#include "nfsrpc.h"
+#include "nfslib.h"
/*
* pollarray:
@@ -88,9 +89,11 @@
* {rpc_pipefs}/{dir}/clntXX/krb5 : read uid for which kernel wants
* a context, write the resulting context
* {rpc_pipefs}/{dir}/clntXX/info : stores info such as server name
+ * {rpc_pipefs}/{dir}/clntXX/gssd : pipe for all gss mechanisms using
+ * a text-based string of parameters
*
* Algorithm:
- * Poll all {rpc_pipefs}/{dir}/clntXX/krb5 files. When data is ready,
+ * Poll all {rpc_pipefs}/{dir}/clntXX/YYYY files. When data is ready,
* read and process; performs rpcsec_gss context initialization protocol to
* get a cred for that user. Writes result to corresponding krb5 file
* in a form the kernel code will understand.
@@ -289,9 +292,13 @@ destroy_client(struct clnt_info *clp)
if (clp->spkm3_poll_index != -1)
memset(&pollarray[clp->spkm3_poll_index], 0,
sizeof(struct pollfd));
+ if (clp->gssd_poll_index != -1)
+ memset(&pollarray[clp->gssd_poll_index], 0,
+ sizeof(struct pollfd));
if (clp->dir_fd != -1) close(clp->dir_fd);
if (clp->krb5_fd != -1) close(clp->krb5_fd);
if (clp->spkm3_fd != -1) close(clp->spkm3_fd);
+ if (clp->gssd_fd != -1) close(clp->gssd_fd);
free(clp->dirname);
free(clp->servicename);
free(clp->servername);
@@ -311,8 +318,10 @@ insert_new_clnt(void)
}
clp->krb5_poll_index = -1;
clp->spkm3_poll_index = -1;
+ clp->gssd_poll_index = -1;
clp->krb5_fd = -1;
clp->spkm3_fd = -1;
+ clp->gssd_fd = -1;
clp->dir_fd = -1;
TAILQ_INSERT_HEAD(&clnt_list, clp, list);
@@ -324,17 +333,42 @@ static int
process_clnt_dir_files(struct clnt_info * clp)
{
char name[PATH_MAX];
+ char gname[PATH_MAX];
char info_file_name[PATH_MAX];
- if (clp->krb5_fd == -1) {
- snprintf(name, sizeof(name), "%s/krb5", clp->dirname);
- clp->krb5_fd = open(name, O_RDWR);
+ if (clp->gssd_fd == -1) {
+ snprintf(gname, sizeof(gname), "%s/gssd", clp->dirname);
+ clp->gssd_fd = open(gname, O_RDWR);
}
- if (clp->spkm3_fd == -1) {
- snprintf(name, sizeof(name), "%s/spkm3", clp->dirname);
- clp->spkm3_fd = open(name, O_RDWR);
+ if (clp->gssd_fd == -1) {
+ if (clp->krb5_fd == -1) {
+ snprintf(name, sizeof(name), "%s/krb5", clp->dirname);
+ clp->krb5_fd = open(name, O_RDWR);
+ }
+ if (clp->spkm3_fd == -1) {
+ snprintf(name, sizeof(name), "%s/spkm3", clp->dirname);
+ clp->spkm3_fd = open(name, O_RDWR);
+ }
+
+ /* If we opened a gss-specific pipe, let's try opening
+ * the new upcall pipe again. If we succeed, close
+ * gss-specific pipe(s).
+ */
+ if (clp->krb5_fd != -1 || clp->spkm3_fd != -1) {
+ clp->gssd_fd = open(gname, O_RDWR);
+ if (clp->gssd_fd != -1) {
+ if (clp->krb5_fd != -1)
+ close(clp->krb5_fd);
+ clp->krb5_fd = -1;
+ if (clp->spkm3_fd != -1)
+ close(clp->spkm3_fd);
+ clp->spkm3_fd = -1;
+ }
+ }
}
- if ((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
+
+ if ((clp->krb5_fd == -1) && (clp->spkm3_fd == -1) &&
+ (clp->gssd_fd == -1))
return -1;
snprintf(info_file_name, sizeof(info_file_name), "%s/info",
clp->dirname);
@@ -369,6 +403,15 @@ get_poll_index(int *ind)
static int
insert_clnt_poll(struct clnt_info *clp)
{
+ if ((clp->gssd_fd != -1) && (clp->gssd_poll_index == -1)) {
+ if (get_poll_index(&clp->gssd_poll_index)) {
+ printerr(0, "ERROR: Too many gssd clients\n");
+ return -1;
+ }
+ pollarray[clp->gssd_poll_index].fd = clp->gssd_fd;
+ pollarray[clp->gssd_poll_index].events |= POLLIN;
+ }
+
if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
if (get_poll_index(&clp->krb5_poll_index)) {
printerr(0, "ERROR: Too many krb5 clients\n");
@@ -835,15 +878,13 @@ int create_auth_rpc_client(struct clnt_info *clp,
goto out;
}
-
/*
* this code uses the userland rpcsec gss library to create a krb5
* context on behalf of the kernel
*/
-void
-handle_krb5_upcall(struct clnt_info *clp)
+static void
+process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd)
{
- uid_t uid;
CLIENT *rpc_clnt = NULL;
AUTH *auth = NULL;
struct authgss_private_data pd;
@@ -859,12 +900,6 @@ handle_krb5_upcall(struct clnt_info *clp)
token.value = NULL;
memset(&pd, 0, sizeof(struct authgss_private_data));
- if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
- printerr(0, "WARNING: failed reading uid from krb5 "
- "upcall pipe: %s\n", strerror(errno));
- goto out;
- }
-
if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0)) {
/* Tell krb5 gss which credentials cache to use */
for (dirname = ccachesearch; *dirname != NULL; dirname++) {
@@ -935,7 +970,7 @@ handle_krb5_upcall(struct clnt_info *clp)
goto out_return_error;
}
- do_downcall(clp->krb5_fd, uid, &pd, &token);
+ do_downcall(fd, uid, &pd, &token);
out:
if (token.value)
@@ -951,7 +986,7 @@ out:
return;
out_return_error:
- do_error_downcall(clp->krb5_fd, uid, -1);
+ do_error_downcall(fd, uid, -1);
goto out;
}
@@ -959,10 +994,9 @@ out_return_error:
* this code uses the userland rpcsec gss library to create an spkm3
* context on behalf of the kernel
*/
-void
-handle_spkm3_upcall(struct clnt_info *clp)
+static void
+process_spkm3_upcall(struct clnt_info *clp, uid_t uid, int fd)
{
- uid_t uid;
CLIENT *rpc_clnt = NULL;
AUTH *auth = NULL;
struct authgss_private_data pd;
@@ -973,12 +1007,6 @@ handle_spkm3_upcall(struct clnt_info *clp)
token.length = 0;
token.value = NULL;
- if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) {
- printerr(0, "WARNING: failed reading uid from spkm3 "
- "upcall pipe: %s\n", strerror(errno));
- goto out;
- }
-
if (create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, AUTHTYPE_SPKM3)) {
printerr(0, "WARNING: Failed to create spkm3 context for "
"user with uid %d\n", uid);
@@ -999,7 +1027,7 @@ handle_spkm3_upcall(struct clnt_info *clp)
goto out_return_error;
}
- do_downcall(clp->spkm3_fd, uid, &pd, &token);
+ do_downcall(fd, uid, &pd, &token);
out:
if (token.value)
@@ -1011,6 +1039,101 @@ out:
return;
out_return_error:
- do_error_downcall(clp->spkm3_fd, uid, -1);
+ do_error_downcall(fd, uid, -1);
goto out;
}
+
+void
+handle_krb5_upcall(struct clnt_info *clp)
+{
+ uid_t uid;
+
+ if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
+ printerr(0, "WARNING: failed reading uid from krb5 "
+ "upcall pipe: %s\n", strerror(errno));
+ return;
+ }
+
+ return process_krb5_upcall(clp, uid, clp->krb5_fd);
+}
+
+void
+handle_spkm3_upcall(struct clnt_info *clp)
+{
+ uid_t uid;
+
+ if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) {
+ printerr(0, "WARNING: failed reading uid from spkm3 "
+ "upcall pipe: %s\n", strerror(errno));
+ return;
+ }
+
+ return process_spkm3_upcall(clp, uid, clp->spkm3_fd);
+}
+
+void
+handle_gssd_upcall(struct clnt_info *clp)
+{
+ uid_t uid;
+ char *lbuf = NULL;
+ int lbuflen = 0;
+ char *p;
+ char *mech = NULL;
+
+ printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
+
+ if (readline(clp->gssd_fd, &lbuf, &lbuflen) != 1) {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed reading request\n");
+ return;
+ }
+ printerr(2, "%s: '%s'\n", __func__, lbuf);
+
+ /* find the mechanism name */
+ if ((p = strstr(lbuf, "mech=")) != NULL) {
+ mech = malloc(lbuflen);
+ if (!mech)
+ goto out;
+ if (sscanf(p, "mech=%s", mech) != 1) {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed to parse gss mechanism name "
+ "in upcall string '%s'\n", lbuf);
+ goto out;
+ }
+ } else {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed to find gss mechanism name "
+ "in upcall string '%s'\n", lbuf);
+ goto out;
+ }
+
+ /* read uid */
+ if ((p = strstr(lbuf, "uid=")) != NULL) {
+ if (sscanf(p, "uid=%d", &uid) != 1) {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed to parse uid "
+ "in upcall string '%s'\n", lbuf);
+ goto out;
+ }
+ } else {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed to find uid "
+ "in upcall string '%s'\n", lbuf);
+ goto out;
+ }
+
+
+ if (strcmp(mech, "krb5") == 0)
+ process_krb5_upcall(clp, uid, clp->gssd_fd);
+ else if (strcmp(mech, "spkm3") == 0)
+ process_spkm3_upcall(clp, uid, clp->gssd_fd);
+ else
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "received unknown gss mech '%s'\n", mech);
+
+out:
+ free(lbuf);
+ free(mech);
+ return;
+}
+
^ permalink raw reply related [flat|nested] 13+ messages in thread* [round2 PATCH 6/7] gssd: process target= attribute in new upcall
[not found] ` <20090520151651.2986.29621.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (4 preceding siblings ...)
2009-05-20 15:21 ` [round2 PATCH 5/7] gssd: handle new client upcall Kevin Coffman
@ 2009-05-20 15:21 ` Kevin Coffman
2009-05-20 15:21 ` [round2 PATCH 7/7] gssd: process service= " Kevin Coffman
` (2 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Kevin Coffman @ 2009-05-20 15:21 UTC (permalink / raw)
To: steved; +Cc: linux-nfs
From: Olga Kornievskaia <aglo@citi.umich.edu>
Add processing of the "target=" attribute in the new gssd upcall.
Information in this field is used to construct the gss service name
of the server for which gssd will create a context .
This, along with the next patch handling "service=", is needed
for callback security.
For Kerberos, the NFS client will use a service principal present
in its keytab during authentication of the SETCLIENT_ID operation.
When establishing the context for the callback, the gssd on the
NFS server will attempt to authenticate the callback against the
principal name used by the client.
Note: An NFS client machine must have a keytab for the callback
authentication to succeed.
Signed-off-by: Olga Kornievskaia <aglo@citi.umich.edu>
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
utils/gssd/gssd_proc.c | 26 +++++++++++++++++++++++---
1 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index f969829..3f94eaf 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -883,7 +883,7 @@ int create_auth_rpc_client(struct clnt_info *clp,
* context on behalf of the kernel
*/
static void
-process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd)
+process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname)
{
CLIENT *rpc_clnt = NULL;
AUTH *auth = NULL;
@@ -896,6 +896,12 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd)
printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
+ if (tgtname) {
+ if (clp->servicename) {
+ free(clp->servicename);
+ clp->servicename = strdup(tgtname);
+ }
+ }
token.length = 0;
token.value = NULL;
memset(&pd, 0, sizeof(struct authgss_private_data));
@@ -1054,7 +1060,7 @@ handle_krb5_upcall(struct clnt_info *clp)
return;
}
- return process_krb5_upcall(clp, uid, clp->krb5_fd);
+ return process_krb5_upcall(clp, uid, clp->krb5_fd, NULL);
}
void
@@ -1079,6 +1085,7 @@ handle_gssd_upcall(struct clnt_info *clp)
int lbuflen = 0;
char *p;
char *mech = NULL;
+ char *target = NULL;
printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
@@ -1122,9 +1129,21 @@ handle_gssd_upcall(struct clnt_info *clp)
goto out;
}
+ /* read target name */
+ if ((p = strstr(lbuf, "target=")) != NULL) {
+ target = malloc(lbuflen);
+ if (!target)
+ goto out;
+ if (sscanf(p, "target=%s", target) != 1) {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed to parse target name "
+ "in upcall string '%s'\n", lbuf);
+ goto out;
+ }
+ }
if (strcmp(mech, "krb5") == 0)
- process_krb5_upcall(clp, uid, clp->gssd_fd);
+ process_krb5_upcall(clp, uid, clp->gssd_fd, target);
else if (strcmp(mech, "spkm3") == 0)
process_spkm3_upcall(clp, uid, clp->gssd_fd);
else
@@ -1134,6 +1153,7 @@ handle_gssd_upcall(struct clnt_info *clp)
out:
free(lbuf);
free(mech);
+ free(target);
return;
}
^ permalink raw reply related [flat|nested] 13+ messages in thread* [round2 PATCH 7/7] gssd: process service= attribute in new upcall
[not found] ` <20090520151651.2986.29621.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (5 preceding siblings ...)
2009-05-20 15:21 ` [round2 PATCH 6/7] gssd: process target= attribute in new upcall Kevin Coffman
@ 2009-05-20 15:21 ` Kevin Coffman
2009-06-05 18:57 ` [round2 PATCH 0/7] nfs-utils: add support for authenticated callbacks Steve Dickson
2009-11-16 17:29 ` Steve Dickson
8 siblings, 0 replies; 13+ messages in thread
From: Kevin Coffman @ 2009-05-20 15:21 UTC (permalink / raw)
To: steved; +Cc: linux-nfs
From: Olga Kornievskaia <aglo@citi.umich.edu>
Add processing of the "service=" attribute in the new gssd upcall.
If "service" is specified, then the kernel is indicating that
we must use machine credentials for this request. (Regardless
of the uid value or the setting of root_uses_machine_creds.)
If the service value is "*", then any service name can be used.
Otherwise, it specifies the service name that should be used.
(For now, the values of service will only be "*" or "nfs".)
Restricting gssd to use "nfs" service name is needed for when
the NFS server is doing a callback to the NFS client. In this
case, the NFS server has to authenticate itself as "nfs" --
even if there are other service keys such as "host" or "root"
in the keytab.
Another case when the kernel may specify the service attribute
is when gssd is being asked to create the context for a
SETCLIENT_ID operation. In this case, machine credentials
must be used for the authentication. However, the service name
used for this case is not important.
Signed-off-by: Olga Kornievskaia <aglo@citi.umich.edu>
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
utils/gssd/gssd_proc.c | 63 +++++++++++++++++++++++++++++++++++++++++++-----
utils/gssd/krb5_util.c | 21 ++++++++++++----
utils/gssd/krb5_util.h | 3 ++
3 files changed, 75 insertions(+), 12 deletions(-)
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index 3f94eaf..97bfa3d 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -883,7 +883,8 @@ int create_auth_rpc_client(struct clnt_info *clp,
* context on behalf of the kernel
*/
static void
-process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname)
+process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
+ char *service)
{
CLIENT *rpc_clnt = NULL;
AUTH *auth = NULL;
@@ -906,7 +907,31 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname)
token.value = NULL;
memset(&pd, 0, sizeof(struct authgss_private_data));
- if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0)) {
+ /*
+ * If "service" is specified, then the kernel is indicating that
+ * we must use machine credentials for this request. (Regardless
+ * of the uid value or the setting of root_uses_machine_creds.)
+ * If the service value is "*", then any service name can be used.
+ * Otherwise, it specifies the service name that should be used.
+ * (For now, the values of service will only be "*" or "nfs".)
+ *
+ * Restricting gssd to use "nfs" service name is needed for when
+ * the NFS server is doing a callback to the NFS client. In this
+ * case, the NFS server has to authenticate itself as "nfs" --
+ * even if there are other service keys such as "host" or "root"
+ * in the keytab.
+ *
+ * Another case when the kernel may specify the service attribute
+ * is when gssd is being asked to create the context for a
+ * SETCLIENT_ID operation. In this case, machine credentials
+ * must be used for the authentication. However, the service name
+ * used for this case is not important.
+ *
+ */
+ printerr(2, "%s: service is '%s'\n", __func__,
+ service ? service : "<null>");
+ if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
+ service == NULL)) {
/* Tell krb5 gss which credentials cache to use */
for (dirname = ccachesearch; *dirname != NULL; dirname++) {
if (gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname) == 0)
@@ -917,11 +942,13 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname)
}
}
if (create_resp != 0) {
- if (uid == 0 && root_uses_machine_creds == 1) {
+
+ if (uid == 0 && (root_uses_machine_creds == 1 ||
+ service != NULL)) {
int success = 0;
gssd_refresh_krb5_machine_credential(clp->servername,
- NULL);
+ NULL, service);
/*
* Get a list of credential cache names and try each
* of them until one works or we've tried them all
@@ -1060,7 +1087,7 @@ handle_krb5_upcall(struct clnt_info *clp)
return;
}
- return process_krb5_upcall(clp, uid, clp->krb5_fd, NULL);
+ return process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
}
void
@@ -1086,6 +1113,7 @@ handle_gssd_upcall(struct clnt_info *clp)
char *p;
char *mech = NULL;
char *target = NULL;
+ char *service = NULL;
printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
@@ -1142,8 +1170,30 @@ handle_gssd_upcall(struct clnt_info *clp)
}
}
+ /*
+ * read the service name
+ *
+ * The presence of attribute "service=" indicates that machine
+ * credentials should be used for this request. If the value
+ * is "*", then any machine credentials available can be used.
+ * If the value is anything else, then machine credentials for
+ * the specified service name (always "nfs" for now) should be
+ * used.
+ */
+ if ((p = strstr(lbuf, "service=")) != NULL) {
+ service = malloc(lbuflen);
+ if (!service)
+ goto out;
+ if (sscanf(p, "service=%s", service) != 1) {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed to parse service type "
+ "in upcall string '%s'\n", lbuf);
+ goto out;
+ }
+ }
+
if (strcmp(mech, "krb5") == 0)
- process_krb5_upcall(clp, uid, clp->gssd_fd, target);
+ process_krb5_upcall(clp, uid, clp->gssd_fd, target, service);
else if (strcmp(mech, "spkm3") == 0)
process_spkm3_upcall(clp, uid, clp->gssd_fd);
else
@@ -1154,6 +1204,7 @@ out:
free(lbuf);
free(mech);
free(target);
+ free(service);
return;
}
diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
index 3009cc5..ef12ec5 100644
--- a/utils/gssd/krb5_util.c
+++ b/utils/gssd/krb5_util.c
@@ -796,10 +796,9 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt,
*/
static int
find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname,
- krb5_keytab_entry *kte)
+ krb5_keytab_entry *kte, const char **svcnames)
{
krb5_error_code code;
- const char *svcnames[] = { "root", "nfs", "host", NULL };
char **realmnames = NULL;
char myhostname[NI_MAXHOST], targethostname[NI_MAXHOST];
int i, j, retval;
@@ -1095,7 +1094,8 @@ gssd_get_krb5_machine_cred_list(char ***list)
for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) {
if (ple->ccname) {
/* Make sure cred is up-to-date before returning it */
- retval = gssd_refresh_krb5_machine_credential(NULL, ple);
+ retval = gssd_refresh_krb5_machine_credential(NULL, ple,
+ NULL);
if (retval)
continue;
if (i + 1 > listsize) {
@@ -1185,13 +1185,24 @@ gssd_destroy_krb5_machine_creds(void)
*/
int
gssd_refresh_krb5_machine_credential(char *hostname,
- struct gssd_k5_kt_princ *ple)
+ struct gssd_k5_kt_princ *ple,
+ char *service)
{
krb5_error_code code = 0;
krb5_context context;
krb5_keytab kt = NULL;;
int retval = 0;
char *k5err = NULL;
+ const char *svcnames[4] = { "root", "nfs", "host", NULL };
+
+ /*
+ * If a specific service name was specified, use it.
+ * Otherwise, use the default list.
+ */
+ if (service != NULL && strcmp(service, "*") != 0) {
+ svcnames[0] = service;
+ svcnames[1] = NULL;
+ }
if (hostname == NULL && ple == NULL)
return EINVAL;
@@ -1215,7 +1226,7 @@ gssd_refresh_krb5_machine_credential(char *hostname,
if (ple == NULL) {
krb5_keytab_entry kte;
- code = find_keytab_entry(context, kt, hostname, &kte);
+ code = find_keytab_entry(context, kt, hostname, &kte, svcnames);
if (code) {
printerr(0, "ERROR: %s: no usable keytab entry found "
"in keytab %s for connection with host %s\n",
diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h
index 3d39300..b696ea4 100644
--- a/utils/gssd/krb5_util.h
+++ b/utils/gssd/krb5_util.h
@@ -30,7 +30,8 @@ void gssd_free_krb5_machine_cred_list(char **list);
void gssd_setup_krb5_machine_gss_ccache(char *servername);
void gssd_destroy_krb5_machine_creds(void);
int gssd_refresh_krb5_machine_credential(char *hostname,
- struct gssd_k5_kt_princ *ple);
+ struct gssd_k5_kt_princ *ple,
+ char *service);
char *gssd_k5_err_msg(krb5_context context, krb5_error_code code);
void gssd_k5_get_default_realm(char **def_realm);
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [round2 PATCH 0/7] nfs-utils: add support for authenticated callbacks
[not found] ` <20090520151651.2986.29621.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (6 preceding siblings ...)
2009-05-20 15:21 ` [round2 PATCH 7/7] gssd: process service= " Kevin Coffman
@ 2009-06-05 18:57 ` Steve Dickson
[not found] ` <4A296A95.3070208-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
2009-11-16 17:29 ` Steve Dickson
8 siblings, 1 reply; 13+ messages in thread
From: Steve Dickson @ 2009-06-05 18:57 UTC (permalink / raw)
To: Kevin Coffman; +Cc: linux-nfs
Kevin Coffman wrote:
> Hi Steve,
>
> This series adds support to gssd and svcgssd to support
> authenticated callbacks.
>
> 1) adds the name the client used when authenticating to the
> svcgssd downcall information. This is used by nfsd to determine
> the target name when initiating the callback.
>
> 2) splits out the processing of update_client_list() to accomodate
> a new upcall pipe added in the next patch.
>
> 3) changes gssd to process all rpc_pipefs directories (this patch is
> changed from the first round to process all directories rather than
> special-casing directories)
>
> 4) a debugging aid to distinquish which upcall is being processed
>
> 6) adds support for handling the "target=" attribute in the new upcall
>
> 7) adds support for handling the "service=" attribute in the new upcall
>
> NOTE: For authenticated callbacks to work, an NFS client or an
> NFS server must be running both rpcgssd _and_ rpcsvcgssd.
> This will require a configuration change.
Question, How are authenticated callbacks are not configured?
Also do both daemons have to be running if authenticated
callbacks are not configured?
steved.
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [round2 PATCH 0/7] nfs-utils: add support for authenticated callbacks
[not found] ` <20090520151651.2986.29621.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (7 preceding siblings ...)
2009-06-05 18:57 ` [round2 PATCH 0/7] nfs-utils: add support for authenticated callbacks Steve Dickson
@ 2009-11-16 17:29 ` Steve Dickson
8 siblings, 0 replies; 13+ messages in thread
From: Steve Dickson @ 2009-11-16 17:29 UTC (permalink / raw)
To: Kevin Coffman; +Cc: linux-nfs
On 05/20/2009 11:20 AM, Kevin Coffman wrote:
> Hi Steve,
>
> This series adds support to gssd and svcgssd to support
> authenticated callbacks.
>
> 1) adds the name the client used when authenticating to the
> svcgssd downcall information. This is used by nfsd to determine
> the target name when initiating the callback.
>
> 2) splits out the processing of update_client_list() to accomodate
> a new upcall pipe added in the next patch.
>
> 3) changes gssd to process all rpc_pipefs directories (this patch is
> changed from the first round to process all directories rather than
> special-casing directories)
>
> 4) a debugging aid to distinquish which upcall is being processed
>
> 6) adds support for handling the "target=" attribute in the new upcall
>
> 7) adds support for handling the "service=" attribute in the new upcall
>
> NOTE: For authenticated callbacks to work, an NFS client or an
> NFS server must be running both rpcgssd _and_ rpcsvcgssd.
> This will require a configuration change.
>
> A future patch is planned to combine gssd and svcgssd into
> a single daemon to make configuration easier. However, there
> are some architectural issues that must be resolved first.
>
> ---
>
> Kevin Coffman (1):
> gssd: add upcall support for callback authentication
>
> Olga Kornievskaia (6):
> gssd: process service= attribute in new upcall
> gssd: process target= attribute in new upcall
> gssd: handle new client upcall
> gssd: print full client directory being handled
> gssd: refactor update_client_list()
> svcgssd: add client's principal name to downcall information
>
>
> utils/gssd/gssd.c | 6 -
> utils/gssd/gssd.h | 12 +
> utils/gssd/gssd_main_loop.c | 102 +++++++++++-
> utils/gssd/gssd_proc.c | 365 +++++++++++++++++++++++++++++++++++--------
> utils/gssd/krb5_util.c | 21 ++
> utils/gssd/krb5_util.h | 3
> utils/gssd/svcgssd_proc.c | 94 ++++++++++-
> 7 files changed, 505 insertions(+), 98 deletions(-)
>
Sorry for taking so long to get to this... I did some quick regression
testing and did not see any problems... but it not clear I actually
tested this new functionality....
I'm going to go ahead and commit this, but if you could supply me
with some tests that explicitly test this new functionality would
be appreciated...
steved.
^ permalink raw reply [flat|nested] 13+ messages in thread