4 Copyright (c) 2000-2004 The Regents of the University of Michigan.
7 Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
8 Copyright (c) 2001 Andy Adamson <andros@UMICH.EDU>.
9 Copyright (c) 2002 Marius Aamodt Eriksen <marius@UMICH.EDU>.
10 Copyright (c) 2002 Bruce Fields <bfields@UMICH.EDU>
11 Copyright (c) 2004 Kevin Coffman <kwc@umich.edu>
12 All rights reserved, all wrongs reversed.
14 Redistribution and use in source and binary forms, with or without
15 modification, are permitted provided that the following conditions
18 1. Redistributions of source code must retain the above copyright
19 notice, this list of conditions and the following disclaimer.
20 2. Redistributions in binary form must reproduce the above copyright
21 notice, this list of conditions and the following disclaimer in the
22 documentation and/or other materials provided with the distribution.
23 3. Neither the name of the University nor the names of its
24 contributors may be used to endorse or promote products derived
25 from this software without specific prior written permission.
27 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
28 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
29 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
30 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
34 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 #endif /* HAVE_CONFIG_H */
49 #include <sys/param.h>
52 #include <sys/socket.h>
53 #include <arpa/inet.h>
54 #include <sys/fsuid.h>
67 #include <gssapi/gssapi.h>
73 #include "krb5_util.h"
80 * array of struct pollfd suitable to pass to poll. initialized to
81 * zero - a zero struct is ignored by poll() because the events mask is 0.
84 * linked list of struct clnt_info which associates a clntXXX directory
85 * with an index into pollarray[], and other basic data about that client.
87 * Directory structure: created by the kernel
88 * {rpc_pipefs}/{dir}/clntXX : one per rpc_clnt struct in the kernel
89 * {rpc_pipefs}/{dir}/clntXX/krb5 : read uid for which kernel wants
90 * a context, write the resulting context
91 * {rpc_pipefs}/{dir}/clntXX/info : stores info such as server name
92 * {rpc_pipefs}/{dir}/clntXX/gssd : pipe for all gss mechanisms using
93 * a text-based string of parameters
96 * Poll all {rpc_pipefs}/{dir}/clntXX/YYYY files. When data is ready,
97 * read and process; performs rpcsec_gss context initialization protocol to
98 * get a cred for that user. Writes result to corresponding krb5 file
99 * in a form the kernel code will understand.
100 * In addition, we make sure we are notified whenever anything is
101 * created or destroyed in {rpc_pipefs} or in any of the clntXX directories,
102 * and rescan the whole {rpc_pipefs} when this happens.
105 struct pollfd * pollarray;
107 unsigned long pollsize; /* the size of pollaray (in pollfd's) */
110 * convert a presentation address string to a sockaddr_storage struct. Returns
111 * true on success or false on failure.
113 * Note that we do not populate the sin6_scope_id field here for IPv6 addrs.
114 * gssd nececessarily relies on hostname resolution and DNS AAAA records
115 * do not generally contain scope-id's. This means that GSSAPI auth really
116 * can't work with IPv6 link-local addresses.
118 * We *could* consider changing this if we did something like adopt the
119 * Microsoft "standard" of using the ipv6-literal.net domainname, but it's
120 * not really feasible at present.
123 addrstr_to_sockaddr(struct sockaddr *sa, const char *node, const char *port)
126 struct addrinfo *res;
127 struct addrinfo hints = { .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV };
129 #ifndef IPV6_SUPPORTED
130 hints.ai_family = AF_INET;
131 #endif /* IPV6_SUPPORTED */
133 rc = getaddrinfo(node, port, &hints, &res);
135 printerr(0, "ERROR: unable to convert %s|%s to sockaddr: %s\n",
136 node, port, rc == EAI_SYSTEM ? strerror(errno) :
141 #ifdef IPV6_SUPPORTED
143 * getnameinfo ignores the scopeid. If the address turns out to have
144 * a non-zero scopeid, we can't use it -- the resolved host might be
145 * completely different from the one intended.
147 if (res->ai_addr->sa_family == AF_INET6) {
148 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)res->ai_addr;
149 if (sin6->sin6_scope_id) {
150 printerr(0, "ERROR: address %s has non-zero "
151 "sin6_scope_id!\n", node);
156 #endif /* IPV6_SUPPORTED */
158 memcpy(sa, res->ai_addr, res->ai_addrlen);
164 * convert a sockaddr to a hostname
167 sockaddr_to_hostname(const struct sockaddr *sa, const char *addr)
172 char hbuf[NI_MAXHOST];
174 switch (sa->sa_family) {
176 addrlen = sizeof(struct sockaddr_in);
178 #ifdef IPV6_SUPPORTED
180 addrlen = sizeof(struct sockaddr_in6);
182 #endif /* IPV6_SUPPORTED */
184 printerr(0, "ERROR: unrecognized addr family %d\n",
189 err = getnameinfo(sa, addrlen, hbuf, sizeof(hbuf), NULL, 0,
192 printerr(0, "ERROR: unable to resolve %s to hostname: %s\n",
193 addr, err == EAI_SYSTEM ? strerror(err) :
198 hostname = strdup(hbuf);
203 /* XXX buffer problems: */
205 read_service_info(char *info_file_name, char **servicename, char **servername,
206 int *prog, int *vers, char **protocol,
207 struct sockaddr *addr) {
208 #define INFOBUFLEN 256
209 char buf[INFOBUFLEN + 1];
210 static char dummy[128];
212 static char service[128];
213 static char address[128];
222 *servicename = *servername = *protocol = NULL;
224 if ((fd = open(info_file_name, O_RDONLY)) == -1) {
225 printerr(0, "ERROR: can't open %s: %s\n", info_file_name,
229 if ((nbytes = read(fd, buf, INFOBUFLEN)) == -1)
234 numfields = sscanf(buf,"RPC server: %127s\n"
235 "service: %127s %15s version %15s\n"
239 service, program, version,
243 if (numfields == 5) {
244 strcpy(protoname, "tcp");
245 } else if (numfields != 6) {
250 if ((p = strstr(buf, "port")) != NULL)
251 sscanf(p, "port: %127s\n", port);
253 /* check service, program, and version */
254 if (memcmp(service, "nfs", 3) != 0)
256 *prog = atoi(program + 1); /* skip open paren */
257 *vers = atoi(version);
259 if (strlen(service) == 3 ) {
260 if ((*prog != 100003) || ((*vers != 2) && (*vers != 3) &&
263 } else if (memcmp(service, "nfs4_cb", 7) == 0) {
268 if (!addrstr_to_sockaddr(addr, address, port))
271 *servername = sockaddr_to_hostname(addr, address);
272 if (*servername == NULL)
275 nbytes = snprintf(buf, INFOBUFLEN, "%s@%s", service, *servername);
276 if (nbytes > INFOBUFLEN)
279 if (!(*servicename = calloc(strlen(buf) + 1, 1)))
281 memcpy(*servicename, buf, strlen(buf));
283 if (!(*protocol = strdup(protoname)))
287 printerr(0, "ERROR: failed to read service info\n");
288 if (fd != -1) close(fd);
292 *servicename = *servername = *protocol = NULL;
297 destroy_client(struct clnt_info *clp)
299 if (clp->krb5_poll_index != -1)
300 memset(&pollarray[clp->krb5_poll_index], 0,
301 sizeof(struct pollfd));
302 if (clp->gssd_poll_index != -1)
303 memset(&pollarray[clp->gssd_poll_index], 0,
304 sizeof(struct pollfd));
305 if (clp->dir_fd != -1) close(clp->dir_fd);
306 if (clp->krb5_fd != -1) close(clp->krb5_fd);
307 if (clp->gssd_fd != -1) close(clp->gssd_fd);
309 free(clp->servicename);
310 free(clp->servername);
315 static struct clnt_info *
316 insert_new_clnt(void)
318 struct clnt_info *clp = NULL;
320 if (!(clp = (struct clnt_info *)calloc(1,sizeof(struct clnt_info)))) {
321 printerr(0, "ERROR: can't malloc clnt_info: %s\n",
325 clp->krb5_poll_index = -1;
326 clp->gssd_poll_index = -1;
331 TAILQ_INSERT_HEAD(&clnt_list, clp, list);
337 process_clnt_dir_files(struct clnt_info * clp)
340 char gname[PATH_MAX];
341 char info_file_name[PATH_MAX];
343 if (clp->gssd_close_me) {
344 printerr(2, "Closing 'gssd' pipe for %s\n", clp->dirname);
346 memset(&pollarray[clp->gssd_poll_index], 0,
347 sizeof(struct pollfd));
349 clp->gssd_poll_index = -1;
350 clp->gssd_close_me = 0;
352 if (clp->krb5_close_me) {
353 printerr(2, "Closing 'krb5' pipe for %s\n", clp->dirname);
355 memset(&pollarray[clp->krb5_poll_index], 0,
356 sizeof(struct pollfd));
358 clp->krb5_poll_index = -1;
359 clp->krb5_close_me = 0;
362 if (clp->gssd_fd == -1) {
363 snprintf(gname, sizeof(gname), "%s/gssd", clp->dirname);
364 clp->gssd_fd = open(gname, O_RDWR);
366 if (clp->gssd_fd == -1) {
367 if (clp->krb5_fd == -1) {
368 snprintf(name, sizeof(name), "%s/krb5", clp->dirname);
369 clp->krb5_fd = open(name, O_RDWR);
372 /* If we opened a gss-specific pipe, let's try opening
373 * the new upcall pipe again. If we succeed, close
374 * gss-specific pipe(s).
376 if (clp->krb5_fd != -1) {
377 clp->gssd_fd = open(gname, O_RDWR);
378 if (clp->gssd_fd != -1) {
379 if (clp->krb5_fd != -1)
386 if ((clp->krb5_fd == -1) && (clp->gssd_fd == -1))
388 snprintf(info_file_name, sizeof(info_file_name), "%s/info",
390 if ((clp->servicename == NULL) &&
391 read_service_info(info_file_name, &clp->servicename,
392 &clp->servername, &clp->prog, &clp->vers,
393 &clp->protocol, (struct sockaddr *) &clp->addr))
399 get_poll_index(int *ind)
404 for (i=0; i<FD_ALLOC_BLOCK; i++) {
405 if (pollarray[i].events == 0) {
411 printerr(0, "ERROR: No pollarray slots open\n");
419 insert_clnt_poll(struct clnt_info *clp)
421 if ((clp->gssd_fd != -1) && (clp->gssd_poll_index == -1)) {
422 if (get_poll_index(&clp->gssd_poll_index)) {
423 printerr(0, "ERROR: Too many gssd clients\n");
426 pollarray[clp->gssd_poll_index].fd = clp->gssd_fd;
427 pollarray[clp->gssd_poll_index].events |= POLLIN;
430 if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
431 if (get_poll_index(&clp->krb5_poll_index)) {
432 printerr(0, "ERROR: Too many krb5 clients\n");
435 pollarray[clp->krb5_poll_index].fd = clp->krb5_fd;
436 pollarray[clp->krb5_poll_index].events |= POLLIN;
443 process_clnt_dir(char *dir, char *pdir)
445 struct clnt_info * clp;
447 if (!(clp = insert_new_clnt()))
448 goto fail_destroy_client;
450 /* An extra for the '/', and an extra for the null */
451 if (!(clp->dirname = calloc(strlen(dir) + strlen(pdir) + 2, 1))) {
452 goto fail_destroy_client;
454 sprintf(clp->dirname, "%s/%s", pdir, dir);
455 if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
456 printerr(0, "ERROR: can't open %s: %s\n",
457 clp->dirname, strerror(errno));
458 goto fail_destroy_client;
460 fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL);
461 fcntl(clp->dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MULTISHOT);
463 if (process_clnt_dir_files(clp))
464 goto fail_keep_client;
466 if (insert_clnt_poll(clp))
467 goto fail_destroy_client;
473 TAILQ_REMOVE(&clnt_list, clp, list);
477 /* We couldn't find some subdirectories, but we keep the client
478 * around in case we get a notification on the directory when the
479 * subdirectories are created. */
484 init_client_list(void)
486 TAILQ_INIT(&clnt_list);
487 /* Eventually plan to grow/shrink poll array: */
488 pollsize = FD_ALLOC_BLOCK;
489 pollarray = calloc(pollsize, sizeof(struct pollfd));
493 * This is run after a DNOTIFY signal, and should clear up any
494 * directories that are no longer around, and re-scan any existing
495 * directories, since the DNOTIFY could have been in there.
498 update_old_clients(struct dirent **namelist, int size, char *pdir)
500 struct clnt_info *clp;
503 char fname[PATH_MAX];
505 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
506 /* only compare entries in the global list that are from the
507 * same pipefs parent directory as "pdir"
509 if (strncmp(clp->dirname, pdir, strlen(pdir)) != 0) continue;
512 for (i=0; i < size; i++) {
513 snprintf(fname, sizeof(fname), "%s/%s",
514 pdir, namelist[i]->d_name);
515 if (strcmp(clp->dirname, fname) == 0) {
521 printerr(2, "destroying client %s\n", clp->dirname);
522 saveprev = clp->list.tqe_prev;
523 TAILQ_REMOVE(&clnt_list, clp, list);
528 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
529 if (!process_clnt_dir_files(clp))
530 insert_clnt_poll(clp);
534 /* Search for a client by directory name, return 1 if found, 0 otherwise */
536 find_client(char *dirname, char *pdir)
538 struct clnt_info *clp;
539 char fname[PATH_MAX];
541 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
542 snprintf(fname, sizeof(fname), "%s/%s", pdir, dirname);
543 if (strcmp(clp->dirname, fname) == 0)
550 process_pipedir(char *pipe_name)
552 struct dirent **namelist;
555 if (chdir(pipe_name) < 0) {
556 printerr(0, "ERROR: can't chdir to %s: %s\n",
557 pipe_name, strerror(errno));
561 j = scandir(pipe_name, &namelist, NULL, alphasort);
563 printerr(0, "ERROR: can't scandir %s: %s\n",
564 pipe_name, strerror(errno));
568 update_old_clients(namelist, j, pipe_name);
569 for (i=0; i < j; i++) {
570 if (i < FD_ALLOC_BLOCK
571 && !strncmp(namelist[i]->d_name, "clnt", 4)
572 && !find_client(namelist[i]->d_name, pipe_name))
573 process_clnt_dir(namelist[i]->d_name, pipe_name);
582 /* Used to read (and re-read) list of clients, set up poll array. */
584 update_client_list(void)
587 struct topdirs_info *tdi;
589 TAILQ_FOREACH(tdi, &topdirs_list, list) {
590 retval = process_pipedir(tdi->dirname);
592 printerr(1, "WARNING: error processing %s\n",
599 /* Encryption types supported by the kernel rpcsec_gss code */
600 int num_krb5_enctypes = 0;
601 krb5_enctype *krb5_enctypes = NULL;
604 * Parse the supported encryption type information
607 parse_enctypes(char *enctypes)
612 static char *cached_types;
614 if (cached_types && strcmp(cached_types, enctypes) == 0)
618 if (krb5_enctypes != NULL) {
620 krb5_enctypes = NULL;
621 num_krb5_enctypes = 0;
624 /* count the number of commas */
625 for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
626 comma = strchr(curr, ',');
632 /* If no more commas and we're not at the end, there's one more value */
636 /* Empty string, return an error */
640 /* Allocate space for enctypes array */
641 if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
645 /* Now parse each value into the array */
646 for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) {
647 krb5_enctypes[i++] = atoi(curr);
648 comma = strchr(curr, ',');
653 num_krb5_enctypes = n;
654 if ((cached_types = malloc(strlen(enctypes)+1)))
655 strcpy(cached_types, enctypes);
661 do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
662 gss_buffer_desc *context_token)
664 char *buf = NULL, *p = NULL, *end = NULL;
665 unsigned int timeout = context_timeout;
666 unsigned int buf_size = 0;
668 printerr(1, "doing downcall\n");
669 buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) +
670 sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length +
671 sizeof(context_token->length) + context_token->length;
672 p = buf = malloc(buf_size);
673 end = buf + buf_size;
675 if (WRITE_BYTES(&p, end, uid)) goto out_err;
676 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
677 if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err;
678 if (write_buffer(&p, end, &pd->pd_ctx_hndl)) goto out_err;
679 if (write_buffer(&p, end, context_token)) goto out_err;
681 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
686 printerr(1, "Failed to write downcall!\n");
691 do_error_downcall(int k5_fd, uid_t uid, int err)
694 char *p = buf, *end = buf + 1024;
695 unsigned int timeout = 0;
698 printerr(1, "doing error downcall\n");
700 if (WRITE_BYTES(&p, end, uid)) goto out_err;
701 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
702 /* use seq_win = 0 to indicate an error: */
703 if (WRITE_BYTES(&p, end, zero)) goto out_err;
704 if (WRITE_BYTES(&p, end, err)) goto out_err;
706 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
709 printerr(1, "Failed to write error downcall!\n");
714 * If the port isn't already set, do an rpcbind query to the remote server
715 * using the program and version and get the port.
717 * Newer kernels send the value of the port= mount option in the "info"
718 * file for the upcall or '0' for NFSv2/3. For NFSv4 it sends the value
719 * of the port= option or '2049'. The port field in a new sockaddr should
720 * reflect the value that was sent by the kernel.
723 populate_port(struct sockaddr *sa, const socklen_t salen,
724 const rpcprog_t program, const rpcvers_t version,
725 const unsigned short protocol)
727 struct sockaddr_in *s4 = (struct sockaddr_in *) sa;
728 #ifdef IPV6_SUPPORTED
729 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa;
730 #endif /* IPV6_SUPPORTED */
734 * Newer kernels send the port in the upcall. If we already have
735 * the port, there's no need to look it up.
737 switch (sa->sa_family) {
739 if (s4->sin_port != 0) {
740 printerr(2, "DEBUG: port already set to %d\n",
741 ntohs(s4->sin_port));
745 #ifdef IPV6_SUPPORTED
747 if (s6->sin6_port != 0) {
748 printerr(2, "DEBUG: port already set to %d\n",
749 ntohs(s6->sin6_port));
753 #endif /* IPV6_SUPPORTED */
755 printerr(0, "ERROR: unsupported address family %d\n",
761 * Newer kernels that send the port in the upcall set the value to
762 * 2049 for NFSv4 mounts when one isn't specified. The check below is
763 * only for kernels that don't send the port in the upcall. For those
764 * we either have to do an rpcbind query or set it to the standard
765 * port. Doing a query could be problematic (firewalls, etc), so take
766 * the latter approach.
768 if (program == 100003 && version == 4) {
773 port = nfs_getport(sa, salen, program, version, protocol);
775 printerr(0, "ERROR: unable to obtain port for prog %ld "
776 "vers %ld\n", program, version);
781 printerr(2, "DEBUG: setting port to %hu for prog %lu vers %lu\n", port,
784 switch (sa->sa_family) {
786 s4->sin_port = htons(port);
788 #ifdef IPV6_SUPPORTED
790 s6->sin6_port = htons(port);
792 #endif /* IPV6_SUPPORTED */
799 * Create an RPC connection and establish an authenticated
800 * gss context with a server.
802 int create_auth_rpc_client(struct clnt_info *clp,
803 CLIENT **clnt_return,
808 CLIENT *rpc_clnt = NULL;
809 struct rpc_gss_sec sec;
814 char rpc_errmsg[1024];
816 struct timeval timeout = {5, 0};
817 struct sockaddr *addr = (struct sockaddr *) &clp->addr;
820 /* Create the context as the user (not as root) */
821 save_uid = geteuid();
822 if (setfsuid(uid) != 0) {
823 printerr(0, "WARNING: Failed to setfsuid for "
824 "user with uid %d\n", uid);
827 printerr(2, "creating context using fsuid %d (save_uid %d)\n",
830 sec.qop = GSS_C_QOP_DEFAULT;
831 sec.svc = RPCSEC_GSS_SVC_NONE;
832 sec.cred = GSS_C_NO_CREDENTIAL;
834 if (authtype == AUTHTYPE_KRB5) {
835 sec.mech = (gss_OID)&krb5oid;
836 sec.req_flags = GSS_C_MUTUAL_FLAG;
839 printerr(0, "ERROR: Invalid authentication type (%d) "
840 "in create_auth_rpc_client\n", authtype);
845 if (authtype == AUTHTYPE_KRB5) {
846 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
848 * Do this before creating rpc connection since we won't need
849 * rpc connection if it fails!
851 if (limit_krb5_enctypes(&sec)) {
852 printerr(1, "WARNING: Failed while limiting krb5 "
853 "encryption types for user with uid %d\n",
860 /* create an rpc connection to the nfs server */
862 printerr(2, "creating %s client for server %s\n", clp->protocol,
865 if ((strcmp(clp->protocol, "tcp")) == 0) {
866 protocol = IPPROTO_TCP;
867 } else if ((strcmp(clp->protocol, "udp")) == 0) {
868 protocol = IPPROTO_UDP;
870 printerr(0, "WARNING: unrecognized protocol, '%s', requested "
871 "for connection to server %s for user with uid %d\n",
872 clp->protocol, clp->servername, uid);
876 switch (addr->sa_family) {
878 salen = sizeof(struct sockaddr_in);
880 #ifdef IPV6_SUPPORTED
882 salen = sizeof(struct sockaddr_in6);
884 #endif /* IPV6_SUPPORTED */
886 printerr(1, "ERROR: Unknown address family %d\n",
891 if (!populate_port(addr, salen, clp->prog, clp->vers, protocol))
894 rpc_clnt = nfs_get_rpcclient(addr, salen, protocol, clp->prog,
895 clp->vers, &timeout);
897 snprintf(rpc_errmsg, sizeof(rpc_errmsg),
898 "WARNING: can't create %s rpc_clnt to server %s for "
900 protocol == IPPROTO_TCP ? "tcp" : "udp",
901 clp->servername, uid);
903 clnt_spcreateerror(rpc_errmsg));
907 printerr(2, "creating context with server %s\n", clp->servicename);
908 auth = authgss_create_default(rpc_clnt, clp->servicename, &sec);
910 /* Our caller should print appropriate message */
911 printerr(2, "WARNING: Failed to create krb5 context for "
912 "user with uid %d for server %s\n",
913 uid, clp->servername);
918 rpc_clnt->cl_auth = auth;
919 *clnt_return = rpc_clnt;
924 if (sec.cred != GSS_C_NO_CREDENTIAL)
925 gss_release_cred(&min_stat, &sec.cred);
926 /* Restore euid to original value */
927 if (((int)save_uid != -1) && (setfsuid(save_uid) != (int)uid)) {
928 printerr(0, "WARNING: Failed to restore fsuid"
929 " to uid %d from %d\n", save_uid, uid);
934 /* Only destroy here if failure. Otherwise, caller is responsible */
935 if (rpc_clnt) clnt_destroy(rpc_clnt);
941 user_cachedir(char *dirname, uid_t uid)
946 if ((pw = getpwuid(uid)) == NULL) {
947 printerr(0, "user_cachedir: Failed to find '%d' uid"
948 " for cache directory\n");
951 ptr = malloc(strlen(dirname)+strlen(pw->pw_name)+2);
953 sprintf(ptr, "%s/%s", dirname, pw->pw_name);
958 * this code uses the userland rpcsec gss library to create a krb5
959 * context on behalf of the kernel
962 process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
965 CLIENT *rpc_clnt = NULL;
967 struct authgss_private_data pd;
968 gss_buffer_desc token;
969 char **credlist = NULL;
971 char **dirname, *dir, *userdir;
972 int create_resp = -1;
973 int err, downcall_err = -EACCES;
975 printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
978 if (clp->servicename) {
979 free(clp->servicename);
980 clp->servicename = strdup(tgtname);
985 memset(&pd, 0, sizeof(struct authgss_private_data));
988 * If "service" is specified, then the kernel is indicating that
989 * we must use machine credentials for this request. (Regardless
990 * of the uid value or the setting of root_uses_machine_creds.)
991 * If the service value is "*", then any service name can be used.
992 * Otherwise, it specifies the service name that should be used.
993 * (For now, the values of service will only be "*" or "nfs".)
995 * Restricting gssd to use "nfs" service name is needed for when
996 * the NFS server is doing a callback to the NFS client. In this
997 * case, the NFS server has to authenticate itself as "nfs" --
998 * even if there are other service keys such as "host" or "root"
1001 * Another case when the kernel may specify the service attribute
1002 * is when gssd is being asked to create the context for a
1003 * SETCLIENT_ID operation. In this case, machine credentials
1004 * must be used for the authentication. However, the service name
1005 * used for this case is not important.
1008 printerr(2, "%s: service is '%s'\n", __func__,
1009 service ? service : "<null>");
1010 if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
1012 /* Tell krb5 gss which credentials cache to use */
1013 for (dirname = ccachesearch; *dirname != NULL; dirname++) {
1014 /* See if the user name is needed */
1015 if (strncmp(*dirname, GSSD_USER_CRED_DIR,
1016 strlen(GSSD_USER_CRED_DIR)) == 0) {
1017 userdir = user_cachedir(*dirname, uid);
1018 if (userdir == NULL)
1024 err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, dir);
1030 if (err == -EKEYEXPIRED)
1031 downcall_err = -EKEYEXPIRED;
1033 create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
1035 if (create_resp == 0)
1039 if (create_resp != 0) {
1040 if (uid == 0 && (root_uses_machine_creds == 1 ||
1045 gssd_refresh_krb5_machine_credential(clp->servername,
1048 * Get a list of credential cache names and try each
1049 * of them until one works or we've tried them all
1051 if (gssd_get_krb5_machine_cred_list(&credlist)) {
1052 printerr(0, "ERROR: No credentials found "
1053 "for connection to server %s\n",
1055 goto out_return_error;
1057 for (ccname = credlist; ccname && *ccname; ccname++) {
1058 gssd_setup_krb5_machine_gss_ccache(*ccname);
1059 if ((create_auth_rpc_client(clp, &rpc_clnt,
1061 AUTHTYPE_KRB5)) == 0) {
1066 printerr(2, "WARNING: Failed to create machine krb5 context "
1067 "with credentials cache %s for server %s\n",
1068 *ccname, clp->servername);
1070 gssd_free_krb5_machine_cred_list(credlist);
1074 printerr(2, "WARNING: Machine cache is prematurely expired or corrupted "
1075 "trying to recreate cache for server %s\n", clp->servername);
1077 printerr(1, "WARNING: Failed to create machine krb5 context "
1078 "with any credentials cache for server %s\n",
1080 goto out_return_error;
1085 printerr(1, "WARNING: Failed to create krb5 context "
1086 "for user with uid %d for server %s\n",
1087 uid, clp->servername);
1088 goto out_return_error;
1092 if (!authgss_get_private_data(auth, &pd)) {
1093 printerr(1, "WARNING: Failed to obtain authentication "
1094 "data for user with uid %d for server %s\n",
1095 uid, clp->servername);
1096 goto out_return_error;
1099 if (serialize_context_for_kernel(pd.pd_ctx, &token, &krb5oid, NULL)) {
1100 printerr(0, "WARNING: Failed to serialize krb5 context for "
1101 "user with uid %d for server %s\n",
1102 uid, clp->servername);
1103 goto out_return_error;
1106 do_downcall(fd, uid, &pd, &token);
1111 #ifndef HAVE_LIBTIRPC
1112 if (pd.pd_ctx_hndl.length != 0)
1113 authgss_free_private_data(&pd);
1118 clnt_destroy(rpc_clnt);
1122 do_error_downcall(fd, uid, downcall_err);
1127 handle_krb5_upcall(struct clnt_info *clp)
1131 if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) {
1132 printerr(0, "WARNING: failed reading uid from krb5 "
1133 "upcall pipe: %s\n", strerror(errno));
1137 return process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
1141 handle_gssd_upcall(struct clnt_info *clp)
1148 char *target = NULL;
1149 char *service = NULL;
1150 char *enctypes = NULL;
1152 printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
1154 if (readline(clp->gssd_fd, &lbuf, &lbuflen) != 1) {
1155 printerr(0, "WARNING: handle_gssd_upcall: "
1156 "failed reading request\n");
1159 printerr(2, "%s: '%s'\n", __func__, lbuf);
1161 /* find the mechanism name */
1162 if ((p = strstr(lbuf, "mech=")) != NULL) {
1163 mech = malloc(lbuflen);
1166 if (sscanf(p, "mech=%s", mech) != 1) {
1167 printerr(0, "WARNING: handle_gssd_upcall: "
1168 "failed to parse gss mechanism name "
1169 "in upcall string '%s'\n", lbuf);
1173 printerr(0, "WARNING: handle_gssd_upcall: "
1174 "failed to find gss mechanism name "
1175 "in upcall string '%s'\n", lbuf);
1180 if ((p = strstr(lbuf, "uid=")) != NULL) {
1181 if (sscanf(p, "uid=%d", &uid) != 1) {
1182 printerr(0, "WARNING: handle_gssd_upcall: "
1183 "failed to parse uid "
1184 "in upcall string '%s'\n", lbuf);
1188 printerr(0, "WARNING: handle_gssd_upcall: "
1189 "failed to find uid "
1190 "in upcall string '%s'\n", lbuf);
1194 /* read supported encryption types if supplied */
1195 if ((p = strstr(lbuf, "enctypes=")) != NULL) {
1196 enctypes = malloc(lbuflen);
1199 if (sscanf(p, "enctypes=%s", enctypes) != 1) {
1200 printerr(0, "WARNING: handle_gssd_upcall: "
1201 "failed to parse encryption types "
1202 "in upcall string '%s'\n", lbuf);
1205 if (parse_enctypes(enctypes) != 0) {
1206 printerr(0, "WARNING: handle_gssd_upcall: "
1207 "parsing encryption types failed: errno %d\n", errno);
1211 /* read target name */
1212 if ((p = strstr(lbuf, "target=")) != NULL) {
1213 target = malloc(lbuflen);
1216 if (sscanf(p, "target=%s", target) != 1) {
1217 printerr(0, "WARNING: handle_gssd_upcall: "
1218 "failed to parse target name "
1219 "in upcall string '%s'\n", lbuf);
1225 * read the service name
1227 * The presence of attribute "service=" indicates that machine
1228 * credentials should be used for this request. If the value
1229 * is "*", then any machine credentials available can be used.
1230 * If the value is anything else, then machine credentials for
1231 * the specified service name (always "nfs" for now) should be
1234 if ((p = strstr(lbuf, "service=")) != NULL) {
1235 service = malloc(lbuflen);
1238 if (sscanf(p, "service=%s", service) != 1) {
1239 printerr(0, "WARNING: handle_gssd_upcall: "
1240 "failed to parse service type "
1241 "in upcall string '%s'\n", lbuf);
1246 if (strcmp(mech, "krb5") == 0)
1247 process_krb5_upcall(clp, uid, clp->gssd_fd, target, service);
1249 printerr(0, "WARNING: handle_gssd_upcall: "
1250 "received unknown gss mech '%s'\n", mech);