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 int 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->spkm3_poll_index != -1)
303 memset(&pollarray[clp->spkm3_poll_index], 0,
304 sizeof(struct pollfd));
305 if (clp->gssd_poll_index != -1)
306 memset(&pollarray[clp->gssd_poll_index], 0,
307 sizeof(struct pollfd));
308 if (clp->dir_fd != -1) close(clp->dir_fd);
309 if (clp->krb5_fd != -1) close(clp->krb5_fd);
310 if (clp->spkm3_fd != -1) close(clp->spkm3_fd);
311 if (clp->gssd_fd != -1) close(clp->gssd_fd);
313 free(clp->servicename);
314 free(clp->servername);
319 static struct clnt_info *
320 insert_new_clnt(void)
322 struct clnt_info *clp = NULL;
324 if (!(clp = (struct clnt_info *)calloc(1,sizeof(struct clnt_info)))) {
325 printerr(0, "ERROR: can't malloc clnt_info: %s\n",
329 clp->krb5_poll_index = -1;
330 clp->spkm3_poll_index = -1;
331 clp->gssd_poll_index = -1;
337 TAILQ_INSERT_HEAD(&clnt_list, clp, list);
343 process_clnt_dir_files(struct clnt_info * clp)
346 char gname[PATH_MAX];
347 char info_file_name[PATH_MAX];
349 if (clp->gssd_fd == -1) {
350 snprintf(gname, sizeof(gname), "%s/gssd", clp->dirname);
351 clp->gssd_fd = open(gname, O_RDWR);
353 if (clp->gssd_fd == -1) {
354 if (clp->krb5_fd == -1) {
355 snprintf(name, sizeof(name), "%s/krb5", clp->dirname);
356 clp->krb5_fd = open(name, O_RDWR);
358 if (clp->spkm3_fd == -1) {
359 snprintf(name, sizeof(name), "%s/spkm3", clp->dirname);
360 clp->spkm3_fd = open(name, O_RDWR);
363 /* If we opened a gss-specific pipe, let's try opening
364 * the new upcall pipe again. If we succeed, close
365 * gss-specific pipe(s).
367 if (clp->krb5_fd != -1 || clp->spkm3_fd != -1) {
368 clp->gssd_fd = open(gname, O_RDWR);
369 if (clp->gssd_fd != -1) {
370 if (clp->krb5_fd != -1)
373 if (clp->spkm3_fd != -1)
374 close(clp->spkm3_fd);
380 if ((clp->krb5_fd == -1) && (clp->spkm3_fd == -1) &&
381 (clp->gssd_fd == -1))
383 snprintf(info_file_name, sizeof(info_file_name), "%s/info",
385 if ((clp->servicename == NULL) &&
386 read_service_info(info_file_name, &clp->servicename,
387 &clp->servername, &clp->prog, &clp->vers,
388 &clp->protocol, (struct sockaddr *) &clp->addr))
394 get_poll_index(int *ind)
399 for (i=0; i<FD_ALLOC_BLOCK; i++) {
400 if (pollarray[i].events == 0) {
406 printerr(0, "ERROR: No pollarray slots open\n");
414 insert_clnt_poll(struct clnt_info *clp)
416 if ((clp->gssd_fd != -1) && (clp->gssd_poll_index == -1)) {
417 if (get_poll_index(&clp->gssd_poll_index)) {
418 printerr(0, "ERROR: Too many gssd clients\n");
421 pollarray[clp->gssd_poll_index].fd = clp->gssd_fd;
422 pollarray[clp->gssd_poll_index].events |= POLLIN;
425 if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
426 if (get_poll_index(&clp->krb5_poll_index)) {
427 printerr(0, "ERROR: Too many krb5 clients\n");
430 pollarray[clp->krb5_poll_index].fd = clp->krb5_fd;
431 pollarray[clp->krb5_poll_index].events |= POLLIN;
434 if ((clp->spkm3_fd != -1) && (clp->spkm3_poll_index == -1)) {
435 if (get_poll_index(&clp->spkm3_poll_index)) {
436 printerr(0, "ERROR: Too many spkm3 clients\n");
439 pollarray[clp->spkm3_poll_index].fd = clp->spkm3_fd;
440 pollarray[clp->spkm3_poll_index].events |= POLLIN;
447 process_clnt_dir(char *dir, char *pdir)
449 struct clnt_info * clp;
451 if (!(clp = insert_new_clnt()))
452 goto fail_destroy_client;
454 /* An extra for the '/', and an extra for the null */
455 if (!(clp->dirname = calloc(strlen(dir) + strlen(pdir) + 2, 1))) {
456 goto fail_destroy_client;
458 sprintf(clp->dirname, "%s/%s", pdir, dir);
459 if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
460 printerr(0, "ERROR: can't open %s: %s\n",
461 clp->dirname, strerror(errno));
462 goto fail_destroy_client;
464 fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL);
465 fcntl(clp->dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MULTISHOT);
467 if (process_clnt_dir_files(clp))
468 goto fail_keep_client;
470 if (insert_clnt_poll(clp))
471 goto fail_destroy_client;
477 TAILQ_REMOVE(&clnt_list, clp, list);
481 /* We couldn't find some subdirectories, but we keep the client
482 * around in case we get a notification on the directory when the
483 * subdirectories are created. */
488 init_client_list(void)
490 TAILQ_INIT(&clnt_list);
491 /* Eventually plan to grow/shrink poll array: */
492 pollsize = FD_ALLOC_BLOCK;
493 pollarray = calloc(pollsize, sizeof(struct pollfd));
497 * This is run after a DNOTIFY signal, and should clear up any
498 * directories that are no longer around, and re-scan any existing
499 * directories, since the DNOTIFY could have been in there.
502 update_old_clients(struct dirent **namelist, int size, char *pdir)
504 struct clnt_info *clp;
507 char fname[PATH_MAX];
509 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
510 /* only compare entries in the global list that are from the
511 * same pipefs parent directory as "pdir"
513 if (strncmp(clp->dirname, pdir, strlen(pdir)) != 0) continue;
516 for (i=0; i < size; i++) {
517 snprintf(fname, sizeof(fname), "%s/%s",
518 pdir, namelist[i]->d_name);
519 if (strcmp(clp->dirname, fname) == 0) {
525 printerr(2, "destroying client %s\n", clp->dirname);
526 saveprev = clp->list.tqe_prev;
527 TAILQ_REMOVE(&clnt_list, clp, list);
532 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
533 if (!process_clnt_dir_files(clp))
534 insert_clnt_poll(clp);
538 /* Search for a client by directory name, return 1 if found, 0 otherwise */
540 find_client(char *dirname, char *pdir)
542 struct clnt_info *clp;
543 char fname[PATH_MAX];
545 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
546 snprintf(fname, sizeof(fname), "%s/%s", pdir, dirname);
547 if (strcmp(clp->dirname, fname) == 0)
554 process_pipedir(char *pipe_name)
556 struct dirent **namelist;
559 if (chdir(pipe_name) < 0) {
560 printerr(0, "ERROR: can't chdir to %s: %s\n",
561 pipe_name, strerror(errno));
565 j = scandir(pipe_name, &namelist, NULL, alphasort);
567 printerr(0, "ERROR: can't scandir %s: %s\n",
568 pipe_name, strerror(errno));
572 update_old_clients(namelist, j, pipe_name);
573 for (i=0; i < j; i++) {
574 if (i < FD_ALLOC_BLOCK
575 && !strncmp(namelist[i]->d_name, "clnt", 4)
576 && !find_client(namelist[i]->d_name, pipe_name))
577 process_clnt_dir(namelist[i]->d_name, pipe_name);
586 /* Used to read (and re-read) list of clients, set up poll array. */
588 update_client_list(void)
591 struct topdirs_info *tdi;
593 TAILQ_FOREACH(tdi, &topdirs_list, list) {
594 retval = process_pipedir(tdi->dirname);
596 printerr(1, "WARNING: error processing %s\n",
603 /* Encryption types supported by the kernel rpcsec_gss code */
604 int num_krb5_enctypes = 0;
605 krb5_enctype *krb5_enctypes = NULL;
608 * Parse the supported encryption type information
611 parse_enctypes(char *enctypes)
616 static char *cached_types;
618 if (cached_types && strcmp(cached_types, enctypes) == 0)
622 if (krb5_enctypes != NULL) {
624 krb5_enctypes = NULL;
625 num_krb5_enctypes = 0;
628 /* count the number of commas */
629 for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
630 comma = strchr(curr, ',');
636 /* If no more commas and we're not at the end, there's one more value */
640 /* Empty string, return an error */
644 /* Allocate space for enctypes array */
645 if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
649 /* Now parse each value into the array */
650 for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) {
651 krb5_enctypes[i++] = atoi(curr);
652 comma = strchr(curr, ',');
657 num_krb5_enctypes = n;
658 if ((cached_types = malloc(strlen(enctypes)+1)))
659 strcpy(cached_types, enctypes);
665 do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
666 gss_buffer_desc *context_token)
668 char *buf = NULL, *p = NULL, *end = NULL;
669 unsigned int timeout = context_timeout;
670 unsigned int buf_size = 0;
672 printerr(1, "doing downcall\n");
673 buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) +
674 sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length +
675 sizeof(context_token->length) + context_token->length;
676 p = buf = malloc(buf_size);
677 end = buf + buf_size;
679 if (WRITE_BYTES(&p, end, uid)) goto out_err;
680 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
681 if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err;
682 if (write_buffer(&p, end, &pd->pd_ctx_hndl)) goto out_err;
683 if (write_buffer(&p, end, context_token)) goto out_err;
685 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
690 printerr(1, "Failed to write downcall!\n");
695 do_error_downcall(int k5_fd, uid_t uid, int err)
698 char *p = buf, *end = buf + 1024;
699 unsigned int timeout = 0;
702 printerr(1, "doing error downcall\n");
704 if (WRITE_BYTES(&p, end, uid)) goto out_err;
705 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
706 /* use seq_win = 0 to indicate an error: */
707 if (WRITE_BYTES(&p, end, zero)) goto out_err;
708 if (WRITE_BYTES(&p, end, err)) goto out_err;
710 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
713 printerr(1, "Failed to write error downcall!\n");
718 * If the port isn't already set, do an rpcbind query to the remote server
719 * using the program and version and get the port.
721 * Newer kernels send the value of the port= mount option in the "info"
722 * file for the upcall or '0' for NFSv2/3. For NFSv4 it sends the value
723 * of the port= option or '2049'. The port field in a new sockaddr should
724 * reflect the value that was sent by the kernel.
727 populate_port(struct sockaddr *sa, const socklen_t salen,
728 const rpcprog_t program, const rpcvers_t version,
729 const unsigned short protocol)
731 struct sockaddr_in *s4 = (struct sockaddr_in *) sa;
732 #ifdef IPV6_SUPPORTED
733 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa;
734 #endif /* IPV6_SUPPORTED */
738 * Newer kernels send the port in the upcall. If we already have
739 * the port, there's no need to look it up.
741 switch (sa->sa_family) {
743 if (s4->sin_port != 0) {
744 printerr(2, "DEBUG: port already set to %d\n",
745 ntohs(s4->sin_port));
749 #ifdef IPV6_SUPPORTED
751 if (s6->sin6_port != 0) {
752 printerr(2, "DEBUG: port already set to %d\n",
753 ntohs(s6->sin6_port));
757 #endif /* IPV6_SUPPORTED */
759 printerr(0, "ERROR: unsupported address family %d\n",
765 * Newer kernels that send the port in the upcall set the value to
766 * 2049 for NFSv4 mounts when one isn't specified. The check below is
767 * only for kernels that don't send the port in the upcall. For those
768 * we either have to do an rpcbind query or set it to the standard
769 * port. Doing a query could be problematic (firewalls, etc), so take
770 * the latter approach.
772 if (program == 100003 && version == 4) {
777 port = nfs_getport(sa, salen, program, version, protocol);
779 printerr(0, "ERROR: unable to obtain port for prog %ld "
780 "vers %ld\n", program, version);
785 printerr(2, "DEBUG: setting port to %hu for prog %lu vers %lu\n", port,
788 switch (sa->sa_family) {
790 s4->sin_port = htons(port);
792 #ifdef IPV6_SUPPORTED
794 s6->sin6_port = htons(port);
796 #endif /* IPV6_SUPPORTED */
803 * Create an RPC connection and establish an authenticated
804 * gss context with a server.
806 int create_auth_rpc_client(struct clnt_info *clp,
807 CLIENT **clnt_return,
812 CLIENT *rpc_clnt = NULL;
813 struct rpc_gss_sec sec;
818 char rpc_errmsg[1024];
820 struct timeval timeout = {5, 0};
821 struct sockaddr *addr = (struct sockaddr *) &clp->addr;
824 /* Create the context as the user (not as root) */
825 save_uid = geteuid();
826 if (setfsuid(uid) != 0) {
827 printerr(0, "WARNING: Failed to setfsuid for "
828 "user with uid %d\n", uid);
831 printerr(2, "creating context using fsuid %d (save_uid %d)\n",
834 sec.qop = GSS_C_QOP_DEFAULT;
835 sec.svc = RPCSEC_GSS_SVC_NONE;
836 sec.cred = GSS_C_NO_CREDENTIAL;
838 if (authtype == AUTHTYPE_KRB5) {
839 sec.mech = (gss_OID)&krb5oid;
840 sec.req_flags = GSS_C_MUTUAL_FLAG;
842 else if (authtype == AUTHTYPE_SPKM3) {
843 sec.mech = (gss_OID)&spkm3oid;
844 /* XXX sec.req_flags = GSS_C_ANON_FLAG;
845 * Need a way to switch....
847 sec.req_flags = GSS_C_MUTUAL_FLAG;
850 printerr(0, "ERROR: Invalid authentication type (%d) "
851 "in create_auth_rpc_client\n", authtype);
856 if (authtype == AUTHTYPE_KRB5) {
857 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
859 * Do this before creating rpc connection since we won't need
860 * rpc connection if it fails!
862 if (limit_krb5_enctypes(&sec)) {
863 printerr(1, "WARNING: Failed while limiting krb5 "
864 "encryption types for user with uid %d\n",
871 /* create an rpc connection to the nfs server */
873 printerr(2, "creating %s client for server %s\n", clp->protocol,
876 if ((strcmp(clp->protocol, "tcp")) == 0) {
877 protocol = IPPROTO_TCP;
878 } else if ((strcmp(clp->protocol, "udp")) == 0) {
879 protocol = IPPROTO_UDP;
881 printerr(0, "WARNING: unrecognized protocol, '%s', requested "
882 "for connection to server %s for user with uid %d\n",
883 clp->protocol, clp->servername, uid);
887 switch (addr->sa_family) {
889 salen = sizeof(struct sockaddr_in);
891 #ifdef IPV6_SUPPORTED
893 salen = sizeof(struct sockaddr_in6);
895 #endif /* IPV6_SUPPORTED */
897 printerr(1, "ERROR: Unknown address family %d\n",
902 if (!populate_port(addr, salen, clp->prog, clp->vers, protocol))
905 rpc_clnt = nfs_get_rpcclient(addr, salen, protocol, clp->prog,
906 clp->vers, &timeout);
908 snprintf(rpc_errmsg, sizeof(rpc_errmsg),
909 "WARNING: can't create %s rpc_clnt to server %s for "
911 protocol == IPPROTO_TCP ? "tcp" : "udp",
912 clp->servername, uid);
914 clnt_spcreateerror(rpc_errmsg));
918 printerr(2, "creating context with server %s\n", clp->servicename);
919 auth = authgss_create_default(rpc_clnt, clp->servicename, &sec);
921 /* Our caller should print appropriate message */
922 printerr(2, "WARNING: Failed to create %s context for "
923 "user with uid %d for server %s\n",
924 (authtype == AUTHTYPE_KRB5 ? "krb5":"spkm3"),
925 uid, clp->servername);
930 rpc_clnt->cl_auth = auth;
931 *clnt_return = rpc_clnt;
936 if (sec.cred != GSS_C_NO_CREDENTIAL)
937 gss_release_cred(&min_stat, &sec.cred);
938 /* Restore euid to original value */
939 if (((int)save_uid != -1) && (setfsuid(save_uid) != (int)uid)) {
940 printerr(0, "WARNING: Failed to restore fsuid"
941 " to uid %d from %d\n", save_uid, uid);
946 /* Only destroy here if failure. Otherwise, caller is responsible */
947 if (rpc_clnt) clnt_destroy(rpc_clnt);
953 * this code uses the userland rpcsec gss library to create a krb5
954 * context on behalf of the kernel
957 process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
960 CLIENT *rpc_clnt = NULL;
962 struct authgss_private_data pd;
963 gss_buffer_desc token;
964 char **credlist = NULL;
967 int create_resp = -1;
968 int err, downcall_err = -EACCES;
970 printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
973 if (clp->servicename) {
974 free(clp->servicename);
975 clp->servicename = strdup(tgtname);
980 memset(&pd, 0, sizeof(struct authgss_private_data));
983 * If "service" is specified, then the kernel is indicating that
984 * we must use machine credentials for this request. (Regardless
985 * of the uid value or the setting of root_uses_machine_creds.)
986 * If the service value is "*", then any service name can be used.
987 * Otherwise, it specifies the service name that should be used.
988 * (For now, the values of service will only be "*" or "nfs".)
990 * Restricting gssd to use "nfs" service name is needed for when
991 * the NFS server is doing a callback to the NFS client. In this
992 * case, the NFS server has to authenticate itself as "nfs" --
993 * even if there are other service keys such as "host" or "root"
996 * Another case when the kernel may specify the service attribute
997 * is when gssd is being asked to create the context for a
998 * SETCLIENT_ID operation. In this case, machine credentials
999 * must be used for the authentication. However, the service name
1000 * used for this case is not important.
1003 printerr(2, "%s: service is '%s'\n", __func__,
1004 service ? service : "<null>");
1005 if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
1007 /* Tell krb5 gss which credentials cache to use */
1008 for (dirname = ccachesearch; *dirname != NULL; dirname++) {
1009 err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname);
1010 if (err == -EKEYEXPIRED)
1011 downcall_err = -EKEYEXPIRED;
1013 create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
1015 if (create_resp == 0)
1019 if (create_resp != 0) {
1020 if (uid == 0 && (root_uses_machine_creds == 1 ||
1025 gssd_refresh_krb5_machine_credential(clp->servername,
1028 * Get a list of credential cache names and try each
1029 * of them until one works or we've tried them all
1031 if (gssd_get_krb5_machine_cred_list(&credlist)) {
1032 printerr(0, "ERROR: No credentials found "
1033 "for connection to server %s\n",
1035 goto out_return_error;
1037 for (ccname = credlist; ccname && *ccname; ccname++) {
1038 gssd_setup_krb5_machine_gss_ccache(*ccname);
1039 if ((create_auth_rpc_client(clp, &rpc_clnt,
1041 AUTHTYPE_KRB5)) == 0) {
1046 printerr(2, "WARNING: Failed to create machine krb5 context "
1047 "with credentials cache %s for server %s\n",
1048 *ccname, clp->servername);
1050 gssd_free_krb5_machine_cred_list(credlist);
1054 printerr(2, "WARNING: Machine cache is prematurely expired or corrupted "
1055 "trying to recreate cache for server %s\n", clp->servername);
1057 printerr(1, "WARNING: Failed to create machine krb5 context "
1058 "with any credentials cache for server %s\n",
1060 goto out_return_error;
1065 printerr(1, "WARNING: Failed to create krb5 context "
1066 "for user with uid %d for server %s\n",
1067 uid, clp->servername);
1068 goto out_return_error;
1072 if (!authgss_get_private_data(auth, &pd)) {
1073 printerr(1, "WARNING: Failed to obtain authentication "
1074 "data for user with uid %d for server %s\n",
1075 uid, clp->servername);
1076 goto out_return_error;
1079 if (serialize_context_for_kernel(pd.pd_ctx, &token, &krb5oid, NULL)) {
1080 printerr(0, "WARNING: Failed to serialize krb5 context for "
1081 "user with uid %d for server %s\n",
1082 uid, clp->servername);
1083 goto out_return_error;
1086 do_downcall(fd, uid, &pd, &token);
1091 #ifndef HAVE_LIBTIRPC
1092 if (pd.pd_ctx_hndl.length != 0)
1093 authgss_free_private_data(&pd);
1098 clnt_destroy(rpc_clnt);
1102 do_error_downcall(fd, uid, downcall_err);
1107 * this code uses the userland rpcsec gss library to create an spkm3
1108 * context on behalf of the kernel
1111 process_spkm3_upcall(struct clnt_info *clp, uid_t uid, int fd)
1113 CLIENT *rpc_clnt = NULL;
1115 struct authgss_private_data pd;
1116 gss_buffer_desc token;
1118 printerr(2, "handling spkm3 upcall (%s)\n", clp->dirname);
1123 if (create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, AUTHTYPE_SPKM3)) {
1124 printerr(0, "WARNING: Failed to create spkm3 context for "
1125 "user with uid %d\n", uid);
1126 goto out_return_error;
1129 if (!authgss_get_private_data(auth, &pd)) {
1130 printerr(0, "WARNING: Failed to obtain authentication "
1131 "data for user with uid %d for server %s\n",
1132 uid, clp->servername);
1133 goto out_return_error;
1136 if (serialize_context_for_kernel(pd.pd_ctx, &token, &spkm3oid, NULL)) {
1137 printerr(0, "WARNING: Failed to serialize spkm3 context for "
1138 "user with uid %d for server\n",
1139 uid, clp->servername);
1140 goto out_return_error;
1143 do_downcall(fd, uid, &pd, &token);
1151 clnt_destroy(rpc_clnt);
1155 do_error_downcall(fd, uid, -1);
1160 handle_krb5_upcall(struct clnt_info *clp)
1164 if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) {
1165 printerr(0, "WARNING: failed reading uid from krb5 "
1166 "upcall pipe: %s\n", strerror(errno));
1170 return process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
1174 handle_spkm3_upcall(struct clnt_info *clp)
1178 if (read(clp->spkm3_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) {
1179 printerr(0, "WARNING: failed reading uid from spkm3 "
1180 "upcall pipe: %s\n", strerror(errno));
1184 return process_spkm3_upcall(clp, uid, clp->spkm3_fd);
1188 handle_gssd_upcall(struct clnt_info *clp)
1195 char *target = NULL;
1196 char *service = NULL;
1197 char *enctypes = NULL;
1199 printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
1201 if (readline(clp->gssd_fd, &lbuf, &lbuflen) != 1) {
1202 printerr(0, "WARNING: handle_gssd_upcall: "
1203 "failed reading request\n");
1206 printerr(2, "%s: '%s'\n", __func__, lbuf);
1208 /* find the mechanism name */
1209 if ((p = strstr(lbuf, "mech=")) != NULL) {
1210 mech = malloc(lbuflen);
1213 if (sscanf(p, "mech=%s", mech) != 1) {
1214 printerr(0, "WARNING: handle_gssd_upcall: "
1215 "failed to parse gss mechanism name "
1216 "in upcall string '%s'\n", lbuf);
1220 printerr(0, "WARNING: handle_gssd_upcall: "
1221 "failed to find gss mechanism name "
1222 "in upcall string '%s'\n", lbuf);
1227 if ((p = strstr(lbuf, "uid=")) != NULL) {
1228 if (sscanf(p, "uid=%d", &uid) != 1) {
1229 printerr(0, "WARNING: handle_gssd_upcall: "
1230 "failed to parse uid "
1231 "in upcall string '%s'\n", lbuf);
1235 printerr(0, "WARNING: handle_gssd_upcall: "
1236 "failed to find uid "
1237 "in upcall string '%s'\n", lbuf);
1241 /* read supported encryption types if supplied */
1242 if ((p = strstr(lbuf, "enctypes=")) != NULL) {
1243 enctypes = malloc(lbuflen);
1246 if (sscanf(p, "enctypes=%s", enctypes) != 1) {
1247 printerr(0, "WARNING: handle_gssd_upcall: "
1248 "failed to parse encryption types "
1249 "in upcall string '%s'\n", lbuf);
1252 if (parse_enctypes(enctypes) != 0) {
1253 printerr(0, "WARNING: handle_gssd_upcall: "
1254 "parsing encryption types failed: errno %d\n", errno);
1258 /* read target name */
1259 if ((p = strstr(lbuf, "target=")) != NULL) {
1260 target = malloc(lbuflen);
1263 if (sscanf(p, "target=%s", target) != 1) {
1264 printerr(0, "WARNING: handle_gssd_upcall: "
1265 "failed to parse target name "
1266 "in upcall string '%s'\n", lbuf);
1272 * read the service name
1274 * The presence of attribute "service=" indicates that machine
1275 * credentials should be used for this request. If the value
1276 * is "*", then any machine credentials available can be used.
1277 * If the value is anything else, then machine credentials for
1278 * the specified service name (always "nfs" for now) should be
1281 if ((p = strstr(lbuf, "service=")) != NULL) {
1282 service = malloc(lbuflen);
1285 if (sscanf(p, "service=%s", service) != 1) {
1286 printerr(0, "WARNING: handle_gssd_upcall: "
1287 "failed to parse service type "
1288 "in upcall string '%s'\n", lbuf);
1293 if (strcmp(mech, "krb5") == 0)
1294 process_krb5_upcall(clp, uid, clp->gssd_fd, target, service);
1295 else if (strcmp(mech, "spkm3") == 0)
1296 process_spkm3_upcall(clp, uid, clp->gssd_fd);
1298 printerr(0, "WARNING: handle_gssd_upcall: "
1299 "received unknown gss mech '%s'\n", mech);