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>
55 #include <sys/resource.h>
68 #include <gssapi/gssapi.h>
75 #include "krb5_util.h"
82 * array of struct pollfd suitable to pass to poll. initialized to
83 * zero - a zero struct is ignored by poll() because the events mask is 0.
86 * linked list of struct clnt_info which associates a clntXXX directory
87 * with an index into pollarray[], and other basic data about that client.
89 * Directory structure: created by the kernel
90 * {rpc_pipefs}/{dir}/clntXX : one per rpc_clnt struct in the kernel
91 * {rpc_pipefs}/{dir}/clntXX/krb5 : read uid for which kernel wants
92 * a context, write the resulting context
93 * {rpc_pipefs}/{dir}/clntXX/info : stores info such as server name
94 * {rpc_pipefs}/{dir}/clntXX/gssd : pipe for all gss mechanisms using
95 * a text-based string of parameters
98 * Poll all {rpc_pipefs}/{dir}/clntXX/YYYY files. When data is ready,
99 * read and process; performs rpcsec_gss context initialization protocol to
100 * get a cred for that user. Writes result to corresponding krb5 file
101 * in a form the kernel code will understand.
102 * In addition, we make sure we are notified whenever anything is
103 * created or destroyed in {rpc_pipefs} or in any of the clntXX directories,
104 * and rescan the whole {rpc_pipefs} when this happens.
107 struct pollfd * pollarray;
109 unsigned long pollsize; /* the size of pollaray (in pollfd's) */
111 /* Avoid DNS reverse lookups on server names */
115 * convert a presentation address string to a sockaddr_storage struct. Returns
116 * true on success or false on failure.
118 * Note that we do not populate the sin6_scope_id field here for IPv6 addrs.
119 * gssd nececessarily relies on hostname resolution and DNS AAAA records
120 * do not generally contain scope-id's. This means that GSSAPI auth really
121 * can't work with IPv6 link-local addresses.
123 * We *could* consider changing this if we did something like adopt the
124 * Microsoft "standard" of using the ipv6-literal.net domainname, but it's
125 * not really feasible at present.
128 addrstr_to_sockaddr(struct sockaddr *sa, const char *node, const char *port)
131 struct addrinfo *res;
132 struct addrinfo hints = { .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV };
134 #ifndef IPV6_SUPPORTED
135 hints.ai_family = AF_INET;
136 #endif /* IPV6_SUPPORTED */
138 rc = getaddrinfo(node, port, &hints, &res);
140 printerr(0, "ERROR: unable to convert %s|%s to sockaddr: %s\n",
141 node, port, rc == EAI_SYSTEM ? strerror(errno) :
146 #ifdef IPV6_SUPPORTED
148 * getnameinfo ignores the scopeid. If the address turns out to have
149 * a non-zero scopeid, we can't use it -- the resolved host might be
150 * completely different from the one intended.
152 if (res->ai_addr->sa_family == AF_INET6) {
153 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)res->ai_addr;
154 if (sin6->sin6_scope_id) {
155 printerr(0, "ERROR: address %s has non-zero "
156 "sin6_scope_id!\n", node);
161 #endif /* IPV6_SUPPORTED */
163 memcpy(sa, res->ai_addr, res->ai_addrlen);
169 * convert a sockaddr to a hostname
172 get_servername(const char *name, const struct sockaddr *sa, const char *addr)
177 char hbuf[NI_MAXHOST];
178 unsigned char buf[sizeof(struct in6_addr)];
183 * Determine if this is a server name, or an IP address.
184 * If it is an IP address, do the DNS lookup otherwise
185 * skip the DNS lookup.
188 if (strchr(name, '.') && inet_pton(AF_INET, name, buf) == 1)
189 servername = 1; /* IPv4 */
190 else if (strchr(name, ':') && inet_pton(AF_INET6, name, buf) == 1)
191 servername = 1; /* or IPv6 */
198 switch (sa->sa_family) {
200 addrlen = sizeof(struct sockaddr_in);
202 #ifdef IPV6_SUPPORTED
204 addrlen = sizeof(struct sockaddr_in6);
206 #endif /* IPV6_SUPPORTED */
208 printerr(0, "ERROR: unrecognized addr family %d\n",
213 err = getnameinfo(sa, addrlen, hbuf, sizeof(hbuf), NULL, 0,
216 printerr(0, "ERROR: unable to resolve %s to hostname: %s\n",
217 addr, err == EAI_SYSTEM ? strerror(err) :
222 hostname = strdup(hbuf);
227 /* XXX buffer problems: */
229 read_service_info(char *info_file_name, char **servicename, char **servername,
230 int *prog, int *vers, char **protocol,
231 struct sockaddr *addr) {
232 #define INFOBUFLEN 256
233 char buf[INFOBUFLEN + 1];
234 static char server[128];
236 static char service[128];
237 static char address[128];
246 *servicename = *servername = *protocol = NULL;
248 if ((fd = open(info_file_name, O_RDONLY)) == -1) {
249 printerr(0, "ERROR: can't open %s: %s\n", info_file_name,
253 if ((nbytes = read(fd, buf, INFOBUFLEN)) == -1)
258 numfields = sscanf(buf,"RPC server: %127s\n"
259 "service: %127s %15s version %15s\n"
263 service, program, version,
267 if (numfields == 5) {
268 strcpy(protoname, "tcp");
269 } else if (numfields != 6) {
274 if ((p = strstr(buf, "port")) != NULL)
275 sscanf(p, "port: %127s\n", port);
277 /* get program, and version numbers */
278 *prog = atoi(program + 1); /* skip open paren */
279 *vers = atoi(version);
281 if (!addrstr_to_sockaddr(addr, address, port))
284 *servername = get_servername(server, addr, address);
285 if (*servername == NULL)
288 nbytes = snprintf(buf, INFOBUFLEN, "%s@%s", service, *servername);
289 if (nbytes > INFOBUFLEN)
292 if (!(*servicename = calloc(strlen(buf) + 1, 1)))
294 memcpy(*servicename, buf, strlen(buf));
296 if (!(*protocol = strdup(protoname)))
300 printerr(0, "ERROR: failed to read service info\n");
301 if (fd != -1) close(fd);
305 *servicename = *servername = *protocol = NULL;
310 destroy_client(struct clnt_info *clp)
312 if (clp->krb5_poll_index != -1)
313 memset(&pollarray[clp->krb5_poll_index], 0,
314 sizeof(struct pollfd));
315 if (clp->gssd_poll_index != -1)
316 memset(&pollarray[clp->gssd_poll_index], 0,
317 sizeof(struct pollfd));
318 if (clp->dir_fd != -1) close(clp->dir_fd);
319 if (clp->krb5_fd != -1) close(clp->krb5_fd);
320 if (clp->gssd_fd != -1) close(clp->gssd_fd);
322 free(clp->servicename);
323 free(clp->servername);
328 static struct clnt_info *
329 insert_new_clnt(void)
331 struct clnt_info *clp = NULL;
333 if (!(clp = (struct clnt_info *)calloc(1,sizeof(struct clnt_info)))) {
334 printerr(0, "ERROR: can't malloc clnt_info: %s\n",
338 clp->krb5_poll_index = -1;
339 clp->gssd_poll_index = -1;
344 TAILQ_INSERT_HEAD(&clnt_list, clp, list);
350 process_clnt_dir_files(struct clnt_info * clp)
353 char gname[PATH_MAX];
354 char info_file_name[PATH_MAX];
356 if (clp->gssd_close_me) {
357 printerr(2, "Closing 'gssd' pipe for %s\n", clp->dirname);
359 memset(&pollarray[clp->gssd_poll_index], 0,
360 sizeof(struct pollfd));
362 clp->gssd_poll_index = -1;
363 clp->gssd_close_me = 0;
365 if (clp->krb5_close_me) {
366 printerr(2, "Closing 'krb5' pipe for %s\n", clp->dirname);
368 memset(&pollarray[clp->krb5_poll_index], 0,
369 sizeof(struct pollfd));
371 clp->krb5_poll_index = -1;
372 clp->krb5_close_me = 0;
375 if (clp->gssd_fd == -1) {
376 snprintf(gname, sizeof(gname), "%s/gssd", clp->dirname);
377 clp->gssd_fd = open(gname, O_RDWR);
379 if (clp->gssd_fd == -1) {
380 if (clp->krb5_fd == -1) {
381 snprintf(name, sizeof(name), "%s/krb5", clp->dirname);
382 clp->krb5_fd = open(name, O_RDWR);
385 /* If we opened a gss-specific pipe, let's try opening
386 * the new upcall pipe again. If we succeed, close
387 * gss-specific pipe(s).
389 if (clp->krb5_fd != -1) {
390 clp->gssd_fd = open(gname, O_RDWR);
391 if (clp->gssd_fd != -1) {
392 if (clp->krb5_fd != -1)
399 if ((clp->krb5_fd == -1) && (clp->gssd_fd == -1))
401 snprintf(info_file_name, sizeof(info_file_name), "%s/info",
403 if ((clp->servicename == NULL) &&
404 read_service_info(info_file_name, &clp->servicename,
405 &clp->servername, &clp->prog, &clp->vers,
406 &clp->protocol, (struct sockaddr *) &clp->addr))
412 get_poll_index(int *ind)
417 for (i=0; i<pollsize; i++) {
418 if (pollarray[i].events == 0) {
424 printerr(0, "ERROR: No pollarray slots open\n");
432 insert_clnt_poll(struct clnt_info *clp)
434 if ((clp->gssd_fd != -1) && (clp->gssd_poll_index == -1)) {
435 if (get_poll_index(&clp->gssd_poll_index)) {
436 printerr(0, "ERROR: Too many gssd clients\n");
439 pollarray[clp->gssd_poll_index].fd = clp->gssd_fd;
440 pollarray[clp->gssd_poll_index].events |= POLLIN;
443 if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
444 if (get_poll_index(&clp->krb5_poll_index)) {
445 printerr(0, "ERROR: Too many krb5 clients\n");
448 pollarray[clp->krb5_poll_index].fd = clp->krb5_fd;
449 pollarray[clp->krb5_poll_index].events |= POLLIN;
456 process_clnt_dir(char *dir, char *pdir)
458 struct clnt_info * clp;
460 if (!(clp = insert_new_clnt()))
461 goto fail_destroy_client;
463 /* An extra for the '/', and an extra for the null */
464 if (!(clp->dirname = calloc(strlen(dir) + strlen(pdir) + 2, 1))) {
465 goto fail_destroy_client;
467 sprintf(clp->dirname, "%s/%s", pdir, dir);
468 if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
469 printerr(0, "ERROR: can't open %s: %s\n",
470 clp->dirname, strerror(errno));
471 goto fail_destroy_client;
473 fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL);
474 fcntl(clp->dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MULTISHOT);
476 if (process_clnt_dir_files(clp))
477 goto fail_keep_client;
479 if (insert_clnt_poll(clp))
480 goto fail_destroy_client;
486 TAILQ_REMOVE(&clnt_list, clp, list);
490 /* We couldn't find some subdirectories, but we keep the client
491 * around in case we get a notification on the directory when the
492 * subdirectories are created. */
497 init_client_list(void)
500 TAILQ_INIT(&clnt_list);
501 /* Eventually plan to grow/shrink poll array: */
502 pollsize = FD_ALLOC_BLOCK;
503 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0 &&
504 rlim.rlim_cur != RLIM_INFINITY)
505 pollsize = rlim.rlim_cur;
506 pollarray = calloc(pollsize, sizeof(struct pollfd));
510 * This is run after a DNOTIFY signal, and should clear up any
511 * directories that are no longer around, and re-scan any existing
512 * directories, since the DNOTIFY could have been in there.
515 update_old_clients(struct dirent **namelist, int size, char *pdir)
517 struct clnt_info *clp;
520 char fname[PATH_MAX];
522 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
523 /* only compare entries in the global list that are from the
524 * same pipefs parent directory as "pdir"
526 if (strncmp(clp->dirname, pdir, strlen(pdir)) != 0) continue;
529 for (i=0; i < size; i++) {
530 snprintf(fname, sizeof(fname), "%s/%s",
531 pdir, namelist[i]->d_name);
532 if (strcmp(clp->dirname, fname) == 0) {
538 printerr(2, "destroying client %s\n", clp->dirname);
539 saveprev = clp->list.tqe_prev;
540 TAILQ_REMOVE(&clnt_list, clp, list);
545 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
546 if (!process_clnt_dir_files(clp))
547 insert_clnt_poll(clp);
551 /* Search for a client by directory name, return 1 if found, 0 otherwise */
553 find_client(char *dirname, char *pdir)
555 struct clnt_info *clp;
556 char fname[PATH_MAX];
558 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
559 snprintf(fname, sizeof(fname), "%s/%s", pdir, dirname);
560 if (strcmp(clp->dirname, fname) == 0)
567 process_pipedir(char *pipe_name)
569 struct dirent **namelist;
572 if (chdir(pipe_name) < 0) {
573 printerr(0, "ERROR: can't chdir to %s: %s\n",
574 pipe_name, strerror(errno));
578 j = scandir(pipe_name, &namelist, NULL, alphasort);
580 printerr(0, "ERROR: can't scandir %s: %s\n",
581 pipe_name, strerror(errno));
585 update_old_clients(namelist, j, pipe_name);
586 for (i=0; i < j; i++) {
587 if (!strncmp(namelist[i]->d_name, "clnt", 4)
588 && !find_client(namelist[i]->d_name, pipe_name))
589 process_clnt_dir(namelist[i]->d_name, pipe_name);
598 /* Used to read (and re-read) list of clients, set up poll array. */
600 update_client_list(void)
603 struct topdirs_info *tdi;
605 TAILQ_FOREACH(tdi, &topdirs_list, list) {
606 retval = process_pipedir(tdi->dirname);
608 printerr(1, "WARNING: error processing %s\n",
615 /* Encryption types supported by the kernel rpcsec_gss code */
616 int num_krb5_enctypes = 0;
617 krb5_enctype *krb5_enctypes = NULL;
620 * Parse the supported encryption type information
623 parse_enctypes(char *enctypes)
628 static char *cached_types;
630 if (cached_types && strcmp(cached_types, enctypes) == 0)
634 if (krb5_enctypes != NULL) {
636 krb5_enctypes = NULL;
637 num_krb5_enctypes = 0;
640 /* count the number of commas */
641 for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
642 comma = strchr(curr, ',');
648 /* If no more commas and we're not at the end, there's one more value */
652 /* Empty string, return an error */
656 /* Allocate space for enctypes array */
657 if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
661 /* Now parse each value into the array */
662 for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) {
663 krb5_enctypes[i++] = atoi(curr);
664 comma = strchr(curr, ',');
669 num_krb5_enctypes = n;
670 if ((cached_types = malloc(strlen(enctypes)+1)))
671 strcpy(cached_types, enctypes);
677 do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
678 gss_buffer_desc *context_token, OM_uint32 lifetime_rec)
680 char *buf = NULL, *p = NULL, *end = NULL;
681 unsigned int timeout = context_timeout;
682 unsigned int buf_size = 0;
684 printerr(1, "doing downcall lifetime_rec %u\n", lifetime_rec);
685 buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) +
686 sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length +
687 sizeof(context_token->length) + context_token->length;
688 p = buf = malloc(buf_size);
689 end = buf + buf_size;
691 /* context_timeout set by -t option overrides context lifetime */
693 timeout = lifetime_rec;
694 if (WRITE_BYTES(&p, end, uid)) goto out_err;
695 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
696 if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err;
697 if (write_buffer(&p, end, &pd->pd_ctx_hndl)) goto out_err;
698 if (write_buffer(&p, end, context_token)) goto out_err;
700 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
705 printerr(1, "Failed to write downcall!\n");
710 do_error_downcall(int k5_fd, uid_t uid, int err)
713 char *p = buf, *end = buf + 1024;
714 unsigned int timeout = 0;
717 printerr(1, "doing error downcall\n");
719 if (WRITE_BYTES(&p, end, uid)) goto out_err;
720 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
721 /* use seq_win = 0 to indicate an error: */
722 if (WRITE_BYTES(&p, end, zero)) goto out_err;
723 if (WRITE_BYTES(&p, end, err)) goto out_err;
725 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
728 printerr(1, "Failed to write error downcall!\n");
733 * If the port isn't already set, do an rpcbind query to the remote server
734 * using the program and version and get the port.
736 * Newer kernels send the value of the port= mount option in the "info"
737 * file for the upcall or '0' for NFSv2/3. For NFSv4 it sends the value
738 * of the port= option or '2049'. The port field in a new sockaddr should
739 * reflect the value that was sent by the kernel.
742 populate_port(struct sockaddr *sa, const socklen_t salen,
743 const rpcprog_t program, const rpcvers_t version,
744 const unsigned short protocol)
746 struct sockaddr_in *s4 = (struct sockaddr_in *) sa;
747 #ifdef IPV6_SUPPORTED
748 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa;
749 #endif /* IPV6_SUPPORTED */
753 * Newer kernels send the port in the upcall. If we already have
754 * the port, there's no need to look it up.
756 switch (sa->sa_family) {
758 if (s4->sin_port != 0) {
759 printerr(2, "DEBUG: port already set to %d\n",
760 ntohs(s4->sin_port));
764 #ifdef IPV6_SUPPORTED
766 if (s6->sin6_port != 0) {
767 printerr(2, "DEBUG: port already set to %d\n",
768 ntohs(s6->sin6_port));
772 #endif /* IPV6_SUPPORTED */
774 printerr(0, "ERROR: unsupported address family %d\n",
780 * Newer kernels that send the port in the upcall set the value to
781 * 2049 for NFSv4 mounts when one isn't specified. The check below is
782 * only for kernels that don't send the port in the upcall. For those
783 * we either have to do an rpcbind query or set it to the standard
784 * port. Doing a query could be problematic (firewalls, etc), so take
785 * the latter approach.
787 if (program == 100003 && version == 4) {
792 port = nfs_getport(sa, salen, program, version, protocol);
794 printerr(0, "ERROR: unable to obtain port for prog %ld "
795 "vers %ld\n", program, version);
800 printerr(2, "DEBUG: setting port to %hu for prog %lu vers %lu\n", port,
803 switch (sa->sa_family) {
805 s4->sin_port = htons(port);
807 #ifdef IPV6_SUPPORTED
809 s6->sin6_port = htons(port);
811 #endif /* IPV6_SUPPORTED */
818 * Create an RPC connection and establish an authenticated
819 * gss context with a server.
822 create_auth_rpc_client(struct clnt_info *clp,
823 CLIENT **clnt_return,
829 CLIENT *rpc_clnt = NULL;
830 struct rpc_gss_sec sec;
835 char rpc_errmsg[1024];
837 struct timeval timeout = {5, 0};
838 struct sockaddr *addr = (struct sockaddr *) &clp->addr;
841 /* Create the context as the user (not as root) */
842 save_uid = geteuid();
843 if (setfsuid(uid) != 0) {
844 printerr(0, "WARNING: Failed to setfsuid for "
845 "user with uid %d\n", uid);
848 printerr(2, "creating context using fsuid %d (save_uid %d)\n",
851 sec.qop = GSS_C_QOP_DEFAULT;
852 sec.svc = RPCSEC_GSS_SVC_NONE;
855 if (authtype == AUTHTYPE_KRB5) {
856 sec.mech = (gss_OID)&krb5oid;
857 sec.req_flags = GSS_C_MUTUAL_FLAG;
860 printerr(0, "ERROR: Invalid authentication type (%d) "
861 "in create_auth_rpc_client\n", authtype);
866 if (authtype == AUTHTYPE_KRB5) {
867 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
869 * Do this before creating rpc connection since we won't need
870 * rpc connection if it fails!
872 if (limit_krb5_enctypes(&sec)) {
873 printerr(1, "WARNING: Failed while limiting krb5 "
874 "encryption types for user with uid %d\n",
881 /* create an rpc connection to the nfs server */
883 printerr(2, "creating %s client for server %s\n", clp->protocol,
886 if ((strcmp(clp->protocol, "tcp")) == 0) {
887 protocol = IPPROTO_TCP;
888 } else if ((strcmp(clp->protocol, "udp")) == 0) {
889 protocol = IPPROTO_UDP;
891 printerr(0, "WARNING: unrecognized protocol, '%s', requested "
892 "for connection to server %s for user with uid %d\n",
893 clp->protocol, clp->servername, uid);
897 switch (addr->sa_family) {
899 salen = sizeof(struct sockaddr_in);
901 #ifdef IPV6_SUPPORTED
903 salen = sizeof(struct sockaddr_in6);
905 #endif /* IPV6_SUPPORTED */
907 printerr(1, "ERROR: Unknown address family %d\n",
912 if (!populate_port(addr, salen, clp->prog, clp->vers, protocol))
915 rpc_clnt = nfs_get_rpcclient(addr, salen, protocol, clp->prog,
916 clp->vers, &timeout);
918 snprintf(rpc_errmsg, sizeof(rpc_errmsg),
919 "WARNING: can't create %s rpc_clnt to server %s for "
921 protocol == IPPROTO_TCP ? "tcp" : "udp",
922 clp->servername, uid);
924 clnt_spcreateerror(rpc_errmsg));
928 printerr(2, "creating context with server %s\n", clp->servicename);
929 auth = authgss_create_default(rpc_clnt, clp->servicename, &sec);
931 /* Our caller should print appropriate message */
932 printerr(2, "WARNING: Failed to create krb5 context for "
933 "user with uid %d for server %s\n",
934 uid, clp->servername);
939 rpc_clnt->cl_auth = auth;
940 *clnt_return = rpc_clnt;
945 if (sec.cred != GSS_C_NO_CREDENTIAL)
946 gss_release_cred(&min_stat, &sec.cred);
947 /* Restore euid to original value */
948 if (((int)save_uid != -1) && (setfsuid(save_uid) != (int)uid)) {
949 printerr(0, "WARNING: Failed to restore fsuid"
950 " to uid %d from %d\n", save_uid, uid);
955 /* Only destroy here if failure. Otherwise, caller is responsible */
956 if (rpc_clnt) clnt_destroy(rpc_clnt);
962 * this code uses the userland rpcsec gss library to create a krb5
963 * context on behalf of the kernel
966 process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
969 CLIENT *rpc_clnt = NULL;
971 struct authgss_private_data pd;
972 gss_buffer_desc token;
973 char **credlist = NULL;
976 int create_resp = -1;
977 int err, downcall_err = -EACCES;
978 gss_cred_id_t gss_cred;
979 OM_uint32 maj_stat, min_stat, lifetime_rec;
981 printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
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 /* Try first to acquire credentials directly via GSSAPI */
1014 err = gssd_acquire_user_cred(uid, &gss_cred);
1016 create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
1017 AUTHTYPE_KRB5, gss_cred);
1018 /* if create_auth_rplc_client fails try the traditional method of
1019 * trolling for credentials */
1020 for (dirname = ccachesearch; create_resp != 0 && *dirname != NULL; dirname++) {
1021 err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname);
1022 if (err == -EKEYEXPIRED)
1023 downcall_err = -EKEYEXPIRED;
1025 create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
1026 AUTHTYPE_KRB5, GSS_C_NO_CREDENTIAL);
1029 if (create_resp != 0) {
1030 if (uid == 0 && (root_uses_machine_creds == 1 ||
1035 gssd_refresh_krb5_machine_credential(clp->servername,
1039 * Get a list of credential cache names and try each
1040 * of them until one works or we've tried them all
1042 if (gssd_get_krb5_machine_cred_list(&credlist)) {
1043 printerr(0, "ERROR: No credentials found "
1044 "for connection to server %s\n",
1046 goto out_return_error;
1048 for (ccname = credlist; ccname && *ccname; ccname++) {
1049 gssd_setup_krb5_machine_gss_ccache(*ccname);
1050 if ((create_auth_rpc_client(clp, &rpc_clnt,
1053 GSS_C_NO_CREDENTIAL)) == 0) {
1058 printerr(2, "WARNING: Failed to create machine krb5 context "
1059 "with credentials cache %s for server %s\n",
1060 *ccname, clp->servername);
1062 gssd_free_krb5_machine_cred_list(credlist);
1066 printerr(2, "WARNING: Machine cache is prematurely expired or corrupted "
1067 "trying to recreate cache for server %s\n", clp->servername);
1069 printerr(1, "WARNING: Failed to create machine krb5 context "
1070 "with any credentials cache for server %s\n",
1072 goto out_return_error;
1077 printerr(1, "WARNING: Failed to create krb5 context "
1078 "for user with uid %d for server %s\n",
1079 uid, clp->servername);
1080 goto out_return_error;
1084 if (!authgss_get_private_data(auth, &pd)) {
1085 printerr(1, "WARNING: Failed to obtain authentication "
1086 "data for user with uid %d for server %s\n",
1087 uid, clp->servername);
1088 goto out_return_error;
1091 /* Grab the context lifetime to pass to the kernel. lifetime_rec
1092 * is set to zero on error */
1093 maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, NULL,
1094 &lifetime_rec, NULL, NULL, NULL, NULL);
1097 printerr(1, "WARNING: Failed to inquire context for lifetme "
1098 "maj_stat %u\n", maj_stat);
1100 if (serialize_context_for_kernel(&pd.pd_ctx, &token, &krb5oid, NULL)) {
1101 printerr(0, "WARNING: Failed to serialize krb5 context for "
1102 "user with uid %d for server %s\n",
1103 uid, clp->servername);
1104 goto out_return_error;
1107 do_downcall(fd, uid, &pd, &token, lifetime_rec);
1112 #ifdef HAVE_AUTHGSS_FREE_PRIVATE_DATA
1113 if (pd.pd_ctx_hndl.length != 0 || pd.pd_ctx != 0)
1114 authgss_free_private_data(&pd);
1119 clnt_destroy(rpc_clnt);
1123 do_error_downcall(fd, uid, downcall_err);
1128 handle_krb5_upcall(struct clnt_info *clp)
1132 if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) {
1133 printerr(0, "WARNING: failed reading uid from krb5 "
1134 "upcall pipe: %s\n", strerror(errno));
1138 process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
1142 handle_gssd_upcall(struct clnt_info *clp)
1149 char *target = NULL;
1150 char *service = NULL;
1151 char *enctypes = NULL;
1153 printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
1155 if (readline(clp->gssd_fd, &lbuf, &lbuflen) != 1) {
1156 printerr(0, "WARNING: handle_gssd_upcall: "
1157 "failed reading request\n");
1160 printerr(2, "%s: '%s'\n", __func__, lbuf);
1162 /* find the mechanism name */
1163 if ((p = strstr(lbuf, "mech=")) != NULL) {
1164 mech = malloc(lbuflen);
1167 if (sscanf(p, "mech=%s", mech) != 1) {
1168 printerr(0, "WARNING: handle_gssd_upcall: "
1169 "failed to parse gss mechanism name "
1170 "in upcall string '%s'\n", lbuf);
1174 printerr(0, "WARNING: handle_gssd_upcall: "
1175 "failed to find gss mechanism name "
1176 "in upcall string '%s'\n", lbuf);
1181 if ((p = strstr(lbuf, "uid=")) != NULL) {
1182 if (sscanf(p, "uid=%d", &uid) != 1) {
1183 printerr(0, "WARNING: handle_gssd_upcall: "
1184 "failed to parse uid "
1185 "in upcall string '%s'\n", lbuf);
1189 printerr(0, "WARNING: handle_gssd_upcall: "
1190 "failed to find uid "
1191 "in upcall string '%s'\n", lbuf);
1195 /* read supported encryption types if supplied */
1196 if ((p = strstr(lbuf, "enctypes=")) != NULL) {
1197 enctypes = malloc(lbuflen);
1200 if (sscanf(p, "enctypes=%s", enctypes) != 1) {
1201 printerr(0, "WARNING: handle_gssd_upcall: "
1202 "failed to parse encryption types "
1203 "in upcall string '%s'\n", lbuf);
1206 if (parse_enctypes(enctypes) != 0) {
1207 printerr(0, "WARNING: handle_gssd_upcall: "
1208 "parsing encryption types failed: errno %d\n", errno);
1212 /* read target name */
1213 if ((p = strstr(lbuf, "target=")) != NULL) {
1214 target = malloc(lbuflen);
1217 if (sscanf(p, "target=%s", target) != 1) {
1218 printerr(0, "WARNING: handle_gssd_upcall: "
1219 "failed to parse target name "
1220 "in upcall string '%s'\n", lbuf);
1226 * read the service name
1228 * The presence of attribute "service=" indicates that machine
1229 * credentials should be used for this request. If the value
1230 * is "*", then any machine credentials available can be used.
1231 * If the value is anything else, then machine credentials for
1232 * the specified service name (always "nfs" for now) should be
1235 if ((p = strstr(lbuf, "service=")) != NULL) {
1236 service = malloc(lbuflen);
1239 if (sscanf(p, "service=%s", service) != 1) {
1240 printerr(0, "WARNING: handle_gssd_upcall: "
1241 "failed to parse service type "
1242 "in upcall string '%s'\n", lbuf);
1247 if (strcmp(mech, "krb5") == 0)
1248 process_krb5_upcall(clp, uid, clp->gssd_fd, target, service);
1250 printerr(0, "WARNING: handle_gssd_upcall: "
1251 "received unknown gss mech '%s'\n", mech);