]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/gssd/gssd_proc.c
rpc.gssd: Squelch compiler error
[nfs-utils.git] / utils / gssd / gssd_proc.c
index 795e06c343e4809bbaddf6d98f12a2d698a779ac..ec251fa0b6069c8bcb42dafdcef89f73afd8e9d2 100644 (file)
 
 struct pollfd * pollarray;
 
-int pollsize;  /* the size of pollaray (in pollfd's) */
+unsigned long pollsize;  /* the size of pollaray (in pollfd's) */
 
 /*
  * convert a presentation address string to a sockaddr_storage struct. Returns
@@ -299,15 +299,11 @@ destroy_client(struct clnt_info *clp)
        if (clp->krb5_poll_index != -1)
                memset(&pollarray[clp->krb5_poll_index], 0,
                                        sizeof(struct pollfd));
-       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);
@@ -327,10 +323,8 @@ insert_new_clnt(void)
                goto out;
        }
        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;
 
@@ -346,6 +340,25 @@ process_clnt_dir_files(struct clnt_info * clp)
        char    gname[PATH_MAX];
        char    info_file_name[PATH_MAX];
 
+       if (clp->gssd_close_me) {
+               printerr(2, "Closing 'gssd' pipe for %s\n", clp->dirname);
+               close(clp->gssd_fd);
+               memset(&pollarray[clp->gssd_poll_index], 0,
+                       sizeof(struct pollfd));
+               clp->gssd_fd = -1;
+               clp->gssd_poll_index = -1;
+               clp->gssd_close_me = 0;
+       }
+       if (clp->krb5_close_me) {
+               printerr(2, "Closing 'krb5' pipe for %s\n", clp->dirname);
+               close(clp->krb5_fd);
+               memset(&pollarray[clp->krb5_poll_index], 0,
+                       sizeof(struct pollfd));
+               clp->krb5_fd = -1;
+               clp->krb5_poll_index = -1;
+               clp->krb5_close_me = 0;
+       }
+
        if (clp->gssd_fd == -1) {
                snprintf(gname, sizeof(gname), "%s/gssd", clp->dirname);
                clp->gssd_fd = open(gname, O_RDWR);
@@ -355,30 +368,22 @@ process_clnt_dir_files(struct clnt_info * clp)
                        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) {
+               if (clp->krb5_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) &&
-                       (clp->gssd_fd == -1))
+       if ((clp->krb5_fd == -1) && (clp->gssd_fd == -1))
                return -1;
        snprintf(info_file_name, sizeof(info_file_name), "%s/info",
                        clp->dirname);
@@ -431,15 +436,6 @@ insert_clnt_poll(struct clnt_info *clp)
                pollarray[clp->krb5_poll_index].events |= POLLIN;
        }
 
-       if ((clp->spkm3_fd != -1) && (clp->spkm3_poll_index == -1)) {
-               if (get_poll_index(&clp->spkm3_poll_index)) {
-                       printerr(0, "ERROR: Too many spkm3 clients\n");
-                       return -1;
-               }
-               pollarray[clp->spkm3_poll_index].fd = clp->spkm3_fd;
-               pollarray[clp->spkm3_poll_index].events |= POLLIN;
-       }
-
        return 0;
 }
 
@@ -600,21 +596,85 @@ update_client_list(void)
        return retval;
 }
 
+/* Encryption types supported by the kernel rpcsec_gss code */
+int num_krb5_enctypes = 0;
+krb5_enctype *krb5_enctypes = NULL;
+
+/*
+ * Parse the supported encryption type information
+ */
+static int
+parse_enctypes(char *enctypes)
+{
+       int n = 0;
+       char *curr, *comma;
+       int i;
+       static char *cached_types;
+
+       if (cached_types && strcmp(cached_types, enctypes) == 0)
+               return 0;
+       free(cached_types);
+
+       if (krb5_enctypes != NULL) {
+               free(krb5_enctypes);
+               krb5_enctypes = NULL;
+               num_krb5_enctypes = 0;
+       }
+
+       /* count the number of commas */
+       for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
+               comma = strchr(curr, ',');
+               if (comma != NULL)
+                       n++;
+               else
+                       break;
+       }
+       /* If no more commas and we're not at the end, there's one more value */
+       if (*curr != '\0')
+               n++;
+
+       /* Empty string, return an error */
+       if (n == 0)
+               return ENOENT;
+
+       /* Allocate space for enctypes array */
+       if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
+               return ENOMEM;
+       }
+
+       /* Now parse each value into the array */
+       for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) {
+               krb5_enctypes[i++] = atoi(curr);
+               comma = strchr(curr, ',');
+               if (comma == NULL)
+                       break;
+       }
+
+       num_krb5_enctypes = n;
+       if ((cached_types = malloc(strlen(enctypes)+1)))
+               strcpy(cached_types, enctypes);
+
+       return 0;
+}
+
 static int
 do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
-           gss_buffer_desc *context_token)
+           gss_buffer_desc *context_token, OM_uint32 lifetime_rec)
 {
        char    *buf = NULL, *p = NULL, *end = NULL;
        unsigned int timeout = context_timeout;
        unsigned int buf_size = 0;
 
-       printerr(1, "doing downcall\n");
+       printerr(1, "doing downcall lifetime_rec %u\n", lifetime_rec);
        buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) +
                sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length +
                sizeof(context_token->length) + context_token->length;
        p = buf = malloc(buf_size);
        end = buf + buf_size;
 
+       /* context_timeout set by -t option overrides context lifetime */
+       if (timeout == 0)
+               timeout = lifetime_rec;
        if (WRITE_BYTES(&p, end, uid)) goto out_err;
        if (WRITE_BYTES(&p, end, timeout)) goto out_err;
        if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err;
@@ -742,11 +802,12 @@ set_port:
  * Create an RPC connection and establish an authenticated
  * gss context with a server.
  */
-int create_auth_rpc_client(struct clnt_info *clp,
-                          CLIENT **clnt_return,
-                          AUTH **auth_return,
-                          uid_t uid,
-                          int authtype)
+static int
+create_auth_rpc_client(struct clnt_info *clp,
+                      CLIENT **clnt_return,
+                      AUTH **auth_return,
+                      uid_t uid,
+                      int authtype)
 {
        CLIENT                  *rpc_clnt = NULL;
        struct rpc_gss_sec      sec;
@@ -778,13 +839,6 @@ int create_auth_rpc_client(struct clnt_info *clp,
                sec.mech = (gss_OID)&krb5oid;
                sec.req_flags = GSS_C_MUTUAL_FLAG;
        }
-       else if (authtype == AUTHTYPE_SPKM3) {
-               sec.mech = (gss_OID)&spkm3oid;
-               /* XXX sec.req_flags = GSS_C_ANON_FLAG;
-                * Need a way to switch....
-                */
-               sec.req_flags = GSS_C_MUTUAL_FLAG;
-       }
        else {
                printerr(0, "ERROR: Invalid authentication type (%d) "
                        "in create_auth_rpc_client\n", authtype);
@@ -798,7 +852,7 @@ int create_auth_rpc_client(struct clnt_info *clp,
                 * Do this before creating rpc connection since we won't need
                 * rpc connection if it fails!
                 */
-               if (limit_krb5_enctypes(&sec, uid)) {
+               if (limit_krb5_enctypes(&sec)) {
                        printerr(1, "WARNING: Failed while limiting krb5 "
                                    "encryption types for user with uid %d\n",
                                 uid);
@@ -858,9 +912,8 @@ int create_auth_rpc_client(struct clnt_info *clp,
        auth = authgss_create_default(rpc_clnt, clp->servicename, &sec);
        if (!auth) {
                /* Our caller should print appropriate message */
-               printerr(2, "WARNING: Failed to create %s context for "
+               printerr(2, "WARNING: Failed to create krb5 context for "
                            "user with uid %d for server %s\n",
-                       (authtype == AUTHTYPE_KRB5 ? "krb5":"spkm3"),
                         uid, clp->servername);
                goto out_fail;
        }
@@ -875,7 +928,7 @@ int create_auth_rpc_client(struct clnt_info *clp,
        if (sec.cred != GSS_C_NO_CREDENTIAL)
                gss_release_cred(&min_stat, &sec.cred);
        /* Restore euid to original value */
-       if ((save_uid != -1) && (setfsuid(save_uid) != uid)) {
+       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);
        }
@@ -904,6 +957,8 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
        char                    **ccname;
        char                    **dirname;
        int                     create_resp = -1;
+       int                     err, downcall_err = -EACCES;
+       OM_uint32               maj_stat, min_stat, lifetime_rec;
 
        printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
 
@@ -944,7 +999,10 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
                                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)
+                       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, &rpc_clnt, &auth, uid,
                                                             AUTHTYPE_KRB5);
                        if (create_resp == 0)
@@ -1011,6 +1069,15 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
                goto out_return_error;
        }
 
+       /* Grab the context lifetime to pass to the kernel. lifetime_rec
+        * is set to zero on error */
+       maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, NULL,
+                                      &lifetime_rec, NULL, NULL, NULL, NULL);
+
+       if (maj_stat)
+               printerr(1, "WARNING: Failed to inquire context for lifetme "
+                           "maj_stat %u\n", maj_stat);
+
        if (serialize_context_for_kernel(pd.pd_ctx, &token, &krb5oid, NULL)) {
                printerr(0, "WARNING: Failed to serialize krb5 context for "
                            "user with uid %d for server %s\n",
@@ -1018,7 +1085,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
                goto out_return_error;
        }
 
-       do_downcall(fd, uid, &pd, &token);
+       do_downcall(fd, uid, &pd, &token, lifetime_rec);
 
 out:
        if (token.value)
@@ -1034,60 +1101,7 @@ out:
        return;
 
 out_return_error:
-       do_error_downcall(fd, uid, -1);
-       goto out;
-}
-
-/*
- * this code uses the userland rpcsec gss library to create an spkm3
- * context on behalf of the kernel
- */
-static void
-process_spkm3_upcall(struct clnt_info *clp, uid_t uid, int fd)
-{
-       CLIENT                  *rpc_clnt = NULL;
-       AUTH                    *auth = NULL;
-       struct authgss_private_data pd;
-       gss_buffer_desc         token;
-
-       printerr(2, "handling spkm3 upcall (%s)\n", clp->dirname);
-
-       token.length = 0;
-       token.value = NULL;
-
-       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);
-               goto out_return_error;
-       }
-
-       if (!authgss_get_private_data(auth, &pd)) {
-               printerr(0, "WARNING: Failed to obtain authentication "
-                           "data for user with uid %d for server %s\n",
-                        uid, clp->servername);
-               goto out_return_error;
-       }
-
-       if (serialize_context_for_kernel(pd.pd_ctx, &token, &spkm3oid, NULL)) {
-               printerr(0, "WARNING: Failed to serialize spkm3 context for "
-                           "user with uid %d for server\n",
-                        uid, clp->servername);
-               goto out_return_error;
-       }
-
-       do_downcall(fd, uid, &pd, &token);
-
-out:
-       if (token.value)
-               free(token.value);
-       if (auth)
-               AUTH_DESTROY(auth);
-       if (rpc_clnt)
-               clnt_destroy(rpc_clnt);
-       return;
-
-out_return_error:
-       do_error_downcall(fd, uid, -1);
+       do_error_downcall(fd, uid, downcall_err);
        goto out;
 }
 
@@ -1096,27 +1110,13 @@ handle_krb5_upcall(struct clnt_info *clp)
 {
        uid_t                   uid;
 
-       if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
+       if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)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, NULL, NULL);
-}
-
-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);
+       process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
 }
 
 void
@@ -1129,6 +1129,7 @@ handle_gssd_upcall(struct clnt_info *clp)
        char                    *mech = NULL;
        char                    *target = NULL;
        char                    *service = NULL;
+       char                    *enctypes = NULL;
 
        printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
 
@@ -1172,6 +1173,23 @@ handle_gssd_upcall(struct clnt_info *clp)
                goto out;
        }
 
+       /* read supported encryption types if supplied */
+       if ((p = strstr(lbuf, "enctypes=")) != NULL) {
+               enctypes = malloc(lbuflen);
+               if (!enctypes)
+                       goto out;
+               if (sscanf(p, "enctypes=%s", enctypes) != 1) {
+                       printerr(0, "WARNING: handle_gssd_upcall: "
+                                   "failed to parse encryption types "
+                                   "in upcall string '%s'\n", lbuf);
+                       goto out;
+               }
+               if (parse_enctypes(enctypes) != 0) {
+                       printerr(0, "WARNING: handle_gssd_upcall: "
+                               "parsing encryption types failed: errno %d\n", errno);
+               }
+       }
+
        /* read target name */
        if ((p = strstr(lbuf, "target=")) != NULL) {
                target = malloc(lbuflen);
@@ -1209,8 +1227,6 @@ handle_gssd_upcall(struct clnt_info *clp)
 
        if (strcmp(mech, "krb5") == 0)
                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
                printerr(0, "WARNING: handle_gssd_upcall: "
                            "received unknown gss mech '%s'\n", mech);
@@ -1218,6 +1234,7 @@ handle_gssd_upcall(struct clnt_info *clp)
 out:
        free(lbuf);
        free(mech);
+       free(enctypes);
        free(target);
        free(service);
        return;