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 (i < FD_ALLOC_BLOCK
560 && !strncmp(namelist[i]->d_name, "clnt", 4)
561 && !find_client(namelist[i]->d_name, pipe_name))
562 process_clnt_dir(namelist[i]->d_name, pipe_name);
571 /* Used to read (and re-read) list of clients, set up poll array. */
573 update_client_list(void)
576 struct topdirs_info *tdi;
578 TAILQ_FOREACH(tdi, &topdirs_list, list) {
579 retval = process_pipedir(tdi->dirname);
581 printerr(1, "WARNING: error processing %s\n",
588 /* Encryption types supported by the kernel rpcsec_gss code */
589 int num_krb5_enctypes = 0;
590 krb5_enctype *krb5_enctypes = NULL;
593 * Parse the supported encryption type information
596 parse_enctypes(char *enctypes)
601 static char *cached_types;
603 if (cached_types && strcmp(cached_types, enctypes) == 0)
607 if (krb5_enctypes != NULL) {
609 krb5_enctypes = NULL;
610 num_krb5_enctypes = 0;
613 /* count the number of commas */
614 for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
615 comma = strchr(curr, ',');
621 /* If no more commas and we're not at the end, there's one more value */
625 /* Empty string, return an error */
629 /* Allocate space for enctypes array */
630 if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
634 /* Now parse each value into the array */
635 for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) {
636 krb5_enctypes[i++] = atoi(curr);
637 comma = strchr(curr, ',');
642 num_krb5_enctypes = n;
643 if ((cached_types = malloc(strlen(enctypes)+1)))
644 strcpy(cached_types, enctypes);
650 do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
651 gss_buffer_desc *context_token, OM_uint32 lifetime_rec)
653 char *buf = NULL, *p = NULL, *end = NULL;
654 unsigned int timeout = context_timeout;
655 unsigned int buf_size = 0;
657 printerr(1, "doing downcall lifetime_rec %u\n", lifetime_rec);
658 buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) +
659 sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length +
660 sizeof(context_token->length) + context_token->length;
661 p = buf = malloc(buf_size);
662 end = buf + buf_size;
664 /* context_timeout set by -t option overrides context lifetime */
666 timeout = lifetime_rec;
667 if (WRITE_BYTES(&p, end, uid)) goto out_err;
668 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
669 if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err;
670 if (write_buffer(&p, end, &pd->pd_ctx_hndl)) goto out_err;
671 if (write_buffer(&p, end, context_token)) goto out_err;
673 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
678 printerr(1, "Failed to write downcall!\n");
683 do_error_downcall(int k5_fd, uid_t uid, int err)
686 char *p = buf, *end = buf + 1024;
687 unsigned int timeout = 0;
690 printerr(1, "doing error downcall\n");
692 if (WRITE_BYTES(&p, end, uid)) goto out_err;
693 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
694 /* use seq_win = 0 to indicate an error: */
695 if (WRITE_BYTES(&p, end, zero)) goto out_err;
696 if (WRITE_BYTES(&p, end, err)) goto out_err;
698 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
701 printerr(1, "Failed to write error downcall!\n");
706 * If the port isn't already set, do an rpcbind query to the remote server
707 * using the program and version and get the port.
709 * Newer kernels send the value of the port= mount option in the "info"
710 * file for the upcall or '0' for NFSv2/3. For NFSv4 it sends the value
711 * of the port= option or '2049'. The port field in a new sockaddr should
712 * reflect the value that was sent by the kernel.
715 populate_port(struct sockaddr *sa, const socklen_t salen,
716 const rpcprog_t program, const rpcvers_t version,
717 const unsigned short protocol)
719 struct sockaddr_in *s4 = (struct sockaddr_in *) sa;
720 #ifdef IPV6_SUPPORTED
721 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa;
722 #endif /* IPV6_SUPPORTED */
726 * Newer kernels send the port in the upcall. If we already have
727 * the port, there's no need to look it up.
729 switch (sa->sa_family) {
731 if (s4->sin_port != 0) {
732 printerr(2, "DEBUG: port already set to %d\n",
733 ntohs(s4->sin_port));
737 #ifdef IPV6_SUPPORTED
739 if (s6->sin6_port != 0) {
740 printerr(2, "DEBUG: port already set to %d\n",
741 ntohs(s6->sin6_port));
745 #endif /* IPV6_SUPPORTED */
747 printerr(0, "ERROR: unsupported address family %d\n",
753 * Newer kernels that send the port in the upcall set the value to
754 * 2049 for NFSv4 mounts when one isn't specified. The check below is
755 * only for kernels that don't send the port in the upcall. For those
756 * we either have to do an rpcbind query or set it to the standard
757 * port. Doing a query could be problematic (firewalls, etc), so take
758 * the latter approach.
760 if (program == 100003 && version == 4) {
765 port = nfs_getport(sa, salen, program, version, protocol);
767 printerr(0, "ERROR: unable to obtain port for prog %ld "
768 "vers %ld\n", program, version);
773 printerr(2, "DEBUG: setting port to %hu for prog %lu vers %lu\n", port,
776 switch (sa->sa_family) {
778 s4->sin_port = htons(port);
780 #ifdef IPV6_SUPPORTED
782 s6->sin6_port = htons(port);
784 #endif /* IPV6_SUPPORTED */
791 * Create an RPC connection and establish an authenticated
792 * gss context with a server.
795 create_auth_rpc_client(struct clnt_info *clp,
796 CLIENT **clnt_return,
801 CLIENT *rpc_clnt = NULL;
802 struct rpc_gss_sec sec;
807 char rpc_errmsg[1024];
809 struct timeval timeout = {5, 0};
810 struct sockaddr *addr = (struct sockaddr *) &clp->addr;
813 /* Create the context as the user (not as root) */
814 save_uid = geteuid();
815 if (setfsuid(uid) != 0) {
816 printerr(0, "WARNING: Failed to setfsuid for "
817 "user with uid %d\n", uid);
820 printerr(2, "creating context using fsuid %d (save_uid %d)\n",
823 sec.qop = GSS_C_QOP_DEFAULT;
824 sec.svc = RPCSEC_GSS_SVC_NONE;
825 sec.cred = GSS_C_NO_CREDENTIAL;
827 if (authtype == AUTHTYPE_KRB5) {
828 sec.mech = (gss_OID)&krb5oid;
829 sec.req_flags = GSS_C_MUTUAL_FLAG;
832 printerr(0, "ERROR: Invalid authentication type (%d) "
833 "in create_auth_rpc_client\n", authtype);
838 if (authtype == AUTHTYPE_KRB5) {
839 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
841 * Do this before creating rpc connection since we won't need
842 * rpc connection if it fails!
844 if (limit_krb5_enctypes(&sec)) {
845 printerr(1, "WARNING: Failed while limiting krb5 "
846 "encryption types for user with uid %d\n",
853 /* create an rpc connection to the nfs server */
855 printerr(2, "creating %s client for server %s\n", clp->protocol,
858 if ((strcmp(clp->protocol, "tcp")) == 0) {
859 protocol = IPPROTO_TCP;
860 } else if ((strcmp(clp->protocol, "udp")) == 0) {
861 protocol = IPPROTO_UDP;
863 printerr(0, "WARNING: unrecognized protocol, '%s', requested "
864 "for connection to server %s for user with uid %d\n",
865 clp->protocol, clp->servername, uid);
869 switch (addr->sa_family) {
871 salen = sizeof(struct sockaddr_in);
873 #ifdef IPV6_SUPPORTED
875 salen = sizeof(struct sockaddr_in6);
877 #endif /* IPV6_SUPPORTED */
879 printerr(1, "ERROR: Unknown address family %d\n",
884 if (!populate_port(addr, salen, clp->prog, clp->vers, protocol))
887 rpc_clnt = nfs_get_rpcclient(addr, salen, protocol, clp->prog,
888 clp->vers, &timeout);
890 snprintf(rpc_errmsg, sizeof(rpc_errmsg),
891 "WARNING: can't create %s rpc_clnt to server %s for "
893 protocol == IPPROTO_TCP ? "tcp" : "udp",
894 clp->servername, uid);
896 clnt_spcreateerror(rpc_errmsg));
900 printerr(2, "creating context with server %s\n", clp->servicename);
901 auth = authgss_create_default(rpc_clnt, clp->servicename, &sec);
903 /* Our caller should print appropriate message */
904 printerr(2, "WARNING: Failed to create krb5 context for "
905 "user with uid %d for server %s\n",
906 uid, clp->servername);
911 rpc_clnt->cl_auth = auth;
912 *clnt_return = rpc_clnt;
917 if (sec.cred != GSS_C_NO_CREDENTIAL)
918 gss_release_cred(&min_stat, &sec.cred);
919 /* Restore euid to original value */
920 if (((int)save_uid != -1) && (setfsuid(save_uid) != (int)uid)) {
921 printerr(0, "WARNING: Failed to restore fsuid"
922 " to uid %d from %d\n", save_uid, uid);
927 /* Only destroy here if failure. Otherwise, caller is responsible */
928 if (rpc_clnt) clnt_destroy(rpc_clnt);
934 * this code uses the userland rpcsec gss library to create a krb5
935 * context on behalf of the kernel
938 process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
941 CLIENT *rpc_clnt = NULL;
943 struct authgss_private_data pd;
944 gss_buffer_desc token;
945 char **credlist = NULL;
948 int create_resp = -1;
949 int err, downcall_err = -EACCES;
950 OM_uint32 maj_stat, min_stat, lifetime_rec;
952 printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
956 memset(&pd, 0, sizeof(struct authgss_private_data));
959 * If "service" is specified, then the kernel is indicating that
960 * we must use machine credentials for this request. (Regardless
961 * of the uid value or the setting of root_uses_machine_creds.)
962 * If the service value is "*", then any service name can be used.
963 * Otherwise, it specifies the service name that should be used.
964 * (For now, the values of service will only be "*" or "nfs".)
966 * Restricting gssd to use "nfs" service name is needed for when
967 * the NFS server is doing a callback to the NFS client. In this
968 * case, the NFS server has to authenticate itself as "nfs" --
969 * even if there are other service keys such as "host" or "root"
972 * Another case when the kernel may specify the service attribute
973 * is when gssd is being asked to create the context for a
974 * SETCLIENT_ID operation. In this case, machine credentials
975 * must be used for the authentication. However, the service name
976 * used for this case is not important.
979 printerr(2, "%s: service is '%s'\n", __func__,
980 service ? service : "<null>");
981 if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
983 /* Tell krb5 gss which credentials cache to use */
984 for (dirname = ccachesearch; *dirname != NULL; dirname++) {
985 err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname);
986 if (err == -EKEYEXPIRED)
987 downcall_err = -EKEYEXPIRED;
989 create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
991 if (create_resp == 0)
995 if (create_resp != 0) {
996 if (uid == 0 && (root_uses_machine_creds == 1 ||
1001 gssd_refresh_krb5_machine_credential(clp->servername,
1005 * Get a list of credential cache names and try each
1006 * of them until one works or we've tried them all
1008 if (gssd_get_krb5_machine_cred_list(&credlist)) {
1009 printerr(0, "ERROR: No credentials found "
1010 "for connection to server %s\n",
1012 goto out_return_error;
1014 for (ccname = credlist; ccname && *ccname; ccname++) {
1015 gssd_setup_krb5_machine_gss_ccache(*ccname);
1016 if ((create_auth_rpc_client(clp, &rpc_clnt,
1018 AUTHTYPE_KRB5)) == 0) {
1023 printerr(2, "WARNING: Failed to create machine krb5 context "
1024 "with credentials cache %s for server %s\n",
1025 *ccname, clp->servername);
1027 gssd_free_krb5_machine_cred_list(credlist);
1031 printerr(2, "WARNING: Machine cache is prematurely expired or corrupted "
1032 "trying to recreate cache for server %s\n", clp->servername);
1034 printerr(1, "WARNING: Failed to create machine krb5 context "
1035 "with any credentials cache for server %s\n",
1037 goto out_return_error;
1042 printerr(1, "WARNING: Failed to create krb5 context "
1043 "for user with uid %d for server %s\n",
1044 uid, clp->servername);
1045 goto out_return_error;
1049 if (!authgss_get_private_data(auth, &pd)) {
1050 printerr(1, "WARNING: Failed to obtain authentication "
1051 "data for user with uid %d for server %s\n",
1052 uid, clp->servername);
1053 goto out_return_error;
1056 /* Grab the context lifetime to pass to the kernel. lifetime_rec
1057 * is set to zero on error */
1058 maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, NULL,
1059 &lifetime_rec, NULL, NULL, NULL, NULL);
1062 printerr(1, "WARNING: Failed to inquire context for lifetme "
1063 "maj_stat %u\n", maj_stat);
1065 if (serialize_context_for_kernel(pd.pd_ctx, &token, &krb5oid, NULL)) {
1066 printerr(0, "WARNING: Failed to serialize krb5 context for "
1067 "user with uid %d for server %s\n",
1068 uid, clp->servername);
1069 goto out_return_error;
1072 do_downcall(fd, uid, &pd, &token, lifetime_rec);
1077 #ifndef HAVE_LIBTIRPC
1078 if (pd.pd_ctx_hndl.length != 0)
1079 authgss_free_private_data(&pd);
1084 clnt_destroy(rpc_clnt);
1088 do_error_downcall(fd, uid, downcall_err);
1093 handle_krb5_upcall(struct clnt_info *clp)
1097 if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) {
1098 printerr(0, "WARNING: failed reading uid from krb5 "
1099 "upcall pipe: %s\n", strerror(errno));
1103 process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
1107 handle_gssd_upcall(struct clnt_info *clp)
1114 char *target = NULL;
1115 char *service = NULL;
1116 char *enctypes = NULL;
1118 printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
1120 if (readline(clp->gssd_fd, &lbuf, &lbuflen) != 1) {
1121 printerr(0, "WARNING: handle_gssd_upcall: "
1122 "failed reading request\n");
1125 printerr(2, "%s: '%s'\n", __func__, lbuf);
1127 /* find the mechanism name */
1128 if ((p = strstr(lbuf, "mech=")) != NULL) {
1129 mech = malloc(lbuflen);
1132 if (sscanf(p, "mech=%s", mech) != 1) {
1133 printerr(0, "WARNING: handle_gssd_upcall: "
1134 "failed to parse gss mechanism name "
1135 "in upcall string '%s'\n", lbuf);
1139 printerr(0, "WARNING: handle_gssd_upcall: "
1140 "failed to find gss mechanism name "
1141 "in upcall string '%s'\n", lbuf);
1146 if ((p = strstr(lbuf, "uid=")) != NULL) {
1147 if (sscanf(p, "uid=%d", &uid) != 1) {
1148 printerr(0, "WARNING: handle_gssd_upcall: "
1149 "failed to parse uid "
1150 "in upcall string '%s'\n", lbuf);
1154 printerr(0, "WARNING: handle_gssd_upcall: "
1155 "failed to find uid "
1156 "in upcall string '%s'\n", lbuf);
1160 /* read supported encryption types if supplied */
1161 if ((p = strstr(lbuf, "enctypes=")) != NULL) {
1162 enctypes = malloc(lbuflen);
1165 if (sscanf(p, "enctypes=%s", enctypes) != 1) {
1166 printerr(0, "WARNING: handle_gssd_upcall: "
1167 "failed to parse encryption types "
1168 "in upcall string '%s'\n", lbuf);
1171 if (parse_enctypes(enctypes) != 0) {
1172 printerr(0, "WARNING: handle_gssd_upcall: "
1173 "parsing encryption types failed: errno %d\n", errno);
1177 /* read target name */
1178 if ((p = strstr(lbuf, "target=")) != NULL) {
1179 target = malloc(lbuflen);
1182 if (sscanf(p, "target=%s", target) != 1) {
1183 printerr(0, "WARNING: handle_gssd_upcall: "
1184 "failed to parse target name "
1185 "in upcall string '%s'\n", lbuf);
1191 * read the service name
1193 * The presence of attribute "service=" indicates that machine
1194 * credentials should be used for this request. If the value
1195 * is "*", then any machine credentials available can be used.
1196 * If the value is anything else, then machine credentials for
1197 * the specified service name (always "nfs" for now) should be
1200 if ((p = strstr(lbuf, "service=")) != NULL) {
1201 service = malloc(lbuflen);
1204 if (sscanf(p, "service=%s", service) != 1) {
1205 printerr(0, "WARNING: handle_gssd_upcall: "
1206 "failed to parse service type "
1207 "in upcall string '%s'\n", lbuf);
1212 if (strcmp(mech, "krb5") == 0)
1213 process_krb5_upcall(clp, uid, clp->gssd_fd, target, service);
1215 printerr(0, "WARNING: handle_gssd_upcall: "
1216 "received unknown gss mech '%s'\n", mech);