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.
111 addrstr_to_sockaddr(struct sockaddr *sa, const char *addr, const int port)
113 struct sockaddr_in *s4 = (struct sockaddr_in *) sa;
115 if (inet_pton(AF_INET, addr, &s4->sin_addr)) {
116 s4->sin_family = AF_INET;
117 s4->sin_port = htons(port);
119 printerr(0, "ERROR: unable to convert %s to address\n", addr);
127 * convert a sockaddr to a hostname
130 sockaddr_to_hostname(const struct sockaddr *sa, const char *addr)
135 char hbuf[NI_MAXHOST];
137 switch (sa->sa_family) {
139 addrlen = sizeof(struct sockaddr_in);
142 printerr(0, "ERROR: unrecognized addr family %d\n",
147 err = getnameinfo(sa, addrlen, hbuf, sizeof(hbuf), NULL, 0,
150 printerr(0, "ERROR: unable to resolve %s to hostname: %s\n",
151 addr, err == EAI_SYSTEM ? strerror(err) :
156 hostname = strdup(hbuf);
161 /* XXX buffer problems: */
163 read_service_info(char *info_file_name, char **servicename, char **servername,
164 int *prog, int *vers, char **protocol,
165 struct sockaddr *addr) {
166 #define INFOBUFLEN 256
167 char buf[INFOBUFLEN + 1];
168 static char dummy[128];
170 static char service[128];
171 static char address[128];
181 *servicename = *servername = *protocol = NULL;
183 if ((fd = open(info_file_name, O_RDONLY)) == -1) {
184 printerr(0, "ERROR: can't open %s: %s\n", info_file_name,
188 if ((nbytes = read(fd, buf, INFOBUFLEN)) == -1)
193 numfields = sscanf(buf,"RPC server: %127s\n"
194 "service: %127s %15s version %15s\n"
198 service, program, version,
202 if (numfields == 5) {
203 strcpy(protoname, "tcp");
204 } else if (numfields != 6) {
209 if ((p = strstr(buf, "port")) != NULL)
210 sscanf(p, "port: %127s\n", cb_port);
212 /* check service, program, and version */
213 if(memcmp(service, "nfs", 3)) return -1;
214 *prog = atoi(program + 1); /* skip open paren */
215 *vers = atoi(version);
216 if((*prog != 100003) || ((*vers != 2) && (*vers != 3) && (*vers != 4)))
219 if (cb_port[0] != '\0') {
220 port = atoi(cb_port);
221 if (port < 0 || port > 65535)
225 if (!addrstr_to_sockaddr(addr, address, port))
228 *servername = sockaddr_to_hostname(addr, address);
229 if (*servername == NULL)
232 nbytes = snprintf(buf, INFOBUFLEN, "%s@%s", service, *servername);
233 if (nbytes > INFOBUFLEN)
236 if (!(*servicename = calloc(strlen(buf) + 1, 1)))
238 memcpy(*servicename, buf, strlen(buf));
240 if (!(*protocol = strdup(protoname)))
244 printerr(0, "ERROR: failed to read service info\n");
245 if (fd != -1) close(fd);
249 *servicename = *servername = *protocol = NULL;
254 destroy_client(struct clnt_info *clp)
256 if (clp->krb5_poll_index != -1)
257 memset(&pollarray[clp->krb5_poll_index], 0,
258 sizeof(struct pollfd));
259 if (clp->spkm3_poll_index != -1)
260 memset(&pollarray[clp->spkm3_poll_index], 0,
261 sizeof(struct pollfd));
262 if (clp->dir_fd != -1) close(clp->dir_fd);
263 if (clp->krb5_fd != -1) close(clp->krb5_fd);
264 if (clp->spkm3_fd != -1) close(clp->spkm3_fd);
266 free(clp->servicename);
267 free(clp->servername);
272 static struct clnt_info *
273 insert_new_clnt(void)
275 struct clnt_info *clp = NULL;
277 if (!(clp = (struct clnt_info *)calloc(1,sizeof(struct clnt_info)))) {
278 printerr(0, "ERROR: can't malloc clnt_info: %s\n",
282 clp->krb5_poll_index = -1;
283 clp->spkm3_poll_index = -1;
288 TAILQ_INSERT_HEAD(&clnt_list, clp, list);
294 process_clnt_dir_files(struct clnt_info * clp)
298 char info_file_name[32];
300 if (clp->krb5_fd == -1) {
301 snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname);
302 clp->krb5_fd = open(kname, O_RDWR);
304 if (clp->spkm3_fd == -1) {
305 snprintf(sname, sizeof(sname), "%s/spkm3", clp->dirname);
306 clp->spkm3_fd = open(sname, O_RDWR);
308 if((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
310 snprintf(info_file_name, sizeof(info_file_name), "%s/info",
312 if ((clp->servicename == NULL) &&
313 read_service_info(info_file_name, &clp->servicename,
314 &clp->servername, &clp->prog, &clp->vers,
315 &clp->protocol, (struct sockaddr *) &clp->addr))
321 get_poll_index(int *ind)
326 for (i=0; i<FD_ALLOC_BLOCK; i++) {
327 if (pollarray[i].events == 0) {
333 printerr(0, "ERROR: No pollarray slots open\n");
341 insert_clnt_poll(struct clnt_info *clp)
343 if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
344 if (get_poll_index(&clp->krb5_poll_index)) {
345 printerr(0, "ERROR: Too many krb5 clients\n");
348 pollarray[clp->krb5_poll_index].fd = clp->krb5_fd;
349 pollarray[clp->krb5_poll_index].events |= POLLIN;
352 if ((clp->spkm3_fd != -1) && (clp->spkm3_poll_index == -1)) {
353 if (get_poll_index(&clp->spkm3_poll_index)) {
354 printerr(0, "ERROR: Too many spkm3 clients\n");
357 pollarray[clp->spkm3_poll_index].fd = clp->spkm3_fd;
358 pollarray[clp->spkm3_poll_index].events |= POLLIN;
365 process_clnt_dir(char *dir)
367 struct clnt_info * clp;
369 if (!(clp = insert_new_clnt()))
370 goto fail_destroy_client;
372 if (!(clp->dirname = calloc(strlen(dir) + 1, 1))) {
373 goto fail_destroy_client;
375 memcpy(clp->dirname, dir, strlen(dir));
376 if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
377 printerr(0, "ERROR: can't open %s: %s\n",
378 clp->dirname, strerror(errno));
379 goto fail_destroy_client;
381 fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL);
382 fcntl(clp->dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MULTISHOT);
384 if (process_clnt_dir_files(clp))
385 goto fail_keep_client;
387 if (insert_clnt_poll(clp))
388 goto fail_destroy_client;
394 TAILQ_REMOVE(&clnt_list, clp, list);
398 /* We couldn't find some subdirectories, but we keep the client
399 * around in case we get a notification on the directory when the
400 * subdirectories are created. */
405 init_client_list(void)
407 TAILQ_INIT(&clnt_list);
408 /* Eventually plan to grow/shrink poll array: */
409 pollsize = FD_ALLOC_BLOCK;
410 pollarray = calloc(pollsize, sizeof(struct pollfd));
414 * This is run after a DNOTIFY signal, and should clear up any
415 * directories that are no longer around, and re-scan any existing
416 * directories, since the DNOTIFY could have been in there.
419 update_old_clients(struct dirent **namelist, int size)
421 struct clnt_info *clp;
425 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
427 for (i=0; i < size; i++) {
428 if (!strcmp(clp->dirname, namelist[i]->d_name)) {
434 printerr(2, "destroying client %s\n", clp->dirname);
435 saveprev = clp->list.tqe_prev;
436 TAILQ_REMOVE(&clnt_list, clp, list);
441 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
442 if (!process_clnt_dir_files(clp))
443 insert_clnt_poll(clp);
447 /* Search for a client by directory name, return 1 if found, 0 otherwise */
449 find_client(char *dirname)
451 struct clnt_info *clp;
453 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
454 if (!strcmp(clp->dirname, dirname))
459 /* Used to read (and re-read) list of clients, set up poll array. */
461 update_client_list(void)
463 struct dirent **namelist;
466 if (chdir(pipefs_nfsdir) < 0) {
467 printerr(0, "ERROR: can't chdir to %s: %s\n",
468 pipefs_nfsdir, strerror(errno));
472 j = scandir(pipefs_nfsdir, &namelist, NULL, alphasort);
474 printerr(0, "ERROR: can't scandir %s: %s\n",
475 pipefs_nfsdir, strerror(errno));
478 update_old_clients(namelist, j);
479 for (i=0; i < j; i++) {
480 if (i < FD_ALLOC_BLOCK
481 && !strncmp(namelist[i]->d_name, "clnt", 4)
482 && !find_client(namelist[i]->d_name))
483 process_clnt_dir(namelist[i]->d_name);
492 do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
493 gss_buffer_desc *context_token)
495 char *buf = NULL, *p = NULL, *end = NULL;
496 unsigned int timeout = context_timeout;
497 unsigned int buf_size = 0;
499 printerr(1, "doing downcall\n");
500 buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) +
501 sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length +
502 sizeof(context_token->length) + context_token->length;
503 p = buf = malloc(buf_size);
504 end = buf + buf_size;
506 if (WRITE_BYTES(&p, end, uid)) goto out_err;
507 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
508 if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err;
509 if (write_buffer(&p, end, &pd->pd_ctx_hndl)) goto out_err;
510 if (write_buffer(&p, end, context_token)) goto out_err;
512 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
517 printerr(1, "Failed to write downcall!\n");
522 do_error_downcall(int k5_fd, uid_t uid, int err)
525 char *p = buf, *end = buf + 1024;
526 unsigned int timeout = 0;
529 printerr(1, "doing error downcall\n");
531 if (WRITE_BYTES(&p, end, uid)) goto out_err;
532 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
533 /* use seq_win = 0 to indicate an error: */
534 if (WRITE_BYTES(&p, end, zero)) goto out_err;
535 if (WRITE_BYTES(&p, end, err)) goto out_err;
537 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
540 printerr(1, "Failed to write error downcall!\n");
545 * If the port isn't already set, do an rpcbind query to the remote server
546 * using the program and version and get the port.
548 * Newer kernels send the value of the port= mount option in the "info"
549 * file for the upcall or '0' for NFSv2/3. For NFSv4 it sends the value
550 * of the port= option or '2049'. The port field in a new sockaddr should
551 * reflect the value that was sent by the kernel.
554 populate_port(struct sockaddr *sa, const socklen_t salen,
555 const rpcprog_t program, const rpcvers_t version,
556 const unsigned short protocol)
558 struct sockaddr_in *s4 = (struct sockaddr_in *) sa;
562 * Newer kernels send the port in the upcall. If we already have
563 * the port, there's no need to look it up.
565 switch (sa->sa_family) {
567 if (s4->sin_port != 0) {
568 printerr(2, "DEBUG: port already set to %d\n",
569 ntohs(s4->sin_port));
574 printerr(0, "ERROR: unsupported address family %d\n",
580 * Newer kernels that send the port in the upcall set the value to
581 * 2049 for NFSv4 mounts when one isn't specified. The check below is
582 * only for kernels that don't send the port in the upcall. For those
583 * we either have to do an rpcbind query or set it to the standard
584 * port. Doing a query could be problematic (firewalls, etc), so take
585 * the latter approach.
587 if (program == 100003 && version == 4) {
592 port = nfs_getport(sa, salen, program, version, protocol);
594 printerr(0, "ERROR: unable to obtain port for prog %ld "
595 "vers %ld\n", program, version);
600 printerr(2, "DEBUG: setting port to %hu for prog %lu vers %lu\n", port,
603 switch (sa->sa_family) {
605 s4->sin_port = htons(port);
613 * Create an RPC connection and establish an authenticated
614 * gss context with a server.
616 int create_auth_rpc_client(struct clnt_info *clp,
617 CLIENT **clnt_return,
622 CLIENT *rpc_clnt = NULL;
623 struct rpc_gss_sec sec;
628 char rpc_errmsg[1024];
629 int sockp = RPC_ANYSOCK;
630 int sendsz = 32768, recvsz = 32768;
632 struct sockaddr *addr = (struct sockaddr *) &clp->addr;
635 /* Create the context as the user (not as root) */
636 save_uid = geteuid();
637 if (setfsuid(uid) != 0) {
638 printerr(0, "WARNING: Failed to setfsuid for "
639 "user with uid %d\n", uid);
642 printerr(2, "creating context using fsuid %d (save_uid %d)\n",
645 sec.qop = GSS_C_QOP_DEFAULT;
646 sec.svc = RPCSEC_GSS_SVC_NONE;
647 sec.cred = GSS_C_NO_CREDENTIAL;
649 if (authtype == AUTHTYPE_KRB5) {
650 sec.mech = (gss_OID)&krb5oid;
651 sec.req_flags = GSS_C_MUTUAL_FLAG;
653 else if (authtype == AUTHTYPE_SPKM3) {
654 sec.mech = (gss_OID)&spkm3oid;
655 /* XXX sec.req_flags = GSS_C_ANON_FLAG;
656 * Need a way to switch....
658 sec.req_flags = GSS_C_MUTUAL_FLAG;
661 printerr(0, "ERROR: Invalid authentication type (%d) "
662 "in create_auth_rpc_client\n", authtype);
667 if (authtype == AUTHTYPE_KRB5) {
668 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
670 * Do this before creating rpc connection since we won't need
671 * rpc connection if it fails!
673 if (limit_krb5_enctypes(&sec, uid)) {
674 printerr(1, "WARNING: Failed while limiting krb5 "
675 "encryption types for user with uid %d\n",
682 /* create an rpc connection to the nfs server */
684 printerr(2, "creating %s client for server %s\n", clp->protocol,
687 if ((strcmp(clp->protocol, "tcp")) == 0) {
688 protocol = IPPROTO_TCP;
689 } else if ((strcmp(clp->protocol, "udp")) == 0) {
690 protocol = IPPROTO_UDP;
692 printerr(0, "WARNING: unrecognized protocol, '%s', requested "
693 "for connection to server %s for user with uid %d\n",
694 clp->protocol, clp->servername, uid);
698 switch (addr->sa_family) {
700 salen = sizeof(struct sockaddr_in);
703 printerr(1, "ERROR: Unknown address family %d\n",
708 if (!populate_port(addr, salen, clp->prog, clp->vers, protocol))
711 if (protocol == IPPROTO_TCP) {
712 if ((rpc_clnt = clnttcp_create(
713 (struct sockaddr_in *) addr,
714 clp->prog, clp->vers, &sockp,
715 sendsz, recvsz)) == NULL) {
716 snprintf(rpc_errmsg, sizeof(rpc_errmsg),
717 "WARNING: can't create tcp rpc_clnt "
718 "for server %s for user with uid %d",
719 clp->servername, uid);
721 clnt_spcreateerror(rpc_errmsg));
724 } else if (protocol == IPPROTO_UDP) {
725 const struct timeval timeout = {5, 0};
726 if ((rpc_clnt = clntudp_bufcreate(
727 (struct sockaddr_in *) addr,
728 clp->prog, clp->vers, timeout,
729 &sockp, sendsz, recvsz)) == NULL) {
730 snprintf(rpc_errmsg, sizeof(rpc_errmsg),
731 "WARNING: can't create udp rpc_clnt "
732 "for server %s for user with uid %d",
733 clp->servername, uid);
735 clnt_spcreateerror(rpc_errmsg));
740 printerr(2, "creating context with server %s\n", clp->servicename);
741 auth = authgss_create_default(rpc_clnt, clp->servicename, &sec);
743 /* Our caller should print appropriate message */
744 printerr(2, "WARNING: Failed to create %s context for "
745 "user with uid %d for server %s\n",
746 (authtype == AUTHTYPE_KRB5 ? "krb5":"spkm3"),
747 uid, clp->servername);
752 rpc_clnt->cl_auth = auth;
753 *clnt_return = rpc_clnt;
758 if (sec.cred != GSS_C_NO_CREDENTIAL)
759 gss_release_cred(&min_stat, &sec.cred);
760 /* Restore euid to original value */
761 if ((save_uid != -1) && (setfsuid(save_uid) != uid)) {
762 printerr(0, "WARNING: Failed to restore fsuid"
763 " to uid %d from %d\n", save_uid, uid);
768 /* Only destroy here if failure. Otherwise, caller is responsible */
769 if (rpc_clnt) clnt_destroy(rpc_clnt);
776 * this code uses the userland rpcsec gss library to create a krb5
777 * context on behalf of the kernel
780 handle_krb5_upcall(struct clnt_info *clp)
783 CLIENT *rpc_clnt = NULL;
785 struct authgss_private_data pd;
786 gss_buffer_desc token;
787 char **credlist = NULL;
790 int create_resp = -1;
792 printerr(1, "handling krb5 upcall\n");
796 memset(&pd, 0, sizeof(struct authgss_private_data));
798 if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
799 printerr(0, "WARNING: failed reading uid from krb5 "
800 "upcall pipe: %s\n", strerror(errno));
804 if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0)) {
805 /* Tell krb5 gss which credentials cache to use */
806 for (dirname = ccachesearch; *dirname != NULL; dirname++) {
807 if (gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname) == 0)
808 create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
810 if (create_resp == 0)
814 if (create_resp != 0) {
815 if (uid == 0 && root_uses_machine_creds == 1) {
818 gssd_refresh_krb5_machine_credential(clp->servername,
821 * Get a list of credential cache names and try each
822 * of them until one works or we've tried them all
824 if (gssd_get_krb5_machine_cred_list(&credlist)) {
825 printerr(0, "ERROR: No credentials found "
826 "for connection to server %s\n",
828 goto out_return_error;
830 for (ccname = credlist; ccname && *ccname; ccname++) {
831 gssd_setup_krb5_machine_gss_ccache(*ccname);
832 if ((create_auth_rpc_client(clp, &rpc_clnt,
834 AUTHTYPE_KRB5)) == 0) {
839 printerr(2, "WARNING: Failed to create krb5 context "
840 "for user with uid %d with credentials "
841 "cache %s for server %s\n",
842 uid, *ccname, clp->servername);
844 gssd_free_krb5_machine_cred_list(credlist);
846 printerr(1, "WARNING: Failed to create krb5 context "
847 "for user with uid %d with any "
848 "credentials cache for server %s\n",
849 uid, clp->servername);
850 goto out_return_error;
853 printerr(1, "WARNING: Failed to create krb5 context "
854 "for user with uid %d for server %s\n",
855 uid, clp->servername);
856 goto out_return_error;
860 if (!authgss_get_private_data(auth, &pd)) {
861 printerr(1, "WARNING: Failed to obtain authentication "
862 "data for user with uid %d for server %s\n",
863 uid, clp->servername);
864 goto out_return_error;
867 if (serialize_context_for_kernel(pd.pd_ctx, &token, &krb5oid, NULL)) {
868 printerr(0, "WARNING: Failed to serialize krb5 context for "
869 "user with uid %d for server %s\n",
870 uid, clp->servername);
871 goto out_return_error;
874 do_downcall(clp->krb5_fd, uid, &pd, &token);
879 #ifndef HAVE_LIBTIRPC
880 if (pd.pd_ctx_hndl.length != 0)
881 authgss_free_private_data(&pd);
886 clnt_destroy(rpc_clnt);
890 do_error_downcall(clp->krb5_fd, uid, -1);
895 * this code uses the userland rpcsec gss library to create an spkm3
896 * context on behalf of the kernel
899 handle_spkm3_upcall(struct clnt_info *clp)
902 CLIENT *rpc_clnt = NULL;
904 struct authgss_private_data pd;
905 gss_buffer_desc token;
907 printerr(2, "handling spkm3 upcall\n");
912 if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) {
913 printerr(0, "WARNING: failed reading uid from spkm3 "
914 "upcall pipe: %s\n", strerror(errno));
918 if (create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, AUTHTYPE_SPKM3)) {
919 printerr(0, "WARNING: Failed to create spkm3 context for "
920 "user with uid %d\n", uid);
921 goto out_return_error;
924 if (!authgss_get_private_data(auth, &pd)) {
925 printerr(0, "WARNING: Failed to obtain authentication "
926 "data for user with uid %d for server %s\n",
927 uid, clp->servername);
928 goto out_return_error;
931 if (serialize_context_for_kernel(pd.pd_ctx, &token, &spkm3oid, NULL)) {
932 printerr(0, "WARNING: Failed to serialize spkm3 context for "
933 "user with uid %d for server\n",
934 uid, clp->servername);
935 goto out_return_error;
938 do_downcall(clp->spkm3_fd, uid, &pd, &token);
946 clnt_destroy(rpc_clnt);
950 do_error_downcall(clp->spkm3_fd, uid, -1);