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))
481 /* Used to read (and re-read) list of clients, set up poll array. */
483 update_client_list(void)
485 struct dirent **namelist;
488 if (chdir(pipefs_nfsdir) < 0) {
489 printerr(0, "ERROR: can't chdir to %s: %s\n",
490 pipefs_nfsdir, strerror(errno));
494 j = scandir(pipefs_nfsdir, &namelist, NULL, alphasort);
496 printerr(0, "ERROR: can't scandir %s: %s\n",
497 pipefs_nfsdir, 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 do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
515 gss_buffer_desc *context_token)
517 char *buf = NULL, *p = NULL, *end = NULL;
518 unsigned int timeout = context_timeout;
519 unsigned int buf_size = 0;
521 printerr(1, "doing downcall\n");
522 buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) +
523 sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length +
524 sizeof(context_token->length) + context_token->length;
525 p = buf = malloc(buf_size);
526 end = buf + buf_size;
528 if (WRITE_BYTES(&p, end, uid)) goto out_err;
529 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
530 if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err;
531 if (write_buffer(&p, end, &pd->pd_ctx_hndl)) goto out_err;
532 if (write_buffer(&p, end, context_token)) goto out_err;
534 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
539 printerr(1, "Failed to write downcall!\n");
544 do_error_downcall(int k5_fd, uid_t uid, int err)
547 char *p = buf, *end = buf + 1024;
548 unsigned int timeout = 0;
551 printerr(1, "doing error downcall\n");
553 if (WRITE_BYTES(&p, end, uid)) goto out_err;
554 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
555 /* use seq_win = 0 to indicate an error: */
556 if (WRITE_BYTES(&p, end, zero)) goto out_err;
557 if (WRITE_BYTES(&p, end, err)) goto out_err;
559 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
562 printerr(1, "Failed to write error downcall!\n");
567 * If the port isn't already set, do an rpcbind query to the remote server
568 * using the program and version and get the port.
570 * Newer kernels send the value of the port= mount option in the "info"
571 * file for the upcall or '0' for NFSv2/3. For NFSv4 it sends the value
572 * of the port= option or '2049'. The port field in a new sockaddr should
573 * reflect the value that was sent by the kernel.
576 populate_port(struct sockaddr *sa, const socklen_t salen,
577 const rpcprog_t program, const rpcvers_t version,
578 const unsigned short protocol)
580 struct sockaddr_in *s4 = (struct sockaddr_in *) sa;
581 #ifdef IPV6_SUPPORTED
582 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa;
583 #endif /* IPV6_SUPPORTED */
587 * Newer kernels send the port in the upcall. If we already have
588 * the port, there's no need to look it up.
590 switch (sa->sa_family) {
592 if (s4->sin_port != 0) {
593 printerr(2, "DEBUG: port already set to %d\n",
594 ntohs(s4->sin_port));
598 #ifdef IPV6_SUPPORTED
600 if (s6->sin6_port != 0) {
601 printerr(2, "DEBUG: port already set to %d\n",
602 ntohs(s6->sin6_port));
606 #endif /* IPV6_SUPPORTED */
608 printerr(0, "ERROR: unsupported address family %d\n",
614 * Newer kernels that send the port in the upcall set the value to
615 * 2049 for NFSv4 mounts when one isn't specified. The check below is
616 * only for kernels that don't send the port in the upcall. For those
617 * we either have to do an rpcbind query or set it to the standard
618 * port. Doing a query could be problematic (firewalls, etc), so take
619 * the latter approach.
621 if (program == 100003 && version == 4) {
626 port = nfs_getport(sa, salen, program, version, protocol);
628 printerr(0, "ERROR: unable to obtain port for prog %ld "
629 "vers %ld\n", program, version);
634 printerr(2, "DEBUG: setting port to %hu for prog %lu vers %lu\n", port,
637 switch (sa->sa_family) {
639 s4->sin_port = htons(port);
641 #ifdef IPV6_SUPPORTED
643 s6->sin6_port = htons(port);
645 #endif /* IPV6_SUPPORTED */
652 * Create an RPC connection and establish an authenticated
653 * gss context with a server.
655 int create_auth_rpc_client(struct clnt_info *clp,
656 CLIENT **clnt_return,
661 CLIENT *rpc_clnt = NULL;
662 struct rpc_gss_sec sec;
667 char rpc_errmsg[1024];
669 struct timeval timeout = {5, 0};
670 struct sockaddr *addr = (struct sockaddr *) &clp->addr;
673 /* Create the context as the user (not as root) */
674 save_uid = geteuid();
675 if (setfsuid(uid) != 0) {
676 printerr(0, "WARNING: Failed to setfsuid for "
677 "user with uid %d\n", uid);
680 printerr(2, "creating context using fsuid %d (save_uid %d)\n",
683 sec.qop = GSS_C_QOP_DEFAULT;
684 sec.svc = RPCSEC_GSS_SVC_NONE;
685 sec.cred = GSS_C_NO_CREDENTIAL;
687 if (authtype == AUTHTYPE_KRB5) {
688 sec.mech = (gss_OID)&krb5oid;
689 sec.req_flags = GSS_C_MUTUAL_FLAG;
691 else if (authtype == AUTHTYPE_SPKM3) {
692 sec.mech = (gss_OID)&spkm3oid;
693 /* XXX sec.req_flags = GSS_C_ANON_FLAG;
694 * Need a way to switch....
696 sec.req_flags = GSS_C_MUTUAL_FLAG;
699 printerr(0, "ERROR: Invalid authentication type (%d) "
700 "in create_auth_rpc_client\n", authtype);
705 if (authtype == AUTHTYPE_KRB5) {
706 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
708 * Do this before creating rpc connection since we won't need
709 * rpc connection if it fails!
711 if (limit_krb5_enctypes(&sec, uid)) {
712 printerr(1, "WARNING: Failed while limiting krb5 "
713 "encryption types for user with uid %d\n",
720 /* create an rpc connection to the nfs server */
722 printerr(2, "creating %s client for server %s\n", clp->protocol,
725 if ((strcmp(clp->protocol, "tcp")) == 0) {
726 protocol = IPPROTO_TCP;
727 } else if ((strcmp(clp->protocol, "udp")) == 0) {
728 protocol = IPPROTO_UDP;
730 printerr(0, "WARNING: unrecognized protocol, '%s', requested "
731 "for connection to server %s for user with uid %d\n",
732 clp->protocol, clp->servername, uid);
736 switch (addr->sa_family) {
738 salen = sizeof(struct sockaddr_in);
740 #ifdef IPV6_SUPPORTED
742 salen = sizeof(struct sockaddr_in6);
744 #endif /* IPV6_SUPPORTED */
746 printerr(1, "ERROR: Unknown address family %d\n",
751 if (!populate_port(addr, salen, clp->prog, clp->vers, protocol))
754 rpc_clnt = nfs_get_rpcclient(addr, salen, protocol, clp->prog,
755 clp->vers, &timeout);
757 snprintf(rpc_errmsg, sizeof(rpc_errmsg),
758 "WARNING: can't create %s rpc_clnt to server %s for "
760 protocol == IPPROTO_TCP ? "tcp" : "udp",
761 clp->servername, uid);
763 clnt_spcreateerror(rpc_errmsg));
767 printerr(2, "creating context with server %s\n", clp->servicename);
768 auth = authgss_create_default(rpc_clnt, clp->servicename, &sec);
770 /* Our caller should print appropriate message */
771 printerr(2, "WARNING: Failed to create %s context for "
772 "user with uid %d for server %s\n",
773 (authtype == AUTHTYPE_KRB5 ? "krb5":"spkm3"),
774 uid, clp->servername);
779 rpc_clnt->cl_auth = auth;
780 *clnt_return = rpc_clnt;
785 if (sec.cred != GSS_C_NO_CREDENTIAL)
786 gss_release_cred(&min_stat, &sec.cred);
787 /* Restore euid to original value */
788 if ((save_uid != -1) && (setfsuid(save_uid) != uid)) {
789 printerr(0, "WARNING: Failed to restore fsuid"
790 " to uid %d from %d\n", save_uid, uid);
795 /* Only destroy here if failure. Otherwise, caller is responsible */
796 if (rpc_clnt) clnt_destroy(rpc_clnt);
803 * this code uses the userland rpcsec gss library to create a krb5
804 * context on behalf of the kernel
807 handle_krb5_upcall(struct clnt_info *clp)
810 CLIENT *rpc_clnt = NULL;
812 struct authgss_private_data pd;
813 gss_buffer_desc token;
814 char **credlist = NULL;
817 int create_resp = -1;
819 printerr(1, "handling krb5 upcall\n");
823 memset(&pd, 0, sizeof(struct authgss_private_data));
825 if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
826 printerr(0, "WARNING: failed reading uid from krb5 "
827 "upcall pipe: %s\n", strerror(errno));
831 if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0)) {
832 /* Tell krb5 gss which credentials cache to use */
833 for (dirname = ccachesearch; *dirname != NULL; dirname++) {
834 if (gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname) == 0)
835 create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
837 if (create_resp == 0)
841 if (create_resp != 0) {
842 if (uid == 0 && root_uses_machine_creds == 1) {
846 gssd_refresh_krb5_machine_credential(clp->servername,
849 * Get a list of credential cache names and try each
850 * of them until one works or we've tried them all
852 if (gssd_get_krb5_machine_cred_list(&credlist)) {
853 printerr(0, "ERROR: No credentials found "
854 "for connection to server %s\n",
856 goto out_return_error;
858 for (ccname = credlist; ccname && *ccname; ccname++) {
859 gssd_setup_krb5_machine_gss_ccache(*ccname);
860 if ((create_auth_rpc_client(clp, &rpc_clnt,
862 AUTHTYPE_KRB5)) == 0) {
867 printerr(2, "WARNING: Failed to create machine krb5 context "
868 "with credentials cache %s for server %s\n",
869 *ccname, clp->servername);
871 gssd_free_krb5_machine_cred_list(credlist);
875 printerr(2, "WARNING: Machine cache is prematurely expired or corrupted "
876 "trying to recreate cache for server %s\n", clp->servername);
878 printerr(1, "WARNING: Failed to create machine krb5 context "
879 "with any credentials cache for server %s\n",
881 goto out_return_error;
886 printerr(1, "WARNING: Failed to create krb5 context "
887 "for user with uid %d for server %s\n",
888 uid, clp->servername);
889 goto out_return_error;
893 if (!authgss_get_private_data(auth, &pd)) {
894 printerr(1, "WARNING: Failed to obtain authentication "
895 "data for user with uid %d for server %s\n",
896 uid, clp->servername);
897 goto out_return_error;
900 if (serialize_context_for_kernel(pd.pd_ctx, &token, &krb5oid, NULL)) {
901 printerr(0, "WARNING: Failed to serialize krb5 context for "
902 "user with uid %d for server %s\n",
903 uid, clp->servername);
904 goto out_return_error;
907 do_downcall(clp->krb5_fd, uid, &pd, &token);
912 #ifndef HAVE_LIBTIRPC
913 if (pd.pd_ctx_hndl.length != 0)
914 authgss_free_private_data(&pd);
919 clnt_destroy(rpc_clnt);
923 do_error_downcall(clp->krb5_fd, uid, -1);
928 * this code uses the userland rpcsec gss library to create an spkm3
929 * context on behalf of the kernel
932 handle_spkm3_upcall(struct clnt_info *clp)
935 CLIENT *rpc_clnt = NULL;
937 struct authgss_private_data pd;
938 gss_buffer_desc token;
940 printerr(2, "handling spkm3 upcall\n");
945 if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) {
946 printerr(0, "WARNING: failed reading uid from spkm3 "
947 "upcall pipe: %s\n", strerror(errno));
951 if (create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, AUTHTYPE_SPKM3)) {
952 printerr(0, "WARNING: Failed to create spkm3 context for "
953 "user with uid %d\n", uid);
954 goto out_return_error;
957 if (!authgss_get_private_data(auth, &pd)) {
958 printerr(0, "WARNING: Failed to obtain authentication "
959 "data for user with uid %d for server %s\n",
960 uid, clp->servername);
961 goto out_return_error;
964 if (serialize_context_for_kernel(pd.pd_ctx, &token, &spkm3oid, NULL)) {
965 printerr(0, "WARNING: Failed to serialize spkm3 context for "
966 "user with uid %d for server\n",
967 uid, clp->servername);
968 goto out_return_error;
971 do_downcall(clp->spkm3_fd, uid, &pd, &token);
979 clnt_destroy(rpc_clnt);
983 do_error_downcall(clp->spkm3_fd, uid, -1);