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 /* get program, and version numbers */
254 *prog = atoi(program + 1); /* skip open paren */
255 *vers = atoi(version);
257 if (!addrstr_to_sockaddr(addr, address, port))
260 *servername = sockaddr_to_hostname(addr, address);
261 if (*servername == NULL)
264 nbytes = snprintf(buf, INFOBUFLEN, "%s@%s", service, *servername);
265 if (nbytes > INFOBUFLEN)
268 if (!(*servicename = calloc(strlen(buf) + 1, 1)))
270 memcpy(*servicename, buf, strlen(buf));
272 if (!(*protocol = strdup(protoname)))
276 printerr(0, "ERROR: failed to read service info\n");
277 if (fd != -1) close(fd);
281 *servicename = *servername = *protocol = NULL;
286 destroy_client(struct clnt_info *clp)
288 if (clp->krb5_poll_index != -1)
289 memset(&pollarray[clp->krb5_poll_index], 0,
290 sizeof(struct pollfd));
291 if (clp->gssd_poll_index != -1)
292 memset(&pollarray[clp->gssd_poll_index], 0,
293 sizeof(struct pollfd));
294 if (clp->dir_fd != -1) close(clp->dir_fd);
295 if (clp->krb5_fd != -1) close(clp->krb5_fd);
296 if (clp->gssd_fd != -1) close(clp->gssd_fd);
298 free(clp->servicename);
299 free(clp->servername);
304 static struct clnt_info *
305 insert_new_clnt(void)
307 struct clnt_info *clp = NULL;
309 if (!(clp = (struct clnt_info *)calloc(1,sizeof(struct clnt_info)))) {
310 printerr(0, "ERROR: can't malloc clnt_info: %s\n",
314 clp->krb5_poll_index = -1;
315 clp->gssd_poll_index = -1;
320 TAILQ_INSERT_HEAD(&clnt_list, clp, list);
326 process_clnt_dir_files(struct clnt_info * clp)
329 char gname[PATH_MAX];
330 char info_file_name[PATH_MAX];
332 if (clp->gssd_close_me) {
333 printerr(2, "Closing 'gssd' pipe for %s\n", clp->dirname);
335 memset(&pollarray[clp->gssd_poll_index], 0,
336 sizeof(struct pollfd));
338 clp->gssd_poll_index = -1;
339 clp->gssd_close_me = 0;
341 if (clp->krb5_close_me) {
342 printerr(2, "Closing 'krb5' pipe for %s\n", clp->dirname);
344 memset(&pollarray[clp->krb5_poll_index], 0,
345 sizeof(struct pollfd));
347 clp->krb5_poll_index = -1;
348 clp->krb5_close_me = 0;
351 if (clp->gssd_fd == -1) {
352 snprintf(gname, sizeof(gname), "%s/gssd", clp->dirname);
353 clp->gssd_fd = open(gname, O_RDWR);
355 if (clp->gssd_fd == -1) {
356 if (clp->krb5_fd == -1) {
357 snprintf(name, sizeof(name), "%s/krb5", clp->dirname);
358 clp->krb5_fd = open(name, O_RDWR);
361 /* If we opened a gss-specific pipe, let's try opening
362 * the new upcall pipe again. If we succeed, close
363 * gss-specific pipe(s).
365 if (clp->krb5_fd != -1) {
366 clp->gssd_fd = open(gname, O_RDWR);
367 if (clp->gssd_fd != -1) {
368 if (clp->krb5_fd != -1)
375 if ((clp->krb5_fd == -1) && (clp->gssd_fd == -1))
377 snprintf(info_file_name, sizeof(info_file_name), "%s/info",
379 if ((clp->servicename == NULL) &&
380 read_service_info(info_file_name, &clp->servicename,
381 &clp->servername, &clp->prog, &clp->vers,
382 &clp->protocol, (struct sockaddr *) &clp->addr))
388 get_poll_index(int *ind)
393 for (i=0; i<pollsize; i++) {
394 if (pollarray[i].events == 0) {
400 printerr(0, "ERROR: No pollarray slots open\n");
408 insert_clnt_poll(struct clnt_info *clp)
410 if ((clp->gssd_fd != -1) && (clp->gssd_poll_index == -1)) {
411 if (get_poll_index(&clp->gssd_poll_index)) {
412 printerr(0, "ERROR: Too many gssd clients\n");
415 pollarray[clp->gssd_poll_index].fd = clp->gssd_fd;
416 pollarray[clp->gssd_poll_index].events |= POLLIN;
419 if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
420 if (get_poll_index(&clp->krb5_poll_index)) {
421 printerr(0, "ERROR: Too many krb5 clients\n");
424 pollarray[clp->krb5_poll_index].fd = clp->krb5_fd;
425 pollarray[clp->krb5_poll_index].events |= POLLIN;
432 process_clnt_dir(char *dir, char *pdir)
434 struct clnt_info * clp;
436 if (!(clp = insert_new_clnt()))
437 goto fail_destroy_client;
439 /* An extra for the '/', and an extra for the null */
440 if (!(clp->dirname = calloc(strlen(dir) + strlen(pdir) + 2, 1))) {
441 goto fail_destroy_client;
443 sprintf(clp->dirname, "%s/%s", pdir, dir);
444 if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
445 printerr(0, "ERROR: can't open %s: %s\n",
446 clp->dirname, strerror(errno));
447 goto fail_destroy_client;
449 fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL);
450 fcntl(clp->dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MULTISHOT);
452 if (process_clnt_dir_files(clp))
453 goto fail_keep_client;
455 if (insert_clnt_poll(clp))
456 goto fail_destroy_client;
462 TAILQ_REMOVE(&clnt_list, clp, list);
466 /* We couldn't find some subdirectories, but we keep the client
467 * around in case we get a notification on the directory when the
468 * subdirectories are created. */
473 init_client_list(void)
475 TAILQ_INIT(&clnt_list);
476 /* Eventually plan to grow/shrink poll array: */
477 pollsize = FD_ALLOC_BLOCK;
478 pollarray = calloc(pollsize, sizeof(struct pollfd));
482 * This is run after a DNOTIFY signal, and should clear up any
483 * directories that are no longer around, and re-scan any existing
484 * directories, since the DNOTIFY could have been in there.
487 update_old_clients(struct dirent **namelist, int size, char *pdir)
489 struct clnt_info *clp;
492 char fname[PATH_MAX];
494 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
495 /* only compare entries in the global list that are from the
496 * same pipefs parent directory as "pdir"
498 if (strncmp(clp->dirname, pdir, strlen(pdir)) != 0) continue;
501 for (i=0; i < size; i++) {
502 snprintf(fname, sizeof(fname), "%s/%s",
503 pdir, namelist[i]->d_name);
504 if (strcmp(clp->dirname, fname) == 0) {
510 printerr(2, "destroying client %s\n", clp->dirname);
511 saveprev = clp->list.tqe_prev;
512 TAILQ_REMOVE(&clnt_list, clp, list);
517 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
518 if (!process_clnt_dir_files(clp))
519 insert_clnt_poll(clp);
523 /* Search for a client by directory name, return 1 if found, 0 otherwise */
525 find_client(char *dirname, char *pdir)
527 struct clnt_info *clp;
528 char fname[PATH_MAX];
530 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
531 snprintf(fname, sizeof(fname), "%s/%s", pdir, dirname);
532 if (strcmp(clp->dirname, fname) == 0)
539 process_pipedir(char *pipe_name)
541 struct dirent **namelist;
544 if (chdir(pipe_name) < 0) {
545 printerr(0, "ERROR: can't chdir to %s: %s\n",
546 pipe_name, strerror(errno));
550 j = scandir(pipe_name, &namelist, NULL, alphasort);
552 printerr(0, "ERROR: can't scandir %s: %s\n",
553 pipe_name, strerror(errno));
557 update_old_clients(namelist, j, pipe_name);
558 for (i=0; i < j; i++) {
559 if (!strncmp(namelist[i]->d_name, "clnt", 4)
560 && !find_client(namelist[i]->d_name, pipe_name))
561 process_clnt_dir(namelist[i]->d_name, pipe_name);
570 /* Used to read (and re-read) list of clients, set up poll array. */
572 update_client_list(void)
575 struct topdirs_info *tdi;
577 TAILQ_FOREACH(tdi, &topdirs_list, list) {
578 retval = process_pipedir(tdi->dirname);
580 printerr(1, "WARNING: error processing %s\n",
587 /* Encryption types supported by the kernel rpcsec_gss code */
588 int num_krb5_enctypes = 0;
589 krb5_enctype *krb5_enctypes = NULL;
592 * Parse the supported encryption type information
595 parse_enctypes(char *enctypes)
600 static char *cached_types;
602 if (cached_types && strcmp(cached_types, enctypes) == 0)
606 if (krb5_enctypes != NULL) {
608 krb5_enctypes = NULL;
609 num_krb5_enctypes = 0;
612 /* count the number of commas */
613 for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
614 comma = strchr(curr, ',');
620 /* If no more commas and we're not at the end, there's one more value */
624 /* Empty string, return an error */
628 /* Allocate space for enctypes array */
629 if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
633 /* Now parse each value into the array */
634 for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) {
635 krb5_enctypes[i++] = atoi(curr);
636 comma = strchr(curr, ',');
641 num_krb5_enctypes = n;
642 if ((cached_types = malloc(strlen(enctypes)+1)))
643 strcpy(cached_types, enctypes);
649 do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
650 gss_buffer_desc *context_token, OM_uint32 lifetime_rec)
652 char *buf = NULL, *p = NULL, *end = NULL;
653 unsigned int timeout = context_timeout;
654 unsigned int buf_size = 0;
656 printerr(1, "doing downcall lifetime_rec %u\n", lifetime_rec);
657 buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) +
658 sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length +
659 sizeof(context_token->length) + context_token->length;
660 p = buf = malloc(buf_size);
661 end = buf + buf_size;
663 /* context_timeout set by -t option overrides context lifetime */
665 timeout = lifetime_rec;
666 if (WRITE_BYTES(&p, end, uid)) goto out_err;
667 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
668 if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err;
669 if (write_buffer(&p, end, &pd->pd_ctx_hndl)) goto out_err;
670 if (write_buffer(&p, end, context_token)) goto out_err;
672 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
677 printerr(1, "Failed to write downcall!\n");
682 do_error_downcall(int k5_fd, uid_t uid, int err)
685 char *p = buf, *end = buf + 1024;
686 unsigned int timeout = 0;
689 printerr(1, "doing error downcall\n");
691 if (WRITE_BYTES(&p, end, uid)) goto out_err;
692 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
693 /* use seq_win = 0 to indicate an error: */
694 if (WRITE_BYTES(&p, end, zero)) goto out_err;
695 if (WRITE_BYTES(&p, end, err)) goto out_err;
697 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
700 printerr(1, "Failed to write error downcall!\n");
705 * If the port isn't already set, do an rpcbind query to the remote server
706 * using the program and version and get the port.
708 * Newer kernels send the value of the port= mount option in the "info"
709 * file for the upcall or '0' for NFSv2/3. For NFSv4 it sends the value
710 * of the port= option or '2049'. The port field in a new sockaddr should
711 * reflect the value that was sent by the kernel.
714 populate_port(struct sockaddr *sa, const socklen_t salen,
715 const rpcprog_t program, const rpcvers_t version,
716 const unsigned short protocol)
718 struct sockaddr_in *s4 = (struct sockaddr_in *) sa;
719 #ifdef IPV6_SUPPORTED
720 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa;
721 #endif /* IPV6_SUPPORTED */
725 * Newer kernels send the port in the upcall. If we already have
726 * the port, there's no need to look it up.
728 switch (sa->sa_family) {
730 if (s4->sin_port != 0) {
731 printerr(2, "DEBUG: port already set to %d\n",
732 ntohs(s4->sin_port));
736 #ifdef IPV6_SUPPORTED
738 if (s6->sin6_port != 0) {
739 printerr(2, "DEBUG: port already set to %d\n",
740 ntohs(s6->sin6_port));
744 #endif /* IPV6_SUPPORTED */
746 printerr(0, "ERROR: unsupported address family %d\n",
752 * Newer kernels that send the port in the upcall set the value to
753 * 2049 for NFSv4 mounts when one isn't specified. The check below is
754 * only for kernels that don't send the port in the upcall. For those
755 * we either have to do an rpcbind query or set it to the standard
756 * port. Doing a query could be problematic (firewalls, etc), so take
757 * the latter approach.
759 if (program == 100003 && version == 4) {
764 port = nfs_getport(sa, salen, program, version, protocol);
766 printerr(0, "ERROR: unable to obtain port for prog %ld "
767 "vers %ld\n", program, version);
772 printerr(2, "DEBUG: setting port to %hu for prog %lu vers %lu\n", port,
775 switch (sa->sa_family) {
777 s4->sin_port = htons(port);
779 #ifdef IPV6_SUPPORTED
781 s6->sin6_port = htons(port);
783 #endif /* IPV6_SUPPORTED */
790 * Create an RPC connection and establish an authenticated
791 * gss context with a server.
794 create_auth_rpc_client(struct clnt_info *clp,
795 CLIENT **clnt_return,
800 CLIENT *rpc_clnt = NULL;
801 struct rpc_gss_sec sec;
806 char rpc_errmsg[1024];
808 struct timeval timeout = {5, 0};
809 struct sockaddr *addr = (struct sockaddr *) &clp->addr;
812 /* Create the context as the user (not as root) */
813 save_uid = geteuid();
814 if (setfsuid(uid) != 0) {
815 printerr(0, "WARNING: Failed to setfsuid for "
816 "user with uid %d\n", uid);
819 printerr(2, "creating context using fsuid %d (save_uid %d)\n",
822 sec.qop = GSS_C_QOP_DEFAULT;
823 sec.svc = RPCSEC_GSS_SVC_NONE;
824 sec.cred = GSS_C_NO_CREDENTIAL;
826 if (authtype == AUTHTYPE_KRB5) {
827 sec.mech = (gss_OID)&krb5oid;
828 sec.req_flags = GSS_C_MUTUAL_FLAG;
831 printerr(0, "ERROR: Invalid authentication type (%d) "
832 "in create_auth_rpc_client\n", authtype);
837 if (authtype == AUTHTYPE_KRB5) {
838 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
840 * Do this before creating rpc connection since we won't need
841 * rpc connection if it fails!
843 if (limit_krb5_enctypes(&sec)) {
844 printerr(1, "WARNING: Failed while limiting krb5 "
845 "encryption types for user with uid %d\n",
852 /* create an rpc connection to the nfs server */
854 printerr(2, "creating %s client for server %s\n", clp->protocol,
857 if ((strcmp(clp->protocol, "tcp")) == 0) {
858 protocol = IPPROTO_TCP;
859 } else if ((strcmp(clp->protocol, "udp")) == 0) {
860 protocol = IPPROTO_UDP;
862 printerr(0, "WARNING: unrecognized protocol, '%s', requested "
863 "for connection to server %s for user with uid %d\n",
864 clp->protocol, clp->servername, uid);
868 switch (addr->sa_family) {
870 salen = sizeof(struct sockaddr_in);
872 #ifdef IPV6_SUPPORTED
874 salen = sizeof(struct sockaddr_in6);
876 #endif /* IPV6_SUPPORTED */
878 printerr(1, "ERROR: Unknown address family %d\n",
883 if (!populate_port(addr, salen, clp->prog, clp->vers, protocol))
886 rpc_clnt = nfs_get_rpcclient(addr, salen, protocol, clp->prog,
887 clp->vers, &timeout);
889 snprintf(rpc_errmsg, sizeof(rpc_errmsg),
890 "WARNING: can't create %s rpc_clnt to server %s for "
892 protocol == IPPROTO_TCP ? "tcp" : "udp",
893 clp->servername, uid);
895 clnt_spcreateerror(rpc_errmsg));
899 printerr(2, "creating context with server %s\n", clp->servicename);
900 auth = authgss_create_default(rpc_clnt, clp->servicename, &sec);
902 /* Our caller should print appropriate message */
903 printerr(2, "WARNING: Failed to create krb5 context for "
904 "user with uid %d for server %s\n",
905 uid, clp->servername);
910 rpc_clnt->cl_auth = auth;
911 *clnt_return = rpc_clnt;
916 if (sec.cred != GSS_C_NO_CREDENTIAL)
917 gss_release_cred(&min_stat, &sec.cred);
918 /* Restore euid to original value */
919 if (((int)save_uid != -1) && (setfsuid(save_uid) != (int)uid)) {
920 printerr(0, "WARNING: Failed to restore fsuid"
921 " to uid %d from %d\n", save_uid, uid);
926 /* Only destroy here if failure. Otherwise, caller is responsible */
927 if (rpc_clnt) clnt_destroy(rpc_clnt);
933 * this code uses the userland rpcsec gss library to create a krb5
934 * context on behalf of the kernel
937 process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
940 CLIENT *rpc_clnt = NULL;
942 struct authgss_private_data pd;
943 gss_buffer_desc token;
944 char **credlist = NULL;
947 int create_resp = -1;
948 int err, downcall_err = -EACCES;
949 OM_uint32 maj_stat, min_stat, lifetime_rec;
951 printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
955 memset(&pd, 0, sizeof(struct authgss_private_data));
958 * If "service" is specified, then the kernel is indicating that
959 * we must use machine credentials for this request. (Regardless
960 * of the uid value or the setting of root_uses_machine_creds.)
961 * If the service value is "*", then any service name can be used.
962 * Otherwise, it specifies the service name that should be used.
963 * (For now, the values of service will only be "*" or "nfs".)
965 * Restricting gssd to use "nfs" service name is needed for when
966 * the NFS server is doing a callback to the NFS client. In this
967 * case, the NFS server has to authenticate itself as "nfs" --
968 * even if there are other service keys such as "host" or "root"
971 * Another case when the kernel may specify the service attribute
972 * is when gssd is being asked to create the context for a
973 * SETCLIENT_ID operation. In this case, machine credentials
974 * must be used for the authentication. However, the service name
975 * used for this case is not important.
978 printerr(2, "%s: service is '%s'\n", __func__,
979 service ? service : "<null>");
980 if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
982 /* Tell krb5 gss which credentials cache to use */
983 for (dirname = ccachesearch; *dirname != NULL; dirname++) {
984 err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname);
985 if (err == -EKEYEXPIRED)
986 downcall_err = -EKEYEXPIRED;
988 create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
990 if (create_resp == 0)
994 if (create_resp != 0) {
995 if (uid == 0 && (root_uses_machine_creds == 1 ||
1000 gssd_refresh_krb5_machine_credential(clp->servername,
1004 * Get a list of credential cache names and try each
1005 * of them until one works or we've tried them all
1007 if (gssd_get_krb5_machine_cred_list(&credlist)) {
1008 printerr(0, "ERROR: No credentials found "
1009 "for connection to server %s\n",
1011 goto out_return_error;
1013 for (ccname = credlist; ccname && *ccname; ccname++) {
1014 gssd_setup_krb5_machine_gss_ccache(*ccname);
1015 if ((create_auth_rpc_client(clp, &rpc_clnt,
1017 AUTHTYPE_KRB5)) == 0) {
1022 printerr(2, "WARNING: Failed to create machine krb5 context "
1023 "with credentials cache %s for server %s\n",
1024 *ccname, clp->servername);
1026 gssd_free_krb5_machine_cred_list(credlist);
1030 printerr(2, "WARNING: Machine cache is prematurely expired or corrupted "
1031 "trying to recreate cache for server %s\n", clp->servername);
1033 printerr(1, "WARNING: Failed to create machine krb5 context "
1034 "with any credentials cache for server %s\n",
1036 goto out_return_error;
1041 printerr(1, "WARNING: Failed to create krb5 context "
1042 "for user with uid %d for server %s\n",
1043 uid, clp->servername);
1044 goto out_return_error;
1048 if (!authgss_get_private_data(auth, &pd)) {
1049 printerr(1, "WARNING: Failed to obtain authentication "
1050 "data for user with uid %d for server %s\n",
1051 uid, clp->servername);
1052 goto out_return_error;
1055 /* Grab the context lifetime to pass to the kernel. lifetime_rec
1056 * is set to zero on error */
1057 maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, NULL,
1058 &lifetime_rec, NULL, NULL, NULL, NULL);
1061 printerr(1, "WARNING: Failed to inquire context for lifetme "
1062 "maj_stat %u\n", maj_stat);
1064 if (serialize_context_for_kernel(pd.pd_ctx, &token, &krb5oid, NULL)) {
1065 printerr(0, "WARNING: Failed to serialize krb5 context for "
1066 "user with uid %d for server %s\n",
1067 uid, clp->servername);
1068 goto out_return_error;
1071 do_downcall(fd, uid, &pd, &token, lifetime_rec);
1076 #ifndef HAVE_LIBTIRPC
1077 if (pd.pd_ctx_hndl.length != 0)
1078 authgss_free_private_data(&pd);
1083 clnt_destroy(rpc_clnt);
1087 do_error_downcall(fd, uid, downcall_err);
1092 handle_krb5_upcall(struct clnt_info *clp)
1096 if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) {
1097 printerr(0, "WARNING: failed reading uid from krb5 "
1098 "upcall pipe: %s\n", strerror(errno));
1102 process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
1106 handle_gssd_upcall(struct clnt_info *clp)
1113 char *target = NULL;
1114 char *service = NULL;
1115 char *enctypes = NULL;
1117 printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
1119 if (readline(clp->gssd_fd, &lbuf, &lbuflen) != 1) {
1120 printerr(0, "WARNING: handle_gssd_upcall: "
1121 "failed reading request\n");
1124 printerr(2, "%s: '%s'\n", __func__, lbuf);
1126 /* find the mechanism name */
1127 if ((p = strstr(lbuf, "mech=")) != NULL) {
1128 mech = malloc(lbuflen);
1131 if (sscanf(p, "mech=%s", mech) != 1) {
1132 printerr(0, "WARNING: handle_gssd_upcall: "
1133 "failed to parse gss mechanism name "
1134 "in upcall string '%s'\n", lbuf);
1138 printerr(0, "WARNING: handle_gssd_upcall: "
1139 "failed to find gss mechanism name "
1140 "in upcall string '%s'\n", lbuf);
1145 if ((p = strstr(lbuf, "uid=")) != NULL) {
1146 if (sscanf(p, "uid=%d", &uid) != 1) {
1147 printerr(0, "WARNING: handle_gssd_upcall: "
1148 "failed to parse uid "
1149 "in upcall string '%s'\n", lbuf);
1153 printerr(0, "WARNING: handle_gssd_upcall: "
1154 "failed to find uid "
1155 "in upcall string '%s'\n", lbuf);
1159 /* read supported encryption types if supplied */
1160 if ((p = strstr(lbuf, "enctypes=")) != NULL) {
1161 enctypes = malloc(lbuflen);
1164 if (sscanf(p, "enctypes=%s", enctypes) != 1) {
1165 printerr(0, "WARNING: handle_gssd_upcall: "
1166 "failed to parse encryption types "
1167 "in upcall string '%s'\n", lbuf);
1170 if (parse_enctypes(enctypes) != 0) {
1171 printerr(0, "WARNING: handle_gssd_upcall: "
1172 "parsing encryption types failed: errno %d\n", errno);
1176 /* read target name */
1177 if ((p = strstr(lbuf, "target=")) != NULL) {
1178 target = malloc(lbuflen);
1181 if (sscanf(p, "target=%s", target) != 1) {
1182 printerr(0, "WARNING: handle_gssd_upcall: "
1183 "failed to parse target name "
1184 "in upcall string '%s'\n", lbuf);
1190 * read the service name
1192 * The presence of attribute "service=" indicates that machine
1193 * credentials should be used for this request. If the value
1194 * is "*", then any machine credentials available can be used.
1195 * If the value is anything else, then machine credentials for
1196 * the specified service name (always "nfs" for now) should be
1199 if ((p = strstr(lbuf, "service=")) != NULL) {
1200 service = malloc(lbuflen);
1203 if (sscanf(p, "service=%s", service) != 1) {
1204 printerr(0, "WARNING: handle_gssd_upcall: "
1205 "failed to parse service type "
1206 "in upcall string '%s'\n", lbuf);
1211 if (strcmp(mech, "krb5") == 0)
1212 process_krb5_upcall(clp, uid, clp->gssd_fd, target, service);
1214 printerr(0, "WARNING: handle_gssd_upcall: "
1215 "received unknown gss mech '%s'\n", mech);