]> git.decadent.org.uk Git - nfs-utils.git/commitdiff
gssd: process service= attribute in new upcall nfs-utils-1-2-2-rc1
authorOlga Kornievskaia <aglo@citi.umich.edu>
Mon, 16 Nov 2009 14:44:03 +0000 (09:44 -0500)
committerSteve Dickson <steved@redhat.com>
Mon, 16 Nov 2009 14:44:03 +0000 (09:44 -0500)
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>
Signed-off-by: Steve Dickson <steved@redhat.com>
utils/gssd/gssd_proc.c
utils/gssd/krb5_util.c
utils/gssd/krb5_util.h

index 799a207c46b45de62a7e7139b6a3c059ad888e6d..33a31c3c3c5b1c018ea8a7408bba34863569053b 100644 (file)
@@ -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,12 +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 nocache = 0;
                        int success = 0;
                        do {
                                gssd_refresh_krb5_machine_credential(clp->servername,
-                                                                    NULL, nocache);
+                                                                    NULL, service);
                                /*
                                 * Get a list of credential cache names and try each
                                 * of them until one works or we've tried them all
@@ -1066,7 +1092,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
@@ -1092,6 +1118,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);
 
@@ -1148,8 +1175,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
@@ -1160,6 +1209,7 @@ out:
        free(lbuf);
        free(mech);
        free(target);
+       free(service);
        return; 
 }
 
index 78e9775de180b3bb5776b91ebb31a860c9992f58..c3c131ba7503ce51f9ae97453e08d09325fb060c 100644 (file)
@@ -797,10 +797,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;
@@ -1096,7 +1095,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, 0);
+                       retval = gssd_refresh_krb5_machine_credential(NULL, ple,
+                               NULL);
                        if (retval)
                                continue;
                        if (i + 1 > listsize) {
@@ -1186,14 +1186,24 @@ gssd_destroy_krb5_machine_creds(void)
  */
 int
 gssd_refresh_krb5_machine_credential(char *hostname,
-                                    struct gssd_k5_kt_princ *ple, int nocache)
+                                    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;
 
@@ -1216,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",
@@ -1241,7 +1251,7 @@ gssd_refresh_krb5_machine_credential(char *hostname,
                        goto out;
                }
        }
-       retval = gssd_get_single_krb5_cred(context, kt, ple, nocache);
+       retval = gssd_get_single_krb5_cred(context, kt, ple, 0);
 out:
        if (kt)
                krb5_kt_close(context, kt);
index 4b6b28119e5b0ce42518fc404221bc2e9736ba89..4602cc31d433561317ff3bcdee796d2f312e2a6b 100644 (file)
@@ -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, int nocache);
+                                         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);