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"
79 * array of struct pollfd suitable to pass to poll. initialized to
80 * zero - a zero struct is ignored by poll() because the events mask is 0.
83 * linked list of struct clnt_info which associates a clntXXX directory
84 * with an index into pollarray[], and other basic data about that client.
86 * Directory structure: created by the kernel
87 * {rpc_pipefs}/{dir}/clntXX : one per rpc_clnt struct in the kernel
88 * {rpc_pipefs}/{dir}/clntXX/krb5 : read uid for which kernel wants
89 * a context, write the resulting context
90 * {rpc_pipefs}/{dir}/clntXX/info : stores info such as server name
93 * Poll all {rpc_pipefs}/{dir}/clntXX/krb5 files. When data is ready,
94 * read and process; performs rpcsec_gss context initialization protocol to
95 * get a cred for that user. Writes result to corresponding krb5 file
96 * in a form the kernel code will understand.
97 * In addition, we make sure we are notified whenever anything is
98 * created or destroyed in {rpc_pipefs} or in any of the clntXX directories,
99 * and rescan the whole {rpc_pipefs} when this happens.
102 struct pollfd * pollarray;
104 int pollsize; /* the size of pollaray (in pollfd's) */
107 * convert a presentation address string to a sockaddr_storage struct. Returns
108 * true on success and false on failure.
110 * Note that we do not populate the sin6_scope_id field here for IPv6 addrs.
111 * gssd nececessarily relies on hostname resolution and DNS AAAA records
112 * do not generally contain scope-id's. This means that GSSAPI auth really
113 * can't work with IPv6 link-local addresses.
115 * We *could* consider changing this if we did something like adopt the
116 * Microsoft "standard" of using the ipv6-literal.net domainname, but it's
117 * not really feasible at present.
120 addrstr_to_sockaddr(struct sockaddr *sa, const char *addr, const int port)
122 struct sockaddr_in *s4 = (struct sockaddr_in *) sa;
123 #ifdef IPV6_SUPPORTED
124 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa;
125 #endif /* IPV6_SUPPORTED */
127 if (inet_pton(AF_INET, addr, &s4->sin_addr)) {
128 s4->sin_family = AF_INET;
129 s4->sin_port = htons(port);
130 #ifdef IPV6_SUPPORTED
131 } else if (inet_pton(AF_INET6, addr, &s6->sin6_addr)) {
132 s6->sin6_family = AF_INET6;
133 s6->sin6_port = htons(port);
134 #endif /* IPV6_SUPPORTED */
136 printerr(0, "ERROR: unable to convert %s to address\n", addr);
144 * convert a sockaddr to a hostname
147 sockaddr_to_hostname(const struct sockaddr *sa, const char *addr)
152 char hbuf[NI_MAXHOST];
154 switch (sa->sa_family) {
156 addrlen = sizeof(struct sockaddr_in);
158 #ifdef IPV6_SUPPORTED
160 addrlen = sizeof(struct sockaddr_in6);
162 #endif /* IPV6_SUPPORTED */
164 printerr(0, "ERROR: unrecognized addr family %d\n",
169 err = getnameinfo(sa, addrlen, hbuf, sizeof(hbuf), NULL, 0,
172 printerr(0, "ERROR: unable to resolve %s to hostname: %s\n",
173 addr, err == EAI_SYSTEM ? strerror(err) :
178 hostname = strdup(hbuf);
183 /* XXX buffer problems: */
185 read_service_info(char *info_file_name, char **servicename, char **servername,
186 int *prog, int *vers, char **protocol,
187 struct sockaddr *addr) {
188 #define INFOBUFLEN 256
189 char buf[INFOBUFLEN + 1];
190 static char dummy[128];
192 static char service[128];
193 static char address[128];
203 *servicename = *servername = *protocol = NULL;
205 if ((fd = open(info_file_name, O_RDONLY)) == -1) {
206 printerr(0, "ERROR: can't open %s: %s\n", info_file_name,
210 if ((nbytes = read(fd, buf, INFOBUFLEN)) == -1)
215 numfields = sscanf(buf,"RPC server: %127s\n"
216 "service: %127s %15s version %15s\n"
220 service, program, version,
224 if (numfields == 5) {
225 strcpy(protoname, "tcp");
226 } else if (numfields != 6) {
231 if ((p = strstr(buf, "port")) != NULL)
232 sscanf(p, "port: %127s\n", cb_port);
234 /* check service, program, and version */
235 if (memcmp(service, "nfs", 3) != 0)
237 *prog = atoi(program + 1); /* skip open paren */
238 *vers = atoi(version);
240 if (strlen(service) == 3 ) {
241 if ((*prog != 100003) || ((*vers != 2) && (*vers != 3) &&
244 } else if (memcmp(service, "nfs4_cb", 7) == 0) {
249 if (cb_port[0] != '\0') {
250 port = atoi(cb_port);
251 if (port < 0 || port > 65535)
255 if (!addrstr_to_sockaddr(addr, address, port))
258 *servername = sockaddr_to_hostname(addr, address);
259 if (*servername == NULL)
262 nbytes = snprintf(buf, INFOBUFLEN, "%s@%s", service, *servername);
263 if (nbytes > INFOBUFLEN)
266 if (!(*servicename = calloc(strlen(buf) + 1, 1)))
268 memcpy(*servicename, buf, strlen(buf));
270 if (!(*protocol = strdup(protoname)))
274 printerr(0, "ERROR: failed to read service info\n");
275 if (fd != -1) close(fd);
279 *servicename = *servername = *protocol = NULL;
284 destroy_client(struct clnt_info *clp)
286 if (clp->krb5_poll_index != -1)
287 memset(&pollarray[clp->krb5_poll_index], 0,
288 sizeof(struct pollfd));
289 if (clp->spkm3_poll_index != -1)
290 memset(&pollarray[clp->spkm3_poll_index], 0,
291 sizeof(struct pollfd));
292 if (clp->dir_fd != -1) close(clp->dir_fd);
293 if (clp->krb5_fd != -1) close(clp->krb5_fd);
294 if (clp->spkm3_fd != -1) close(clp->spkm3_fd);
296 free(clp->servicename);
297 free(clp->servername);
302 static struct clnt_info *
303 insert_new_clnt(void)
305 struct clnt_info *clp = NULL;
307 if (!(clp = (struct clnt_info *)calloc(1,sizeof(struct clnt_info)))) {
308 printerr(0, "ERROR: can't malloc clnt_info: %s\n",
312 clp->krb5_poll_index = -1;
313 clp->spkm3_poll_index = -1;
318 TAILQ_INSERT_HEAD(&clnt_list, clp, list);
324 process_clnt_dir_files(struct clnt_info * clp)
327 char info_file_name[PATH_MAX];
329 if (clp->krb5_fd == -1) {
330 snprintf(name, sizeof(name), "%s/krb5", clp->dirname);
331 clp->krb5_fd = open(name, O_RDWR);
333 if (clp->spkm3_fd == -1) {
334 snprintf(name, sizeof(name), "%s/spkm3", clp->dirname);
335 clp->spkm3_fd = open(name, O_RDWR);
337 if ((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
339 snprintf(info_file_name, sizeof(info_file_name), "%s/info",
341 if ((clp->servicename == NULL) &&
342 read_service_info(info_file_name, &clp->servicename,
343 &clp->servername, &clp->prog, &clp->vers,
344 &clp->protocol, (struct sockaddr *) &clp->addr))
350 get_poll_index(int *ind)
355 for (i=0; i<FD_ALLOC_BLOCK; i++) {
356 if (pollarray[i].events == 0) {
362 printerr(0, "ERROR: No pollarray slots open\n");
370 insert_clnt_poll(struct clnt_info *clp)
372 if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
373 if (get_poll_index(&clp->krb5_poll_index)) {
374 printerr(0, "ERROR: Too many krb5 clients\n");
377 pollarray[clp->krb5_poll_index].fd = clp->krb5_fd;
378 pollarray[clp->krb5_poll_index].events |= POLLIN;
381 if ((clp->spkm3_fd != -1) && (clp->spkm3_poll_index == -1)) {
382 if (get_poll_index(&clp->spkm3_poll_index)) {
383 printerr(0, "ERROR: Too many spkm3 clients\n");
386 pollarray[clp->spkm3_poll_index].fd = clp->spkm3_fd;
387 pollarray[clp->spkm3_poll_index].events |= POLLIN;
394 process_clnt_dir(char *dir, char *pdir)
396 struct clnt_info * clp;
398 if (!(clp = insert_new_clnt()))
399 goto fail_destroy_client;
401 /* An extra for the '/', and an extra for the null */
402 if (!(clp->dirname = calloc(strlen(dir) + strlen(pdir) + 2, 1))) {
403 goto fail_destroy_client;
405 sprintf(clp->dirname, "%s/%s", pdir, dir);
406 if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
407 printerr(0, "ERROR: can't open %s: %s\n",
408 clp->dirname, strerror(errno));
409 goto fail_destroy_client;
411 fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL);
412 fcntl(clp->dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MULTISHOT);
414 if (process_clnt_dir_files(clp))
415 goto fail_keep_client;
417 if (insert_clnt_poll(clp))
418 goto fail_destroy_client;
424 TAILQ_REMOVE(&clnt_list, clp, list);
428 /* We couldn't find some subdirectories, but we keep the client
429 * around in case we get a notification on the directory when the
430 * subdirectories are created. */
435 init_client_list(void)
437 TAILQ_INIT(&clnt_list);
438 /* Eventually plan to grow/shrink poll array: */
439 pollsize = FD_ALLOC_BLOCK;
440 pollarray = calloc(pollsize, sizeof(struct pollfd));
444 * This is run after a DNOTIFY signal, and should clear up any
445 * directories that are no longer around, and re-scan any existing
446 * directories, since the DNOTIFY could have been in there.
449 update_old_clients(struct dirent **namelist, int size, char *pdir)
451 struct clnt_info *clp;
454 char fname[PATH_MAX];
456 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
457 /* only compare entries in the global list that are from the
458 * same pipefs parent directory as "pdir"
460 if (strncmp(clp->dirname, pdir, strlen(pdir)) != 0) continue;
463 for (i=0; i < size; i++) {
464 snprintf(fname, sizeof(fname), "%s/%s",
465 pdir, namelist[i]->d_name);
466 if (strcmp(clp->dirname, fname) == 0) {
472 printerr(2, "destroying client %s\n", clp->dirname);
473 saveprev = clp->list.tqe_prev;
474 TAILQ_REMOVE(&clnt_list, clp, list);
479 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
480 if (!process_clnt_dir_files(clp))
481 insert_clnt_poll(clp);
485 /* Search for a client by directory name, return 1 if found, 0 otherwise */
487 find_client(char *dirname, char *pdir)
489 struct clnt_info *clp;
490 char fname[PATH_MAX];
492 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
493 snprintf(fname, sizeof(fname), "%s/%s", pdir, dirname);
494 if (strcmp(clp->dirname, fname) == 0)
501 process_pipedir(char *pipe_name)
503 struct dirent **namelist;
506 if (chdir(pipe_name) < 0) {
507 printerr(0, "ERROR: can't chdir to %s: %s\n",
508 pipe_name, strerror(errno));
512 j = scandir(pipe_name, &namelist, NULL, alphasort);
514 printerr(0, "ERROR: can't scandir %s: %s\n",
515 pipe_name, strerror(errno));
519 update_old_clients(namelist, j, pipe_name);
520 for (i=0; i < j; i++) {
521 if (i < FD_ALLOC_BLOCK
522 && !strncmp(namelist[i]->d_name, "clnt", 4)
523 && !find_client(namelist[i]->d_name, pipe_name))
524 process_clnt_dir(namelist[i]->d_name, pipe_name);
533 /* Used to read (and re-read) list of clients, set up poll array. */
535 update_client_list(void)
538 struct topdirs_info *tdi;
540 TAILQ_FOREACH(tdi, &topdirs_list, list) {
541 retval = process_pipedir(tdi->dirname);
543 printerr(1, "WARNING: error processing %s\n",
551 do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
552 gss_buffer_desc *context_token)
554 char *buf = NULL, *p = NULL, *end = NULL;
555 unsigned int timeout = context_timeout;
556 unsigned int buf_size = 0;
558 printerr(1, "doing downcall\n");
559 buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) +
560 sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length +
561 sizeof(context_token->length) + context_token->length;
562 p = buf = malloc(buf_size);
563 end = buf + buf_size;
565 if (WRITE_BYTES(&p, end, uid)) goto out_err;
566 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
567 if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err;
568 if (write_buffer(&p, end, &pd->pd_ctx_hndl)) goto out_err;
569 if (write_buffer(&p, end, context_token)) goto out_err;
571 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
576 printerr(1, "Failed to write downcall!\n");
581 do_error_downcall(int k5_fd, uid_t uid, int err)
584 char *p = buf, *end = buf + 1024;
585 unsigned int timeout = 0;
588 printerr(1, "doing error downcall\n");
590 if (WRITE_BYTES(&p, end, uid)) goto out_err;
591 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
592 /* use seq_win = 0 to indicate an error: */
593 if (WRITE_BYTES(&p, end, zero)) goto out_err;
594 if (WRITE_BYTES(&p, end, err)) goto out_err;
596 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
599 printerr(1, "Failed to write error downcall!\n");
604 * If the port isn't already set, do an rpcbind query to the remote server
605 * using the program and version and get the port.
607 * Newer kernels send the value of the port= mount option in the "info"
608 * file for the upcall or '0' for NFSv2/3. For NFSv4 it sends the value
609 * of the port= option or '2049'. The port field in a new sockaddr should
610 * reflect the value that was sent by the kernel.
613 populate_port(struct sockaddr *sa, const socklen_t salen,
614 const rpcprog_t program, const rpcvers_t version,
615 const unsigned short protocol)
617 struct sockaddr_in *s4 = (struct sockaddr_in *) sa;
618 #ifdef IPV6_SUPPORTED
619 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa;
620 #endif /* IPV6_SUPPORTED */
624 * Newer kernels send the port in the upcall. If we already have
625 * the port, there's no need to look it up.
627 switch (sa->sa_family) {
629 if (s4->sin_port != 0) {
630 printerr(2, "DEBUG: port already set to %d\n",
631 ntohs(s4->sin_port));
635 #ifdef IPV6_SUPPORTED
637 if (s6->sin6_port != 0) {
638 printerr(2, "DEBUG: port already set to %d\n",
639 ntohs(s6->sin6_port));
643 #endif /* IPV6_SUPPORTED */
645 printerr(0, "ERROR: unsupported address family %d\n",
651 * Newer kernels that send the port in the upcall set the value to
652 * 2049 for NFSv4 mounts when one isn't specified. The check below is
653 * only for kernels that don't send the port in the upcall. For those
654 * we either have to do an rpcbind query or set it to the standard
655 * port. Doing a query could be problematic (firewalls, etc), so take
656 * the latter approach.
658 if (program == 100003 && version == 4) {
663 port = nfs_getport(sa, salen, program, version, protocol);
665 printerr(0, "ERROR: unable to obtain port for prog %ld "
666 "vers %ld\n", program, version);
671 printerr(2, "DEBUG: setting port to %hu for prog %lu vers %lu\n", port,
674 switch (sa->sa_family) {
676 s4->sin_port = htons(port);
678 #ifdef IPV6_SUPPORTED
680 s6->sin6_port = htons(port);
682 #endif /* IPV6_SUPPORTED */
689 * Create an RPC connection and establish an authenticated
690 * gss context with a server.
692 int create_auth_rpc_client(struct clnt_info *clp,
693 CLIENT **clnt_return,
698 CLIENT *rpc_clnt = NULL;
699 struct rpc_gss_sec sec;
704 char rpc_errmsg[1024];
706 struct timeval timeout = {5, 0};
707 struct sockaddr *addr = (struct sockaddr *) &clp->addr;
710 /* Create the context as the user (not as root) */
711 save_uid = geteuid();
712 if (setfsuid(uid) != 0) {
713 printerr(0, "WARNING: Failed to setfsuid for "
714 "user with uid %d\n", uid);
717 printerr(2, "creating context using fsuid %d (save_uid %d)\n",
720 sec.qop = GSS_C_QOP_DEFAULT;
721 sec.svc = RPCSEC_GSS_SVC_NONE;
722 sec.cred = GSS_C_NO_CREDENTIAL;
724 if (authtype == AUTHTYPE_KRB5) {
725 sec.mech = (gss_OID)&krb5oid;
726 sec.req_flags = GSS_C_MUTUAL_FLAG;
728 else if (authtype == AUTHTYPE_SPKM3) {
729 sec.mech = (gss_OID)&spkm3oid;
730 /* XXX sec.req_flags = GSS_C_ANON_FLAG;
731 * Need a way to switch....
733 sec.req_flags = GSS_C_MUTUAL_FLAG;
736 printerr(0, "ERROR: Invalid authentication type (%d) "
737 "in create_auth_rpc_client\n", authtype);
742 if (authtype == AUTHTYPE_KRB5) {
743 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
745 * Do this before creating rpc connection since we won't need
746 * rpc connection if it fails!
748 if (limit_krb5_enctypes(&sec, uid)) {
749 printerr(1, "WARNING: Failed while limiting krb5 "
750 "encryption types for user with uid %d\n",
757 /* create an rpc connection to the nfs server */
759 printerr(2, "creating %s client for server %s\n", clp->protocol,
762 if ((strcmp(clp->protocol, "tcp")) == 0) {
763 protocol = IPPROTO_TCP;
764 } else if ((strcmp(clp->protocol, "udp")) == 0) {
765 protocol = IPPROTO_UDP;
767 printerr(0, "WARNING: unrecognized protocol, '%s', requested "
768 "for connection to server %s for user with uid %d\n",
769 clp->protocol, clp->servername, uid);
773 switch (addr->sa_family) {
775 salen = sizeof(struct sockaddr_in);
777 #ifdef IPV6_SUPPORTED
779 salen = sizeof(struct sockaddr_in6);
781 #endif /* IPV6_SUPPORTED */
783 printerr(1, "ERROR: Unknown address family %d\n",
788 if (!populate_port(addr, salen, clp->prog, clp->vers, protocol))
791 rpc_clnt = nfs_get_rpcclient(addr, salen, protocol, clp->prog,
792 clp->vers, &timeout);
794 snprintf(rpc_errmsg, sizeof(rpc_errmsg),
795 "WARNING: can't create %s rpc_clnt to server %s for "
797 protocol == IPPROTO_TCP ? "tcp" : "udp",
798 clp->servername, uid);
800 clnt_spcreateerror(rpc_errmsg));
804 printerr(2, "creating context with server %s\n", clp->servicename);
805 auth = authgss_create_default(rpc_clnt, clp->servicename, &sec);
807 /* Our caller should print appropriate message */
808 printerr(2, "WARNING: Failed to create %s context for "
809 "user with uid %d for server %s\n",
810 (authtype == AUTHTYPE_KRB5 ? "krb5":"spkm3"),
811 uid, clp->servername);
816 rpc_clnt->cl_auth = auth;
817 *clnt_return = rpc_clnt;
822 if (sec.cred != GSS_C_NO_CREDENTIAL)
823 gss_release_cred(&min_stat, &sec.cred);
824 /* Restore euid to original value */
825 if ((save_uid != -1) && (setfsuid(save_uid) != uid)) {
826 printerr(0, "WARNING: Failed to restore fsuid"
827 " to uid %d from %d\n", save_uid, uid);
832 /* Only destroy here if failure. Otherwise, caller is responsible */
833 if (rpc_clnt) clnt_destroy(rpc_clnt);
840 * this code uses the userland rpcsec gss library to create a krb5
841 * context on behalf of the kernel
844 handle_krb5_upcall(struct clnt_info *clp)
847 CLIENT *rpc_clnt = NULL;
849 struct authgss_private_data pd;
850 gss_buffer_desc token;
851 char **credlist = NULL;
854 int create_resp = -1;
856 printerr(1, "handling krb5 upcall\n");
860 memset(&pd, 0, sizeof(struct authgss_private_data));
862 if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
863 printerr(0, "WARNING: failed reading uid from krb5 "
864 "upcall pipe: %s\n", strerror(errno));
868 if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0)) {
869 /* Tell krb5 gss which credentials cache to use */
870 for (dirname = ccachesearch; *dirname != NULL; dirname++) {
871 if (gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname) == 0)
872 create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
874 if (create_resp == 0)
878 if (create_resp != 0) {
879 if (uid == 0 && root_uses_machine_creds == 1) {
883 gssd_refresh_krb5_machine_credential(clp->servername,
886 * Get a list of credential cache names and try each
887 * of them until one works or we've tried them all
889 if (gssd_get_krb5_machine_cred_list(&credlist)) {
890 printerr(0, "ERROR: No credentials found "
891 "for connection to server %s\n",
893 goto out_return_error;
895 for (ccname = credlist; ccname && *ccname; ccname++) {
896 gssd_setup_krb5_machine_gss_ccache(*ccname);
897 if ((create_auth_rpc_client(clp, &rpc_clnt,
899 AUTHTYPE_KRB5)) == 0) {
904 printerr(2, "WARNING: Failed to create machine krb5 context "
905 "with credentials cache %s for server %s\n",
906 *ccname, clp->servername);
908 gssd_free_krb5_machine_cred_list(credlist);
912 printerr(2, "WARNING: Machine cache is prematurely expired or corrupted "
913 "trying to recreate cache for server %s\n", clp->servername);
915 printerr(1, "WARNING: Failed to create machine krb5 context "
916 "with any credentials cache for server %s\n",
918 goto out_return_error;
923 printerr(1, "WARNING: Failed to create krb5 context "
924 "for user with uid %d for server %s\n",
925 uid, clp->servername);
926 goto out_return_error;
930 if (!authgss_get_private_data(auth, &pd)) {
931 printerr(1, "WARNING: Failed to obtain authentication "
932 "data for user with uid %d for server %s\n",
933 uid, clp->servername);
934 goto out_return_error;
937 if (serialize_context_for_kernel(pd.pd_ctx, &token, &krb5oid, NULL)) {
938 printerr(0, "WARNING: Failed to serialize krb5 context for "
939 "user with uid %d for server %s\n",
940 uid, clp->servername);
941 goto out_return_error;
944 do_downcall(clp->krb5_fd, uid, &pd, &token);
949 #ifndef HAVE_LIBTIRPC
950 if (pd.pd_ctx_hndl.length != 0)
951 authgss_free_private_data(&pd);
956 clnt_destroy(rpc_clnt);
960 do_error_downcall(clp->krb5_fd, uid, -1);
965 * this code uses the userland rpcsec gss library to create an spkm3
966 * context on behalf of the kernel
969 handle_spkm3_upcall(struct clnt_info *clp)
972 CLIENT *rpc_clnt = NULL;
974 struct authgss_private_data pd;
975 gss_buffer_desc token;
977 printerr(2, "handling spkm3 upcall\n");
982 if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) {
983 printerr(0, "WARNING: failed reading uid from spkm3 "
984 "upcall pipe: %s\n", strerror(errno));
988 if (create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, AUTHTYPE_SPKM3)) {
989 printerr(0, "WARNING: Failed to create spkm3 context for "
990 "user with uid %d\n", uid);
991 goto out_return_error;
994 if (!authgss_get_private_data(auth, &pd)) {
995 printerr(0, "WARNING: Failed to obtain authentication "
996 "data for user with uid %d for server %s\n",
997 uid, clp->servername);
998 goto out_return_error;
1001 if (serialize_context_for_kernel(pd.pd_ctx, &token, &spkm3oid, NULL)) {
1002 printerr(0, "WARNING: Failed to serialize spkm3 context for "
1003 "user with uid %d for server\n",
1004 uid, clp->servername);
1005 goto out_return_error;
1008 do_downcall(clp->spkm3_fd, uid, &pd, &token);
1016 clnt_destroy(rpc_clnt);
1020 do_error_downcall(clp->spkm3_fd, uid, -1);