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>
74 #include "krb5_util.h"
81 * array of struct pollfd suitable to pass to poll. initialized to
82 * zero - a zero struct is ignored by poll() because the events mask is 0.
85 * linked list of struct clnt_info which associates a clntXXX directory
86 * with an index into pollarray[], and other basic data about that client.
88 * Directory structure: created by the kernel
89 * {rpc_pipefs}/{dir}/clntXX : one per rpc_clnt struct in the kernel
90 * {rpc_pipefs}/{dir}/clntXX/krb5 : read uid for which kernel wants
91 * a context, write the resulting context
92 * {rpc_pipefs}/{dir}/clntXX/info : stores info such as server name
93 * {rpc_pipefs}/{dir}/clntXX/gssd : pipe for all gss mechanisms using
94 * a text-based string of parameters
97 * Poll all {rpc_pipefs}/{dir}/clntXX/YYYY files. When data is ready,
98 * read and process; performs rpcsec_gss context initialization protocol to
99 * get a cred for that user. Writes result to corresponding krb5 file
100 * in a form the kernel code will understand.
101 * In addition, we make sure we are notified whenever anything is
102 * created or destroyed in {rpc_pipefs} or in any of the clntXX directories,
103 * and rescan the whole {rpc_pipefs} when this happens.
106 struct pollfd * pollarray;
108 unsigned long pollsize; /* the size of pollaray (in pollfd's) */
111 * convert a presentation address string to a sockaddr_storage struct. Returns
112 * true on success or false on failure.
114 * Note that we do not populate the sin6_scope_id field here for IPv6 addrs.
115 * gssd nececessarily relies on hostname resolution and DNS AAAA records
116 * do not generally contain scope-id's. This means that GSSAPI auth really
117 * can't work with IPv6 link-local addresses.
119 * We *could* consider changing this if we did something like adopt the
120 * Microsoft "standard" of using the ipv6-literal.net domainname, but it's
121 * not really feasible at present.
124 addrstr_to_sockaddr(struct sockaddr *sa, const char *node, const char *port)
127 struct addrinfo *res;
128 struct addrinfo hints = { .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV };
130 #ifndef IPV6_SUPPORTED
131 hints.ai_family = AF_INET;
132 #endif /* IPV6_SUPPORTED */
134 rc = getaddrinfo(node, port, &hints, &res);
136 printerr(0, "ERROR: unable to convert %s|%s to sockaddr: %s\n",
137 node, port, rc == EAI_SYSTEM ? strerror(errno) :
142 #ifdef IPV6_SUPPORTED
144 * getnameinfo ignores the scopeid. If the address turns out to have
145 * a non-zero scopeid, we can't use it -- the resolved host might be
146 * completely different from the one intended.
148 if (res->ai_addr->sa_family == AF_INET6) {
149 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)res->ai_addr;
150 if (sin6->sin6_scope_id) {
151 printerr(0, "ERROR: address %s has non-zero "
152 "sin6_scope_id!\n", node);
157 #endif /* IPV6_SUPPORTED */
159 memcpy(sa, res->ai_addr, res->ai_addrlen);
165 * convert a sockaddr to a hostname
168 sockaddr_to_hostname(const struct sockaddr *sa, const char *addr)
173 char hbuf[NI_MAXHOST];
175 switch (sa->sa_family) {
177 addrlen = sizeof(struct sockaddr_in);
179 #ifdef IPV6_SUPPORTED
181 addrlen = sizeof(struct sockaddr_in6);
183 #endif /* IPV6_SUPPORTED */
185 printerr(0, "ERROR: unrecognized addr family %d\n",
190 err = getnameinfo(sa, addrlen, hbuf, sizeof(hbuf), NULL, 0,
193 printerr(0, "ERROR: unable to resolve %s to hostname: %s\n",
194 addr, err == EAI_SYSTEM ? strerror(err) :
199 hostname = strdup(hbuf);
204 /* XXX buffer problems: */
206 read_service_info(char *info_file_name, char **servicename, char **servername,
207 int *prog, int *vers, char **protocol,
208 struct sockaddr *addr) {
209 #define INFOBUFLEN 256
210 char buf[INFOBUFLEN + 1];
211 static char dummy[128];
213 static char service[128];
214 static char address[128];
223 *servicename = *servername = *protocol = NULL;
225 if ((fd = open(info_file_name, O_RDONLY)) == -1) {
226 printerr(0, "ERROR: can't open %s: %s\n", info_file_name,
230 if ((nbytes = read(fd, buf, INFOBUFLEN)) == -1)
235 numfields = sscanf(buf,"RPC server: %127s\n"
236 "service: %127s %15s version %15s\n"
240 service, program, version,
244 if (numfields == 5) {
245 strcpy(protoname, "tcp");
246 } else if (numfields != 6) {
251 if ((p = strstr(buf, "port")) != NULL)
252 sscanf(p, "port: %127s\n", port);
254 /* get program, and version numbers */
255 *prog = atoi(program + 1); /* skip open paren */
256 *vers = atoi(version);
258 if (!addrstr_to_sockaddr(addr, address, port))
261 *servername = sockaddr_to_hostname(addr, address);
262 if (*servername == NULL)
265 nbytes = snprintf(buf, INFOBUFLEN, "%s@%s", service, *servername);
266 if (nbytes > INFOBUFLEN)
269 if (!(*servicename = calloc(strlen(buf) + 1, 1)))
271 memcpy(*servicename, buf, strlen(buf));
273 if (!(*protocol = strdup(protoname)))
277 printerr(0, "ERROR: failed to read service info\n");
278 if (fd != -1) close(fd);
282 *servicename = *servername = *protocol = NULL;
287 destroy_client(struct clnt_info *clp)
289 if (clp->krb5_poll_index != -1)
290 memset(&pollarray[clp->krb5_poll_index], 0,
291 sizeof(struct pollfd));
292 if (clp->gssd_poll_index != -1)
293 memset(&pollarray[clp->gssd_poll_index], 0,
294 sizeof(struct pollfd));
295 if (clp->dir_fd != -1) close(clp->dir_fd);
296 if (clp->krb5_fd != -1) close(clp->krb5_fd);
297 if (clp->gssd_fd != -1) close(clp->gssd_fd);
299 free(clp->servicename);
300 free(clp->servername);
305 static struct clnt_info *
306 insert_new_clnt(void)
308 struct clnt_info *clp = NULL;
310 if (!(clp = (struct clnt_info *)calloc(1,sizeof(struct clnt_info)))) {
311 printerr(0, "ERROR: can't malloc clnt_info: %s\n",
315 clp->krb5_poll_index = -1;
316 clp->gssd_poll_index = -1;
321 TAILQ_INSERT_HEAD(&clnt_list, clp, list);
327 process_clnt_dir_files(struct clnt_info * clp)
330 char gname[PATH_MAX];
331 char info_file_name[PATH_MAX];
333 if (clp->gssd_close_me) {
334 printerr(2, "Closing 'gssd' pipe for %s\n", clp->dirname);
336 memset(&pollarray[clp->gssd_poll_index], 0,
337 sizeof(struct pollfd));
339 clp->gssd_poll_index = -1;
340 clp->gssd_close_me = 0;
342 if (clp->krb5_close_me) {
343 printerr(2, "Closing 'krb5' pipe for %s\n", clp->dirname);
345 memset(&pollarray[clp->krb5_poll_index], 0,
346 sizeof(struct pollfd));
348 clp->krb5_poll_index = -1;
349 clp->krb5_close_me = 0;
352 if (clp->gssd_fd == -1) {
353 snprintf(gname, sizeof(gname), "%s/gssd", clp->dirname);
354 clp->gssd_fd = open(gname, O_RDWR);
356 if (clp->gssd_fd == -1) {
357 if (clp->krb5_fd == -1) {
358 snprintf(name, sizeof(name), "%s/krb5", clp->dirname);
359 clp->krb5_fd = open(name, O_RDWR);
362 /* If we opened a gss-specific pipe, let's try opening
363 * the new upcall pipe again. If we succeed, close
364 * gss-specific pipe(s).
366 if (clp->krb5_fd != -1) {
367 clp->gssd_fd = open(gname, O_RDWR);
368 if (clp->gssd_fd != -1) {
369 if (clp->krb5_fd != -1)
376 if ((clp->krb5_fd == -1) && (clp->gssd_fd == -1))
378 snprintf(info_file_name, sizeof(info_file_name), "%s/info",
380 if ((clp->servicename == NULL) &&
381 read_service_info(info_file_name, &clp->servicename,
382 &clp->servername, &clp->prog, &clp->vers,
383 &clp->protocol, (struct sockaddr *) &clp->addr))
389 get_poll_index(int *ind)
394 for (i=0; i<pollsize; i++) {
395 if (pollarray[i].events == 0) {
401 printerr(0, "ERROR: No pollarray slots open\n");
409 insert_clnt_poll(struct clnt_info *clp)
411 if ((clp->gssd_fd != -1) && (clp->gssd_poll_index == -1)) {
412 if (get_poll_index(&clp->gssd_poll_index)) {
413 printerr(0, "ERROR: Too many gssd clients\n");
416 pollarray[clp->gssd_poll_index].fd = clp->gssd_fd;
417 pollarray[clp->gssd_poll_index].events |= POLLIN;
420 if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
421 if (get_poll_index(&clp->krb5_poll_index)) {
422 printerr(0, "ERROR: Too many krb5 clients\n");
425 pollarray[clp->krb5_poll_index].fd = clp->krb5_fd;
426 pollarray[clp->krb5_poll_index].events |= POLLIN;
433 process_clnt_dir(char *dir, char *pdir)
435 struct clnt_info * clp;
437 if (!(clp = insert_new_clnt()))
438 goto fail_destroy_client;
440 /* An extra for the '/', and an extra for the null */
441 if (!(clp->dirname = calloc(strlen(dir) + strlen(pdir) + 2, 1))) {
442 goto fail_destroy_client;
444 sprintf(clp->dirname, "%s/%s", pdir, dir);
445 if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
446 printerr(0, "ERROR: can't open %s: %s\n",
447 clp->dirname, strerror(errno));
448 goto fail_destroy_client;
450 fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL);
451 fcntl(clp->dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MULTISHOT);
453 if (process_clnt_dir_files(clp))
454 goto fail_keep_client;
456 if (insert_clnt_poll(clp))
457 goto fail_destroy_client;
463 TAILQ_REMOVE(&clnt_list, clp, list);
467 /* We couldn't find some subdirectories, but we keep the client
468 * around in case we get a notification on the directory when the
469 * subdirectories are created. */
474 init_client_list(void)
477 TAILQ_INIT(&clnt_list);
478 /* Eventually plan to grow/shrink poll array: */
479 pollsize = FD_ALLOC_BLOCK;
480 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0 &&
481 rlim.rlim_cur != RLIM_INFINITY)
482 pollsize = rlim.rlim_cur;
483 pollarray = calloc(pollsize, sizeof(struct pollfd));
487 * This is run after a DNOTIFY signal, and should clear up any
488 * directories that are no longer around, and re-scan any existing
489 * directories, since the DNOTIFY could have been in there.
492 update_old_clients(struct dirent **namelist, int size, char *pdir)
494 struct clnt_info *clp;
497 char fname[PATH_MAX];
499 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
500 /* only compare entries in the global list that are from the
501 * same pipefs parent directory as "pdir"
503 if (strncmp(clp->dirname, pdir, strlen(pdir)) != 0) continue;
506 for (i=0; i < size; i++) {
507 snprintf(fname, sizeof(fname), "%s/%s",
508 pdir, namelist[i]->d_name);
509 if (strcmp(clp->dirname, fname) == 0) {
515 printerr(2, "destroying client %s\n", clp->dirname);
516 saveprev = clp->list.tqe_prev;
517 TAILQ_REMOVE(&clnt_list, clp, list);
522 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
523 if (!process_clnt_dir_files(clp))
524 insert_clnt_poll(clp);
528 /* Search for a client by directory name, return 1 if found, 0 otherwise */
530 find_client(char *dirname, char *pdir)
532 struct clnt_info *clp;
533 char fname[PATH_MAX];
535 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
536 snprintf(fname, sizeof(fname), "%s/%s", pdir, dirname);
537 if (strcmp(clp->dirname, fname) == 0)
544 process_pipedir(char *pipe_name)
546 struct dirent **namelist;
549 if (chdir(pipe_name) < 0) {
550 printerr(0, "ERROR: can't chdir to %s: %s\n",
551 pipe_name, strerror(errno));
555 j = scandir(pipe_name, &namelist, NULL, alphasort);
557 printerr(0, "ERROR: can't scandir %s: %s\n",
558 pipe_name, strerror(errno));
562 update_old_clients(namelist, j, pipe_name);
563 for (i=0; i < j; i++) {
564 if (!strncmp(namelist[i]->d_name, "clnt", 4)
565 && !find_client(namelist[i]->d_name, pipe_name))
566 process_clnt_dir(namelist[i]->d_name, pipe_name);
575 /* Used to read (and re-read) list of clients, set up poll array. */
577 update_client_list(void)
580 struct topdirs_info *tdi;
582 TAILQ_FOREACH(tdi, &topdirs_list, list) {
583 retval = process_pipedir(tdi->dirname);
585 printerr(1, "WARNING: error processing %s\n",
592 /* Encryption types supported by the kernel rpcsec_gss code */
593 int num_krb5_enctypes = 0;
594 krb5_enctype *krb5_enctypes = NULL;
597 * Parse the supported encryption type information
600 parse_enctypes(char *enctypes)
605 static char *cached_types;
607 if (cached_types && strcmp(cached_types, enctypes) == 0)
611 if (krb5_enctypes != NULL) {
613 krb5_enctypes = NULL;
614 num_krb5_enctypes = 0;
617 /* count the number of commas */
618 for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
619 comma = strchr(curr, ',');
625 /* If no more commas and we're not at the end, there's one more value */
629 /* Empty string, return an error */
633 /* Allocate space for enctypes array */
634 if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
638 /* Now parse each value into the array */
639 for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) {
640 krb5_enctypes[i++] = atoi(curr);
641 comma = strchr(curr, ',');
646 num_krb5_enctypes = n;
647 if ((cached_types = malloc(strlen(enctypes)+1)))
648 strcpy(cached_types, enctypes);
654 do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
655 gss_buffer_desc *context_token, OM_uint32 lifetime_rec)
657 char *buf = NULL, *p = NULL, *end = NULL;
658 unsigned int timeout = context_timeout;
659 unsigned int buf_size = 0;
661 printerr(1, "doing downcall lifetime_rec %u\n", lifetime_rec);
662 buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) +
663 sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length +
664 sizeof(context_token->length) + context_token->length;
665 p = buf = malloc(buf_size);
666 end = buf + buf_size;
668 /* context_timeout set by -t option overrides context lifetime */
670 timeout = lifetime_rec;
671 if (WRITE_BYTES(&p, end, uid)) goto out_err;
672 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
673 if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err;
674 if (write_buffer(&p, end, &pd->pd_ctx_hndl)) goto out_err;
675 if (write_buffer(&p, end, context_token)) goto out_err;
677 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
682 printerr(1, "Failed to write downcall!\n");
687 do_error_downcall(int k5_fd, uid_t uid, int err)
690 char *p = buf, *end = buf + 1024;
691 unsigned int timeout = 0;
694 printerr(1, "doing error downcall\n");
696 if (WRITE_BYTES(&p, end, uid)) goto out_err;
697 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
698 /* use seq_win = 0 to indicate an error: */
699 if (WRITE_BYTES(&p, end, zero)) goto out_err;
700 if (WRITE_BYTES(&p, end, err)) goto out_err;
702 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
705 printerr(1, "Failed to write error downcall!\n");
710 * If the port isn't already set, do an rpcbind query to the remote server
711 * using the program and version and get the port.
713 * Newer kernels send the value of the port= mount option in the "info"
714 * file for the upcall or '0' for NFSv2/3. For NFSv4 it sends the value
715 * of the port= option or '2049'. The port field in a new sockaddr should
716 * reflect the value that was sent by the kernel.
719 populate_port(struct sockaddr *sa, const socklen_t salen,
720 const rpcprog_t program, const rpcvers_t version,
721 const unsigned short protocol)
723 struct sockaddr_in *s4 = (struct sockaddr_in *) sa;
724 #ifdef IPV6_SUPPORTED
725 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa;
726 #endif /* IPV6_SUPPORTED */
730 * Newer kernels send the port in the upcall. If we already have
731 * the port, there's no need to look it up.
733 switch (sa->sa_family) {
735 if (s4->sin_port != 0) {
736 printerr(2, "DEBUG: port already set to %d\n",
737 ntohs(s4->sin_port));
741 #ifdef IPV6_SUPPORTED
743 if (s6->sin6_port != 0) {
744 printerr(2, "DEBUG: port already set to %d\n",
745 ntohs(s6->sin6_port));
749 #endif /* IPV6_SUPPORTED */
751 printerr(0, "ERROR: unsupported address family %d\n",
757 * Newer kernels that send the port in the upcall set the value to
758 * 2049 for NFSv4 mounts when one isn't specified. The check below is
759 * only for kernels that don't send the port in the upcall. For those
760 * we either have to do an rpcbind query or set it to the standard
761 * port. Doing a query could be problematic (firewalls, etc), so take
762 * the latter approach.
764 if (program == 100003 && version == 4) {
769 port = nfs_getport(sa, salen, program, version, protocol);
771 printerr(0, "ERROR: unable to obtain port for prog %ld "
772 "vers %ld\n", program, version);
777 printerr(2, "DEBUG: setting port to %hu for prog %lu vers %lu\n", port,
780 switch (sa->sa_family) {
782 s4->sin_port = htons(port);
784 #ifdef IPV6_SUPPORTED
786 s6->sin6_port = htons(port);
788 #endif /* IPV6_SUPPORTED */
795 * Create an RPC connection and establish an authenticated
796 * gss context with a server.
799 create_auth_rpc_client(struct clnt_info *clp,
800 CLIENT **clnt_return,
805 CLIENT *rpc_clnt = NULL;
806 struct rpc_gss_sec sec;
811 char rpc_errmsg[1024];
813 struct timeval timeout = {5, 0};
814 struct sockaddr *addr = (struct sockaddr *) &clp->addr;
817 /* Create the context as the user (not as root) */
818 save_uid = geteuid();
819 if (setfsuid(uid) != 0) {
820 printerr(0, "WARNING: Failed to setfsuid for "
821 "user with uid %d\n", uid);
824 printerr(2, "creating context using fsuid %d (save_uid %d)\n",
827 sec.qop = GSS_C_QOP_DEFAULT;
828 sec.svc = RPCSEC_GSS_SVC_NONE;
829 sec.cred = GSS_C_NO_CREDENTIAL;
831 if (authtype == AUTHTYPE_KRB5) {
832 sec.mech = (gss_OID)&krb5oid;
833 sec.req_flags = GSS_C_MUTUAL_FLAG;
836 printerr(0, "ERROR: Invalid authentication type (%d) "
837 "in create_auth_rpc_client\n", authtype);
842 if (authtype == AUTHTYPE_KRB5) {
843 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
845 * Do this before creating rpc connection since we won't need
846 * rpc connection if it fails!
848 if (limit_krb5_enctypes(&sec)) {
849 printerr(1, "WARNING: Failed while limiting krb5 "
850 "encryption types for user with uid %d\n",
857 /* create an rpc connection to the nfs server */
859 printerr(2, "creating %s client for server %s\n", clp->protocol,
862 if ((strcmp(clp->protocol, "tcp")) == 0) {
863 protocol = IPPROTO_TCP;
864 } else if ((strcmp(clp->protocol, "udp")) == 0) {
865 protocol = IPPROTO_UDP;
867 printerr(0, "WARNING: unrecognized protocol, '%s', requested "
868 "for connection to server %s for user with uid %d\n",
869 clp->protocol, clp->servername, uid);
873 switch (addr->sa_family) {
875 salen = sizeof(struct sockaddr_in);
877 #ifdef IPV6_SUPPORTED
879 salen = sizeof(struct sockaddr_in6);
881 #endif /* IPV6_SUPPORTED */
883 printerr(1, "ERROR: Unknown address family %d\n",
888 if (!populate_port(addr, salen, clp->prog, clp->vers, protocol))
891 rpc_clnt = nfs_get_rpcclient(addr, salen, protocol, clp->prog,
892 clp->vers, &timeout);
894 snprintf(rpc_errmsg, sizeof(rpc_errmsg),
895 "WARNING: can't create %s rpc_clnt to server %s for "
897 protocol == IPPROTO_TCP ? "tcp" : "udp",
898 clp->servername, uid);
900 clnt_spcreateerror(rpc_errmsg));
904 printerr(2, "creating context with server %s\n", clp->servicename);
905 auth = authgss_create_default(rpc_clnt, clp->servicename, &sec);
907 /* Our caller should print appropriate message */
908 printerr(2, "WARNING: Failed to create krb5 context for "
909 "user with uid %d for server %s\n",
910 uid, clp->servername);
915 rpc_clnt->cl_auth = auth;
916 *clnt_return = rpc_clnt;
921 if (sec.cred != GSS_C_NO_CREDENTIAL)
922 gss_release_cred(&min_stat, &sec.cred);
923 /* Restore euid to original value */
924 if (((int)save_uid != -1) && (setfsuid(save_uid) != (int)uid)) {
925 printerr(0, "WARNING: Failed to restore fsuid"
926 " to uid %d from %d\n", save_uid, uid);
931 /* Only destroy here if failure. Otherwise, caller is responsible */
932 if (rpc_clnt) clnt_destroy(rpc_clnt);
938 * this code uses the userland rpcsec gss library to create a krb5
939 * context on behalf of the kernel
942 process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
945 CLIENT *rpc_clnt = NULL;
947 struct authgss_private_data pd;
948 gss_buffer_desc token;
949 char **credlist = NULL;
952 int create_resp = -1;
953 int err, downcall_err = -EACCES;
954 OM_uint32 maj_stat, min_stat, lifetime_rec;
956 printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
960 memset(&pd, 0, sizeof(struct authgss_private_data));
963 * If "service" is specified, then the kernel is indicating that
964 * we must use machine credentials for this request. (Regardless
965 * of the uid value or the setting of root_uses_machine_creds.)
966 * If the service value is "*", then any service name can be used.
967 * Otherwise, it specifies the service name that should be used.
968 * (For now, the values of service will only be "*" or "nfs".)
970 * Restricting gssd to use "nfs" service name is needed for when
971 * the NFS server is doing a callback to the NFS client. In this
972 * case, the NFS server has to authenticate itself as "nfs" --
973 * even if there are other service keys such as "host" or "root"
976 * Another case when the kernel may specify the service attribute
977 * is when gssd is being asked to create the context for a
978 * SETCLIENT_ID operation. In this case, machine credentials
979 * must be used for the authentication. However, the service name
980 * used for this case is not important.
983 printerr(2, "%s: service is '%s'\n", __func__,
984 service ? service : "<null>");
985 if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
987 /* Tell krb5 gss which credentials cache to use */
988 for (dirname = ccachesearch; *dirname != NULL; dirname++) {
989 err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname);
990 if (err == -EKEYEXPIRED)
991 downcall_err = -EKEYEXPIRED;
993 create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
995 if (create_resp == 0)
999 if (create_resp != 0) {
1000 if (uid == 0 && (root_uses_machine_creds == 1 ||
1005 gssd_refresh_krb5_machine_credential(clp->servername,
1009 * Get a list of credential cache names and try each
1010 * of them until one works or we've tried them all
1012 if (gssd_get_krb5_machine_cred_list(&credlist)) {
1013 printerr(0, "ERROR: No credentials found "
1014 "for connection to server %s\n",
1016 goto out_return_error;
1018 for (ccname = credlist; ccname && *ccname; ccname++) {
1019 gssd_setup_krb5_machine_gss_ccache(*ccname);
1020 if ((create_auth_rpc_client(clp, &rpc_clnt,
1022 AUTHTYPE_KRB5)) == 0) {
1027 printerr(2, "WARNING: Failed to create machine krb5 context "
1028 "with credentials cache %s for server %s\n",
1029 *ccname, clp->servername);
1031 gssd_free_krb5_machine_cred_list(credlist);
1035 printerr(2, "WARNING: Machine cache is prematurely expired or corrupted "
1036 "trying to recreate cache for server %s\n", clp->servername);
1038 printerr(1, "WARNING: Failed to create machine krb5 context "
1039 "with any credentials cache for server %s\n",
1041 goto out_return_error;
1046 printerr(1, "WARNING: Failed to create krb5 context "
1047 "for user with uid %d for server %s\n",
1048 uid, clp->servername);
1049 goto out_return_error;
1053 if (!authgss_get_private_data(auth, &pd)) {
1054 printerr(1, "WARNING: Failed to obtain authentication "
1055 "data for user with uid %d for server %s\n",
1056 uid, clp->servername);
1057 goto out_return_error;
1060 /* Grab the context lifetime to pass to the kernel. lifetime_rec
1061 * is set to zero on error */
1062 maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, NULL,
1063 &lifetime_rec, NULL, NULL, NULL, NULL);
1066 printerr(1, "WARNING: Failed to inquire context for lifetme "
1067 "maj_stat %u\n", maj_stat);
1069 if (serialize_context_for_kernel(pd.pd_ctx, &token, &krb5oid, NULL)) {
1070 printerr(0, "WARNING: Failed to serialize krb5 context for "
1071 "user with uid %d for server %s\n",
1072 uid, clp->servername);
1073 goto out_return_error;
1076 do_downcall(fd, uid, &pd, &token, lifetime_rec);
1081 #ifndef HAVE_LIBTIRPC
1082 if (pd.pd_ctx_hndl.length != 0)
1083 authgss_free_private_data(&pd);
1088 clnt_destroy(rpc_clnt);
1092 do_error_downcall(fd, uid, downcall_err);
1097 handle_krb5_upcall(struct clnt_info *clp)
1101 if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) {
1102 printerr(0, "WARNING: failed reading uid from krb5 "
1103 "upcall pipe: %s\n", strerror(errno));
1107 process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
1111 handle_gssd_upcall(struct clnt_info *clp)
1118 char *target = NULL;
1119 char *service = NULL;
1120 char *enctypes = NULL;
1122 printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
1124 if (readline(clp->gssd_fd, &lbuf, &lbuflen) != 1) {
1125 printerr(0, "WARNING: handle_gssd_upcall: "
1126 "failed reading request\n");
1129 printerr(2, "%s: '%s'\n", __func__, lbuf);
1131 /* find the mechanism name */
1132 if ((p = strstr(lbuf, "mech=")) != NULL) {
1133 mech = malloc(lbuflen);
1136 if (sscanf(p, "mech=%s", mech) != 1) {
1137 printerr(0, "WARNING: handle_gssd_upcall: "
1138 "failed to parse gss mechanism name "
1139 "in upcall string '%s'\n", lbuf);
1143 printerr(0, "WARNING: handle_gssd_upcall: "
1144 "failed to find gss mechanism name "
1145 "in upcall string '%s'\n", lbuf);
1150 if ((p = strstr(lbuf, "uid=")) != NULL) {
1151 if (sscanf(p, "uid=%d", &uid) != 1) {
1152 printerr(0, "WARNING: handle_gssd_upcall: "
1153 "failed to parse uid "
1154 "in upcall string '%s'\n", lbuf);
1158 printerr(0, "WARNING: handle_gssd_upcall: "
1159 "failed to find uid "
1160 "in upcall string '%s'\n", lbuf);
1164 /* read supported encryption types if supplied */
1165 if ((p = strstr(lbuf, "enctypes=")) != NULL) {
1166 enctypes = malloc(lbuflen);
1169 if (sscanf(p, "enctypes=%s", enctypes) != 1) {
1170 printerr(0, "WARNING: handle_gssd_upcall: "
1171 "failed to parse encryption types "
1172 "in upcall string '%s'\n", lbuf);
1175 if (parse_enctypes(enctypes) != 0) {
1176 printerr(0, "WARNING: handle_gssd_upcall: "
1177 "parsing encryption types failed: errno %d\n", errno);
1181 /* read target name */
1182 if ((p = strstr(lbuf, "target=")) != NULL) {
1183 target = malloc(lbuflen);
1186 if (sscanf(p, "target=%s", target) != 1) {
1187 printerr(0, "WARNING: handle_gssd_upcall: "
1188 "failed to parse target name "
1189 "in upcall string '%s'\n", lbuf);
1195 * read the service name
1197 * The presence of attribute "service=" indicates that machine
1198 * credentials should be used for this request. If the value
1199 * is "*", then any machine credentials available can be used.
1200 * If the value is anything else, then machine credentials for
1201 * the specified service name (always "nfs" for now) should be
1204 if ((p = strstr(lbuf, "service=")) != NULL) {
1205 service = malloc(lbuflen);
1208 if (sscanf(p, "service=%s", service) != 1) {
1209 printerr(0, "WARNING: handle_gssd_upcall: "
1210 "failed to parse service type "
1211 "in upcall string '%s'\n", lbuf);
1216 if (strcmp(mech, "krb5") == 0)
1217 process_krb5_upcall(clp, uid, clp->gssd_fd, target, service);
1219 printerr(0, "WARNING: handle_gssd_upcall: "
1220 "received unknown gss mech '%s'\n", mech);