]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/gssd/gssd_proc.c
gssd_setup_krb5_user_gss_ccache must return an error if no usable cache is
[nfs-utils.git] / utils / gssd / gssd_proc.c
index 04de4e676683c96010be6c6ebc0e6e1884b7d7cf..a145081e8ae234627ad2b98c1db78fbd8b25061d 100644 (file)
  *     with an index into pollarray[], and other basic data about that client.
  *
  * Directory structure: created by the kernel nfs client
- *      /pipefsdir/clntXX             : one per rpc_clnt struct in the kernel
- *      /pipefsdir/clntXX/krb5        : read uid for which kernel wants
- *                                      a context, write the resulting context
- *      /pipefsdir/clntXX/info        : stores info such as server name
+ *      {pipefs_nfsdir}/clntXX             : one per rpc_clnt struct in the kernel
+ *      {pipefs_nfsdir}/clntXX/krb5        : read uid for which kernel wants
+ *                                         a context, write the resulting context
+ *      {pipefs_nfsdir}/clntXX/info        : stores info such as server name
  *
  * Algorithm:
- *      Poll all /pipefsdir/clntXX/krb5 files.  When ready, data read
+ *      Poll all {pipefs_nfsdir}/clntXX/krb5 files.  When ready, data read
  *      is a uid; 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 pipefsdir/ or in an of the clntXX directories,
- *      and rescan the whole pipefsdir when this happens.
+ *      created or destroyed in {pipefs_nfsdir} or in an of the clntXX directories,
+ *      and rescan the whole {pipefs_nfsdir} when this happens.
  */
 
 struct pollfd * pollarray;
@@ -102,7 +102,7 @@ int pollsize;  /* the size of pollaray (in pollfd's) */
 /* XXX buffer problems: */
 static int
 read_service_info(char *info_file_name, char **servicename, char **servername,
-                 int *prog, int *vers, char **protocol) {
+                 int *prog, int *vers, char **protocol, int *port) {
 #define INFOBUFLEN 256
        char            buf[INFOBUFLEN];
        static char     dummy[128];
@@ -112,6 +112,8 @@ read_service_info(char *info_file_name, char **servicename, char **servername,
        char            program[16];
        char            version[16];
        char            protoname[16];
+       char            cb_port[128];
+       char            *p;
        in_addr_t       inaddr;
        int             fd = -1;
        struct hostent  *ent = NULL;
@@ -143,6 +145,10 @@ read_service_info(char *info_file_name, char **servicename, char **servername,
                goto fail;
        }
 
+       cb_port[0] = '\0';
+       if ((p = strstr(buf, "port")) != NULL)
+               sscanf(p, "port: %127s\n", cb_port);
+
        /* check service, program, and version */
        if(memcmp(service, "nfs", 3)) return -1;
        *prog = atoi(program + 1); /* skip open paren */
@@ -163,6 +169,8 @@ read_service_info(char *info_file_name, char **servicename, char **servername,
        if (!(*servicename = calloc(strlen(buf) + 1, 1)))
                goto fail;
        memcpy(*servicename, buf, strlen(buf));
+       if (cb_port[0] != '\0')
+               *port = atoi(cb_port);
 
        if (!(*protocol = strdup(protoname)))
                goto fail;
@@ -238,7 +246,7 @@ process_clnt_dir_files(struct clnt_info * clp)
        if ((clp->servicename == NULL) &&
             read_service_info(info_file_name, &clp->servicename,
                                &clp->servername, &clp->prog, &clp->vers,
-                               &clp->protocol))
+                               &clp->protocol, &clp->port))
                return -1;
        return 0;
 }
@@ -389,16 +397,16 @@ update_client_list(void)
        struct dirent **namelist;
        int i, j;
 
-       if (chdir(pipefsdir) < 0) {
+       if (chdir(pipefs_nfsdir) < 0) {
                printerr(0, "ERROR: can't chdir to %s: %s\n",
-                        pipefsdir, strerror(errno));
+                        pipefs_nfsdir, strerror(errno));
                return -1;
        }
 
-       j = scandir(pipefsdir, &namelist, NULL, alphasort);
+       j = scandir(pipefs_nfsdir, &namelist, NULL, alphasort);
        if (j < 0) {
                printerr(0, "ERROR: can't scandir %s: %s\n",
-                        pipefsdir, strerror(errno));
+                        pipefs_nfsdir, strerror(errno));
                return -1;
        }
        update_old_clients(namelist, j);
@@ -464,7 +472,7 @@ do_error_downcall(int k5_fd, uid_t uid, int err)
        if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
        return 0;
 out_err:
-       printerr(0, "Failed to write error downcall!\n");
+       printerr(1, "Failed to write error downcall!\n");
        return -1;
 }
 
@@ -555,7 +563,7 @@ int create_auth_rpc_client(struct clnt_info *clp,
                ai_hints.ai_protocol = IPPROTO_UDP;
        } else {
                printerr(0, "WARNING: unrecognized protocol, '%s', requested "
-                        "for connection to server %s for user with uid %d",
+                        "for connection to server %s for user with uid %d\n",
                         clp->protocol, clp->servername, uid);
                goto out_fail;
        }
@@ -563,12 +571,12 @@ int create_auth_rpc_client(struct clnt_info *clp,
        /* extract the service name from clp->servicename */
        if ((at_sign = strchr(clp->servicename, '@')) == NULL) {
                printerr(0, "WARNING: servicename (%s) not formatted as "
-                       "expected with service@host", clp->servicename);
+                       "expected with service@host\n", clp->servicename);
                goto out_fail;
        }
        if ((at_sign - clp->servicename) >= sizeof(service)) {
                printerr(0, "WARNING: service portion of servicename (%s) "
-                       "is too long!", clp->servicename);
+                       "is too long!\n", clp->servicename);
                goto out_fail;
        }
        strncpy(service, clp->servicename, at_sign - clp->servicename);
@@ -577,16 +585,18 @@ int create_auth_rpc_client(struct clnt_info *clp,
        errcode = getaddrinfo(clp->servername, service, &ai_hints, &a);
        if (errcode) {
                printerr(0, "WARNING: Error from getaddrinfo for server "
-                        "'%s': %s", clp->servername, gai_strerror(errcode));
+                        "'%s': %s\n", clp->servername, gai_strerror(errcode));
                goto out_fail;
        }
 
        if (a == NULL) {
                printerr(0, "WARNING: No address information found for "
-                        "connection to server %s for user with uid %d",
+                        "connection to server %s for user with uid %d\n",
                         clp->servername, uid);
                goto out_fail;
        }
+       if (clp->port)
+               ((struct sockaddr_in *)a->ai_addr)->sin_port = htons(clp->port);
        if (a->ai_protocol == IPPROTO_TCP) {
                if ((rpc_clnt = clnttcp_create(
                                        (struct sockaddr_in *) a->ai_addr,
@@ -617,7 +627,7 @@ int create_auth_rpc_client(struct clnt_info *clp,
        } else {
                /* Shouldn't happen! */
                printerr(0, "ERROR: requested protocol '%s', but "
-                        "got addrinfo with protocol %d",
+                        "got addrinfo with protocol %d\n",
                         clp->protocol, a->ai_protocol);
                goto out_fail;
        }
@@ -675,6 +685,7 @@ handle_krb5_upcall(struct clnt_info *clp)
        gss_buffer_desc         token;
        char                    **credlist = NULL;
        char                    **ccname;
+       char                    **dirname;
        int                     create_resp = -1;
 
        printerr(1, "handling krb5 upcall\n");
@@ -691,23 +702,28 @@ handle_krb5_upcall(struct clnt_info *clp)
 
        if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0)) {
                /* Tell krb5 gss which credentials cache to use */
-               gssd_setup_krb5_user_gss_ccache(uid, clp->servername);
-
-               create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
-                                                    AUTHTYPE_KRB5);
+               for (dirname = ccachesearch; *dirname != NULL; dirname++) {
+                       if (gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname) == 0)
+                               create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
+                                                            AUTHTYPE_KRB5);
+                       if (create_resp == 0)
+                               break;
+               }
        }
        if (create_resp != 0) {
                if (uid == 0 && root_uses_machine_creds == 1) {
                        int success = 0;
 
+                       gssd_refresh_krb5_machine_credential(clp->servername,
+                                                            NULL);
                        /*
                         * Get a list of credential cache names and try each
                         * of them until one works or we've tried them all
                         */
                        if (gssd_get_krb5_machine_cred_list(&credlist)) {
-                               printerr(0, "WARNING: Failed to obtain machine "
-                                        "credentials for connection to "
-                                        "server %s\n", clp->servername);
+                               printerr(0, "ERROR: No credentials found "
+                                        "for connection to server %s\n",
+                                        clp->servername);
                                        goto out_return_error;
                        }
                        for (ccname = credlist; ccname && *ccname; ccname++) {