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 nfs client
87 * {pipefs_nfsdir}/clntXX : one per rpc_clnt struct in the kernel
88 * {pipefs_nfsdir}/clntXX/krb5 : read uid for which kernel wants
89 * a context, write the resulting context
90 * {pipefs_nfsdir}/clntXX/info : stores info such as server name
93 * Poll all {pipefs_nfsdir}/clntXX/krb5 files. When ready, data read
94 * is a uid; 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 {pipefs_nfsdir} or in an of the clntXX directories,
99 * and rescan the whole {pipefs_nfsdir} 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)) return -1;
236 *prog = atoi(program + 1); /* skip open paren */
237 *vers = atoi(version);
238 if((*prog != 100003) || ((*vers != 2) && (*vers != 3) && (*vers != 4)))
241 if (cb_port[0] != '\0') {
242 port = atoi(cb_port);
243 if (port < 0 || port > 65535)
247 if (!addrstr_to_sockaddr(addr, address, port))
250 *servername = sockaddr_to_hostname(addr, address);
251 if (*servername == NULL)
254 nbytes = snprintf(buf, INFOBUFLEN, "%s@%s", service, *servername);
255 if (nbytes > INFOBUFLEN)
258 if (!(*servicename = calloc(strlen(buf) + 1, 1)))
260 memcpy(*servicename, buf, strlen(buf));
262 if (!(*protocol = strdup(protoname)))
266 printerr(0, "ERROR: failed to read service info\n");
267 if (fd != -1) close(fd);
271 *servicename = *servername = *protocol = NULL;
276 destroy_client(struct clnt_info *clp)
278 if (clp->krb5_poll_index != -1)
279 memset(&pollarray[clp->krb5_poll_index], 0,
280 sizeof(struct pollfd));
281 if (clp->spkm3_poll_index != -1)
282 memset(&pollarray[clp->spkm3_poll_index], 0,
283 sizeof(struct pollfd));
284 if (clp->dir_fd != -1) close(clp->dir_fd);
285 if (clp->krb5_fd != -1) close(clp->krb5_fd);
286 if (clp->spkm3_fd != -1) close(clp->spkm3_fd);
288 free(clp->servicename);
289 free(clp->servername);
294 static struct clnt_info *
295 insert_new_clnt(void)
297 struct clnt_info *clp = NULL;
299 if (!(clp = (struct clnt_info *)calloc(1,sizeof(struct clnt_info)))) {
300 printerr(0, "ERROR: can't malloc clnt_info: %s\n",
304 clp->krb5_poll_index = -1;
305 clp->spkm3_poll_index = -1;
310 TAILQ_INSERT_HEAD(&clnt_list, clp, list);
316 process_clnt_dir_files(struct clnt_info * clp)
320 char info_file_name[32];
322 if (clp->krb5_fd == -1) {
323 snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname);
324 clp->krb5_fd = open(kname, O_RDWR);
326 if (clp->spkm3_fd == -1) {
327 snprintf(sname, sizeof(sname), "%s/spkm3", clp->dirname);
328 clp->spkm3_fd = open(sname, O_RDWR);
330 if((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
332 snprintf(info_file_name, sizeof(info_file_name), "%s/info",
334 if ((clp->servicename == NULL) &&
335 read_service_info(info_file_name, &clp->servicename,
336 &clp->servername, &clp->prog, &clp->vers,
337 &clp->protocol, (struct sockaddr *) &clp->addr))
343 get_poll_index(int *ind)
348 for (i=0; i<FD_ALLOC_BLOCK; i++) {
349 if (pollarray[i].events == 0) {
355 printerr(0, "ERROR: No pollarray slots open\n");
363 insert_clnt_poll(struct clnt_info *clp)
365 if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
366 if (get_poll_index(&clp->krb5_poll_index)) {
367 printerr(0, "ERROR: Too many krb5 clients\n");
370 pollarray[clp->krb5_poll_index].fd = clp->krb5_fd;
371 pollarray[clp->krb5_poll_index].events |= POLLIN;
374 if ((clp->spkm3_fd != -1) && (clp->spkm3_poll_index == -1)) {
375 if (get_poll_index(&clp->spkm3_poll_index)) {
376 printerr(0, "ERROR: Too many spkm3 clients\n");
379 pollarray[clp->spkm3_poll_index].fd = clp->spkm3_fd;
380 pollarray[clp->spkm3_poll_index].events |= POLLIN;
387 process_clnt_dir(char *dir)
389 struct clnt_info * clp;
391 if (!(clp = insert_new_clnt()))
392 goto fail_destroy_client;
394 if (!(clp->dirname = calloc(strlen(dir) + 1, 1))) {
395 goto fail_destroy_client;
397 memcpy(clp->dirname, dir, strlen(dir));
398 if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
399 printerr(0, "ERROR: can't open %s: %s\n",
400 clp->dirname, strerror(errno));
401 goto fail_destroy_client;
403 fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL);
404 fcntl(clp->dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MULTISHOT);
406 if (process_clnt_dir_files(clp))
407 goto fail_keep_client;
409 if (insert_clnt_poll(clp))
410 goto fail_destroy_client;
416 TAILQ_REMOVE(&clnt_list, clp, list);
420 /* We couldn't find some subdirectories, but we keep the client
421 * around in case we get a notification on the directory when the
422 * subdirectories are created. */
427 init_client_list(void)
429 TAILQ_INIT(&clnt_list);
430 /* Eventually plan to grow/shrink poll array: */
431 pollsize = FD_ALLOC_BLOCK;
432 pollarray = calloc(pollsize, sizeof(struct pollfd));
436 * This is run after a DNOTIFY signal, and should clear up any
437 * directories that are no longer around, and re-scan any existing
438 * directories, since the DNOTIFY could have been in there.
441 update_old_clients(struct dirent **namelist, int size)
443 struct clnt_info *clp;
447 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
449 for (i=0; i < size; i++) {
450 if (!strcmp(clp->dirname, namelist[i]->d_name)) {
456 printerr(2, "destroying client %s\n", clp->dirname);
457 saveprev = clp->list.tqe_prev;
458 TAILQ_REMOVE(&clnt_list, clp, list);
463 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
464 if (!process_clnt_dir_files(clp))
465 insert_clnt_poll(clp);
469 /* Search for a client by directory name, return 1 if found, 0 otherwise */
471 find_client(char *dirname)
473 struct clnt_info *clp;
475 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
476 if (!strcmp(clp->dirname, dirname))
482 process_pipedir(char *pipe_name)
484 struct dirent **namelist;
487 if (chdir(pipe_name) < 0) {
488 printerr(0, "ERROR: can't chdir to %s: %s\n",
489 pipe_name, strerror(errno));
493 j = scandir(pipe_name, &namelist, NULL, alphasort);
495 printerr(0, "ERROR: can't scandir %s: %s\n",
496 pipe_name, strerror(errno));
500 update_old_clients(namelist, j);
501 for (i=0; i < j; i++) {
502 if (i < FD_ALLOC_BLOCK
503 && !strncmp(namelist[i]->d_name, "clnt", 4)
504 && !find_client(namelist[i]->d_name))
505 process_clnt_dir(namelist[i]->d_name);
514 /* Used to read (and re-read) list of clients, set up poll array. */
516 update_client_list(void)
520 retval = process_pipedir(pipefs_nfsdir);
522 printerr(0, "ERROR: processing %s\n", pipefs_nfsdir);
528 do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
529 gss_buffer_desc *context_token)
531 char *buf = NULL, *p = NULL, *end = NULL;
532 unsigned int timeout = context_timeout;
533 unsigned int buf_size = 0;
535 printerr(1, "doing downcall\n");
536 buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) +
537 sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length +
538 sizeof(context_token->length) + context_token->length;
539 p = buf = malloc(buf_size);
540 end = buf + buf_size;
542 if (WRITE_BYTES(&p, end, uid)) goto out_err;
543 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
544 if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err;
545 if (write_buffer(&p, end, &pd->pd_ctx_hndl)) goto out_err;
546 if (write_buffer(&p, end, context_token)) goto out_err;
548 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
553 printerr(1, "Failed to write downcall!\n");
558 do_error_downcall(int k5_fd, uid_t uid, int err)
561 char *p = buf, *end = buf + 1024;
562 unsigned int timeout = 0;
565 printerr(1, "doing error downcall\n");
567 if (WRITE_BYTES(&p, end, uid)) goto out_err;
568 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
569 /* use seq_win = 0 to indicate an error: */
570 if (WRITE_BYTES(&p, end, zero)) goto out_err;
571 if (WRITE_BYTES(&p, end, err)) goto out_err;
573 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
576 printerr(1, "Failed to write error downcall!\n");
581 * If the port isn't already set, do an rpcbind query to the remote server
582 * using the program and version and get the port.
584 * Newer kernels send the value of the port= mount option in the "info"
585 * file for the upcall or '0' for NFSv2/3. For NFSv4 it sends the value
586 * of the port= option or '2049'. The port field in a new sockaddr should
587 * reflect the value that was sent by the kernel.
590 populate_port(struct sockaddr *sa, const socklen_t salen,
591 const rpcprog_t program, const rpcvers_t version,
592 const unsigned short protocol)
594 struct sockaddr_in *s4 = (struct sockaddr_in *) sa;
595 #ifdef IPV6_SUPPORTED
596 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa;
597 #endif /* IPV6_SUPPORTED */
601 * Newer kernels send the port in the upcall. If we already have
602 * the port, there's no need to look it up.
604 switch (sa->sa_family) {
606 if (s4->sin_port != 0) {
607 printerr(2, "DEBUG: port already set to %d\n",
608 ntohs(s4->sin_port));
612 #ifdef IPV6_SUPPORTED
614 if (s6->sin6_port != 0) {
615 printerr(2, "DEBUG: port already set to %d\n",
616 ntohs(s6->sin6_port));
620 #endif /* IPV6_SUPPORTED */
622 printerr(0, "ERROR: unsupported address family %d\n",
628 * Newer kernels that send the port in the upcall set the value to
629 * 2049 for NFSv4 mounts when one isn't specified. The check below is
630 * only for kernels that don't send the port in the upcall. For those
631 * we either have to do an rpcbind query or set it to the standard
632 * port. Doing a query could be problematic (firewalls, etc), so take
633 * the latter approach.
635 if (program == 100003 && version == 4) {
640 port = nfs_getport(sa, salen, program, version, protocol);
642 printerr(0, "ERROR: unable to obtain port for prog %ld "
643 "vers %ld\n", program, version);
648 printerr(2, "DEBUG: setting port to %hu for prog %lu vers %lu\n", port,
651 switch (sa->sa_family) {
653 s4->sin_port = htons(port);
655 #ifdef IPV6_SUPPORTED
657 s6->sin6_port = htons(port);
659 #endif /* IPV6_SUPPORTED */
666 * Create an RPC connection and establish an authenticated
667 * gss context with a server.
669 int create_auth_rpc_client(struct clnt_info *clp,
670 CLIENT **clnt_return,
675 CLIENT *rpc_clnt = NULL;
676 struct rpc_gss_sec sec;
681 char rpc_errmsg[1024];
683 struct timeval timeout = {5, 0};
684 struct sockaddr *addr = (struct sockaddr *) &clp->addr;
687 /* Create the context as the user (not as root) */
688 save_uid = geteuid();
689 if (setfsuid(uid) != 0) {
690 printerr(0, "WARNING: Failed to setfsuid for "
691 "user with uid %d\n", uid);
694 printerr(2, "creating context using fsuid %d (save_uid %d)\n",
697 sec.qop = GSS_C_QOP_DEFAULT;
698 sec.svc = RPCSEC_GSS_SVC_NONE;
699 sec.cred = GSS_C_NO_CREDENTIAL;
701 if (authtype == AUTHTYPE_KRB5) {
702 sec.mech = (gss_OID)&krb5oid;
703 sec.req_flags = GSS_C_MUTUAL_FLAG;
705 else if (authtype == AUTHTYPE_SPKM3) {
706 sec.mech = (gss_OID)&spkm3oid;
707 /* XXX sec.req_flags = GSS_C_ANON_FLAG;
708 * Need a way to switch....
710 sec.req_flags = GSS_C_MUTUAL_FLAG;
713 printerr(0, "ERROR: Invalid authentication type (%d) "
714 "in create_auth_rpc_client\n", authtype);
719 if (authtype == AUTHTYPE_KRB5) {
720 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
722 * Do this before creating rpc connection since we won't need
723 * rpc connection if it fails!
725 if (limit_krb5_enctypes(&sec, uid)) {
726 printerr(1, "WARNING: Failed while limiting krb5 "
727 "encryption types for user with uid %d\n",
734 /* create an rpc connection to the nfs server */
736 printerr(2, "creating %s client for server %s\n", clp->protocol,
739 if ((strcmp(clp->protocol, "tcp")) == 0) {
740 protocol = IPPROTO_TCP;
741 } else if ((strcmp(clp->protocol, "udp")) == 0) {
742 protocol = IPPROTO_UDP;
744 printerr(0, "WARNING: unrecognized protocol, '%s', requested "
745 "for connection to server %s for user with uid %d\n",
746 clp->protocol, clp->servername, uid);
750 switch (addr->sa_family) {
752 salen = sizeof(struct sockaddr_in);
754 #ifdef IPV6_SUPPORTED
756 salen = sizeof(struct sockaddr_in6);
758 #endif /* IPV6_SUPPORTED */
760 printerr(1, "ERROR: Unknown address family %d\n",
765 if (!populate_port(addr, salen, clp->prog, clp->vers, protocol))
768 rpc_clnt = nfs_get_rpcclient(addr, salen, protocol, clp->prog,
769 clp->vers, &timeout);
771 snprintf(rpc_errmsg, sizeof(rpc_errmsg),
772 "WARNING: can't create %s rpc_clnt to server %s for "
774 protocol == IPPROTO_TCP ? "tcp" : "udp",
775 clp->servername, uid);
777 clnt_spcreateerror(rpc_errmsg));
781 printerr(2, "creating context with server %s\n", clp->servicename);
782 auth = authgss_create_default(rpc_clnt, clp->servicename, &sec);
784 /* Our caller should print appropriate message */
785 printerr(2, "WARNING: Failed to create %s context for "
786 "user with uid %d for server %s\n",
787 (authtype == AUTHTYPE_KRB5 ? "krb5":"spkm3"),
788 uid, clp->servername);
793 rpc_clnt->cl_auth = auth;
794 *clnt_return = rpc_clnt;
799 if (sec.cred != GSS_C_NO_CREDENTIAL)
800 gss_release_cred(&min_stat, &sec.cred);
801 /* Restore euid to original value */
802 if ((save_uid != -1) && (setfsuid(save_uid) != uid)) {
803 printerr(0, "WARNING: Failed to restore fsuid"
804 " to uid %d from %d\n", save_uid, uid);
809 /* Only destroy here if failure. Otherwise, caller is responsible */
810 if (rpc_clnt) clnt_destroy(rpc_clnt);
817 * this code uses the userland rpcsec gss library to create a krb5
818 * context on behalf of the kernel
821 handle_krb5_upcall(struct clnt_info *clp)
824 CLIENT *rpc_clnt = NULL;
826 struct authgss_private_data pd;
827 gss_buffer_desc token;
828 char **credlist = NULL;
831 int create_resp = -1;
833 printerr(1, "handling krb5 upcall\n");
837 memset(&pd, 0, sizeof(struct authgss_private_data));
839 if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
840 printerr(0, "WARNING: failed reading uid from krb5 "
841 "upcall pipe: %s\n", strerror(errno));
845 if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0)) {
846 /* Tell krb5 gss which credentials cache to use */
847 for (dirname = ccachesearch; *dirname != NULL; dirname++) {
848 if (gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname) == 0)
849 create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
851 if (create_resp == 0)
855 if (create_resp != 0) {
856 if (uid == 0 && root_uses_machine_creds == 1) {
860 gssd_refresh_krb5_machine_credential(clp->servername,
863 * Get a list of credential cache names and try each
864 * of them until one works or we've tried them all
866 if (gssd_get_krb5_machine_cred_list(&credlist)) {
867 printerr(0, "ERROR: No credentials found "
868 "for connection to server %s\n",
870 goto out_return_error;
872 for (ccname = credlist; ccname && *ccname; ccname++) {
873 gssd_setup_krb5_machine_gss_ccache(*ccname);
874 if ((create_auth_rpc_client(clp, &rpc_clnt,
876 AUTHTYPE_KRB5)) == 0) {
881 printerr(2, "WARNING: Failed to create machine krb5 context "
882 "with credentials cache %s for server %s\n",
883 *ccname, clp->servername);
885 gssd_free_krb5_machine_cred_list(credlist);
889 printerr(2, "WARNING: Machine cache is prematurely expired or corrupted "
890 "trying to recreate cache for server %s\n", clp->servername);
892 printerr(1, "WARNING: Failed to create machine krb5 context "
893 "with any credentials cache for server %s\n",
895 goto out_return_error;
900 printerr(1, "WARNING: Failed to create krb5 context "
901 "for user with uid %d for server %s\n",
902 uid, clp->servername);
903 goto out_return_error;
907 if (!authgss_get_private_data(auth, &pd)) {
908 printerr(1, "WARNING: Failed to obtain authentication "
909 "data for user with uid %d for server %s\n",
910 uid, clp->servername);
911 goto out_return_error;
914 if (serialize_context_for_kernel(pd.pd_ctx, &token, &krb5oid, NULL)) {
915 printerr(0, "WARNING: Failed to serialize krb5 context for "
916 "user with uid %d for server %s\n",
917 uid, clp->servername);
918 goto out_return_error;
921 do_downcall(clp->krb5_fd, uid, &pd, &token);
926 #ifndef HAVE_LIBTIRPC
927 if (pd.pd_ctx_hndl.length != 0)
928 authgss_free_private_data(&pd);
933 clnt_destroy(rpc_clnt);
937 do_error_downcall(clp->krb5_fd, uid, -1);
942 * this code uses the userland rpcsec gss library to create an spkm3
943 * context on behalf of the kernel
946 handle_spkm3_upcall(struct clnt_info *clp)
949 CLIENT *rpc_clnt = NULL;
951 struct authgss_private_data pd;
952 gss_buffer_desc token;
954 printerr(2, "handling spkm3 upcall\n");
959 if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) {
960 printerr(0, "WARNING: failed reading uid from spkm3 "
961 "upcall pipe: %s\n", strerror(errno));
965 if (create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, AUTHTYPE_SPKM3)) {
966 printerr(0, "WARNING: Failed to create spkm3 context for "
967 "user with uid %d\n", uid);
968 goto out_return_error;
971 if (!authgss_get_private_data(auth, &pd)) {
972 printerr(0, "WARNING: Failed to obtain authentication "
973 "data for user with uid %d for server %s\n",
974 uid, clp->servername);
975 goto out_return_error;
978 if (serialize_context_for_kernel(pd.pd_ctx, &token, &spkm3oid, NULL)) {
979 printerr(0, "WARNING: Failed to serialize spkm3 context for "
980 "user with uid %d for server\n",
981 uid, clp->servername);
982 goto out_return_error;
985 do_downcall(clp->spkm3_fd, uid, &pd, &token);
993 clnt_destroy(rpc_clnt);
997 do_error_downcall(clp->spkm3_fd, uid, -1);