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"
78 * array of struct pollfd suitable to pass to poll. initialized to
79 * zero - a zero struct is ignored by poll() because the events mask is 0.
82 * linked list of struct clnt_info which associates a clntXXX directory
83 * with an index into pollarray[], and other basic data about that client.
85 * Directory structure: created by the kernel nfs client
86 * {pipefs_nfsdir}/clntXX : one per rpc_clnt struct in the kernel
87 * {pipefs_nfsdir}/clntXX/krb5 : read uid for which kernel wants
88 * a context, write the resulting context
89 * {pipefs_nfsdir}/clntXX/info : stores info such as server name
92 * Poll all {pipefs_nfsdir}/clntXX/krb5 files. When ready, data read
93 * is a uid; performs rpcsec_gss context initialization protocol to
94 * get a cred for that user. Writes result to corresponding krb5 file
95 * in a form the kernel code will understand.
96 * In addition, we make sure we are notified whenever anything is
97 * created or destroyed in {pipefs_nfsdir} or in an of the clntXX directories,
98 * and rescan the whole {pipefs_nfsdir} when this happens.
101 struct pollfd * pollarray;
103 int pollsize; /* the size of pollaray (in pollfd's) */
106 * convert a presentation address string to a sockaddr_storage struct. Returns
107 * true on success and false on failure.
110 addrstr_to_sockaddr(struct sockaddr *sa, const char *addr, const int port)
112 struct sockaddr_in *s4 = (struct sockaddr_in *) sa;
114 if (inet_pton(AF_INET, addr, &s4->sin_addr)) {
115 s4->sin_family = AF_INET;
116 s4->sin_port = htons(port);
118 printerr(0, "ERROR: unable to convert %s to address\n", addr);
126 * convert a sockaddr to a hostname
129 sockaddr_to_hostname(const struct sockaddr *sa, const char *addr)
134 char hbuf[NI_MAXHOST];
136 switch (sa->sa_family) {
138 addrlen = sizeof(struct sockaddr_in);
141 printerr(0, "ERROR: unrecognized addr family %d\n",
146 err = getnameinfo(sa, addrlen, hbuf, sizeof(hbuf), NULL, 0,
149 printerr(0, "ERROR: unable to resolve %s to hostname: %s\n",
150 addr, err == EAI_SYSTEM ? strerror(err) :
155 hostname = strdup(hbuf);
160 /* XXX buffer problems: */
162 read_service_info(char *info_file_name, char **servicename, char **servername,
163 int *prog, int *vers, char **protocol,
164 struct sockaddr *addr) {
165 #define INFOBUFLEN 256
166 char buf[INFOBUFLEN + 1];
167 static char dummy[128];
169 static char service[128];
170 static char address[128];
180 *servicename = *servername = *protocol = NULL;
182 if ((fd = open(info_file_name, O_RDONLY)) == -1) {
183 printerr(0, "ERROR: can't open %s: %s\n", info_file_name,
187 if ((nbytes = read(fd, buf, INFOBUFLEN)) == -1)
192 numfields = sscanf(buf,"RPC server: %127s\n"
193 "service: %127s %15s version %15s\n"
197 service, program, version,
201 if (numfields == 5) {
202 strcpy(protoname, "tcp");
203 } else if (numfields != 6) {
208 if ((p = strstr(buf, "port")) != NULL)
209 sscanf(p, "port: %127s\n", cb_port);
211 /* check service, program, and version */
212 if(memcmp(service, "nfs", 3)) return -1;
213 *prog = atoi(program + 1); /* skip open paren */
214 *vers = atoi(version);
215 if((*prog != 100003) || ((*vers != 2) && (*vers != 3) && (*vers != 4)))
218 if (cb_port[0] != '\0') {
219 port = atoi(cb_port);
220 if (port < 0 || port > 65535)
224 if (!addrstr_to_sockaddr(addr, address, port))
227 *servername = sockaddr_to_hostname(addr, address);
228 if (*servername == NULL)
231 nbytes = snprintf(buf, INFOBUFLEN, "%s@%s", service, *servername);
232 if (nbytes > INFOBUFLEN)
235 if (!(*servicename = calloc(strlen(buf) + 1, 1)))
237 memcpy(*servicename, buf, strlen(buf));
239 if (!(*protocol = strdup(protoname)))
243 printerr(0, "ERROR: failed to read service info\n");
244 if (fd != -1) close(fd);
248 *servicename = *servername = *protocol = NULL;
253 destroy_client(struct clnt_info *clp)
255 if (clp->krb5_poll_index != -1)
256 memset(&pollarray[clp->krb5_poll_index], 0,
257 sizeof(struct pollfd));
258 if (clp->spkm3_poll_index != -1)
259 memset(&pollarray[clp->spkm3_poll_index], 0,
260 sizeof(struct pollfd));
261 if (clp->dir_fd != -1) close(clp->dir_fd);
262 if (clp->krb5_fd != -1) close(clp->krb5_fd);
263 if (clp->spkm3_fd != -1) close(clp->spkm3_fd);
265 free(clp->servicename);
266 free(clp->servername);
271 static struct clnt_info *
272 insert_new_clnt(void)
274 struct clnt_info *clp = NULL;
276 if (!(clp = (struct clnt_info *)calloc(1,sizeof(struct clnt_info)))) {
277 printerr(0, "ERROR: can't malloc clnt_info: %s\n",
281 clp->krb5_poll_index = -1;
282 clp->spkm3_poll_index = -1;
287 TAILQ_INSERT_HEAD(&clnt_list, clp, list);
293 process_clnt_dir_files(struct clnt_info * clp)
297 char info_file_name[32];
299 if (clp->krb5_fd == -1) {
300 snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname);
301 clp->krb5_fd = open(kname, O_RDWR);
303 if (clp->spkm3_fd == -1) {
304 snprintf(sname, sizeof(sname), "%s/spkm3", clp->dirname);
305 clp->spkm3_fd = open(sname, O_RDWR);
307 if((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
309 snprintf(info_file_name, sizeof(info_file_name), "%s/info",
311 if ((clp->servicename == NULL) &&
312 read_service_info(info_file_name, &clp->servicename,
313 &clp->servername, &clp->prog, &clp->vers,
314 &clp->protocol, (struct sockaddr *) &clp->addr))
320 get_poll_index(int *ind)
325 for (i=0; i<FD_ALLOC_BLOCK; i++) {
326 if (pollarray[i].events == 0) {
332 printerr(0, "ERROR: No pollarray slots open\n");
340 insert_clnt_poll(struct clnt_info *clp)
342 if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
343 if (get_poll_index(&clp->krb5_poll_index)) {
344 printerr(0, "ERROR: Too many krb5 clients\n");
347 pollarray[clp->krb5_poll_index].fd = clp->krb5_fd;
348 pollarray[clp->krb5_poll_index].events |= POLLIN;
351 if ((clp->spkm3_fd != -1) && (clp->spkm3_poll_index == -1)) {
352 if (get_poll_index(&clp->spkm3_poll_index)) {
353 printerr(0, "ERROR: Too many spkm3 clients\n");
356 pollarray[clp->spkm3_poll_index].fd = clp->spkm3_fd;
357 pollarray[clp->spkm3_poll_index].events |= POLLIN;
364 process_clnt_dir(char *dir)
366 struct clnt_info * clp;
368 if (!(clp = insert_new_clnt()))
369 goto fail_destroy_client;
371 if (!(clp->dirname = calloc(strlen(dir) + 1, 1))) {
372 goto fail_destroy_client;
374 memcpy(clp->dirname, dir, strlen(dir));
375 if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
376 printerr(0, "ERROR: can't open %s: %s\n",
377 clp->dirname, strerror(errno));
378 goto fail_destroy_client;
380 fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL);
381 fcntl(clp->dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MULTISHOT);
383 if (process_clnt_dir_files(clp))
384 goto fail_keep_client;
386 if (insert_clnt_poll(clp))
387 goto fail_destroy_client;
393 TAILQ_REMOVE(&clnt_list, clp, list);
397 /* We couldn't find some subdirectories, but we keep the client
398 * around in case we get a notification on the directory when the
399 * subdirectories are created. */
404 init_client_list(void)
406 TAILQ_INIT(&clnt_list);
407 /* Eventually plan to grow/shrink poll array: */
408 pollsize = FD_ALLOC_BLOCK;
409 pollarray = calloc(pollsize, sizeof(struct pollfd));
413 * This is run after a DNOTIFY signal, and should clear up any
414 * directories that are no longer around, and re-scan any existing
415 * directories, since the DNOTIFY could have been in there.
418 update_old_clients(struct dirent **namelist, int size)
420 struct clnt_info *clp;
424 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
426 for (i=0; i < size; i++) {
427 if (!strcmp(clp->dirname, namelist[i]->d_name)) {
433 printerr(2, "destroying client %s\n", clp->dirname);
434 saveprev = clp->list.tqe_prev;
435 TAILQ_REMOVE(&clnt_list, clp, list);
440 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
441 if (!process_clnt_dir_files(clp))
442 insert_clnt_poll(clp);
446 /* Search for a client by directory name, return 1 if found, 0 otherwise */
448 find_client(char *dirname)
450 struct clnt_info *clp;
452 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
453 if (!strcmp(clp->dirname, dirname))
458 /* Used to read (and re-read) list of clients, set up poll array. */
460 update_client_list(void)
462 struct dirent **namelist;
465 if (chdir(pipefs_nfsdir) < 0) {
466 printerr(0, "ERROR: can't chdir to %s: %s\n",
467 pipefs_nfsdir, strerror(errno));
471 j = scandir(pipefs_nfsdir, &namelist, NULL, alphasort);
473 printerr(0, "ERROR: can't scandir %s: %s\n",
474 pipefs_nfsdir, strerror(errno));
477 update_old_clients(namelist, j);
478 for (i=0; i < j; i++) {
479 if (i < FD_ALLOC_BLOCK
480 && !strncmp(namelist[i]->d_name, "clnt", 4)
481 && !find_client(namelist[i]->d_name))
482 process_clnt_dir(namelist[i]->d_name);
491 do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
492 gss_buffer_desc *context_token)
494 char *buf = NULL, *p = NULL, *end = NULL;
495 unsigned int timeout = context_timeout;
496 unsigned int buf_size = 0;
498 printerr(1, "doing downcall\n");
499 buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) +
500 sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length +
501 sizeof(context_token->length) + context_token->length;
502 p = buf = malloc(buf_size);
503 end = buf + buf_size;
505 if (WRITE_BYTES(&p, end, uid)) goto out_err;
506 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
507 if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err;
508 if (write_buffer(&p, end, &pd->pd_ctx_hndl)) goto out_err;
509 if (write_buffer(&p, end, context_token)) goto out_err;
511 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
516 printerr(1, "Failed to write downcall!\n");
521 do_error_downcall(int k5_fd, uid_t uid, int err)
524 char *p = buf, *end = buf + 1024;
525 unsigned int timeout = 0;
528 printerr(1, "doing error downcall\n");
530 if (WRITE_BYTES(&p, end, uid)) goto out_err;
531 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
532 /* use seq_win = 0 to indicate an error: */
533 if (WRITE_BYTES(&p, end, zero)) goto out_err;
534 if (WRITE_BYTES(&p, end, err)) goto out_err;
536 if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
539 printerr(1, "Failed to write error downcall!\n");
544 * Create an RPC connection and establish an authenticated
545 * gss context with a server.
547 int create_auth_rpc_client(struct clnt_info *clp,
548 CLIENT **clnt_return,
553 CLIENT *rpc_clnt = NULL;
554 struct rpc_gss_sec sec;
560 char rpc_errmsg[1024];
561 int sockp = RPC_ANYSOCK;
562 int sendsz = 32768, recvsz = 32768;
563 struct addrinfo ai_hints, *a = NULL;
566 struct sockaddr_in *addr = (struct sockaddr_in *) &clp->addr;
568 /* Create the context as the user (not as root) */
569 save_uid = geteuid();
570 if (setfsuid(uid) != 0) {
571 printerr(0, "WARNING: Failed to setfsuid for "
572 "user with uid %d\n", uid);
575 printerr(2, "creating context using fsuid %d (save_uid %d)\n",
578 sec.qop = GSS_C_QOP_DEFAULT;
579 sec.svc = RPCSEC_GSS_SVC_NONE;
580 sec.cred = GSS_C_NO_CREDENTIAL;
582 if (authtype == AUTHTYPE_KRB5) {
583 sec.mech = (gss_OID)&krb5oid;
584 sec.req_flags = GSS_C_MUTUAL_FLAG;
586 else if (authtype == AUTHTYPE_SPKM3) {
587 sec.mech = (gss_OID)&spkm3oid;
588 /* XXX sec.req_flags = GSS_C_ANON_FLAG;
589 * Need a way to switch....
591 sec.req_flags = GSS_C_MUTUAL_FLAG;
594 printerr(0, "ERROR: Invalid authentication type (%d) "
595 "in create_auth_rpc_client\n", authtype);
600 if (authtype == AUTHTYPE_KRB5) {
601 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
603 * Do this before creating rpc connection since we won't need
604 * rpc connection if it fails!
606 if (limit_krb5_enctypes(&sec, uid)) {
607 printerr(1, "WARNING: Failed while limiting krb5 "
608 "encryption types for user with uid %d\n",
615 /* create an rpc connection to the nfs server */
617 printerr(2, "creating %s client for server %s\n", clp->protocol,
620 memset(&ai_hints, '\0', sizeof(ai_hints));
621 ai_hints.ai_family = PF_INET;
622 ai_hints.ai_flags |= AI_CANONNAME;
623 if ((strcmp(clp->protocol, "tcp")) == 0) {
624 ai_hints.ai_socktype = SOCK_STREAM;
625 ai_hints.ai_protocol = IPPROTO_TCP;
626 } else if ((strcmp(clp->protocol, "udp")) == 0) {
627 ai_hints.ai_socktype = SOCK_DGRAM;
628 ai_hints.ai_protocol = IPPROTO_UDP;
630 printerr(0, "WARNING: unrecognized protocol, '%s', requested "
631 "for connection to server %s for user with uid %d\n",
632 clp->protocol, clp->servername, uid);
636 /* extract the service name from clp->servicename */
637 if ((at_sign = strchr(clp->servicename, '@')) == NULL) {
638 printerr(0, "WARNING: servicename (%s) not formatted as "
639 "expected with service@host\n", clp->servicename);
642 if ((at_sign - clp->servicename) >= sizeof(service)) {
643 printerr(0, "WARNING: service portion of servicename (%s) "
644 "is too long!\n", clp->servicename);
647 strncpy(service, clp->servicename, at_sign - clp->servicename);
648 service[at_sign - clp->servicename] = '\0';
650 errcode = getaddrinfo(clp->servername, service, &ai_hints, &a);
652 printerr(0, "WARNING: Error from getaddrinfo for server "
653 "'%s': %s\n", clp->servername, gai_strerror(errcode));
658 printerr(0, "WARNING: No address information found for "
659 "connection to server %s for user with uid %d\n",
660 clp->servername, uid);
664 if (addr->sin_port != 0)
665 ((struct sockaddr_in *) a->ai_addr)->sin_port = addr->sin_port;
667 if (a->ai_protocol == IPPROTO_TCP) {
668 if ((rpc_clnt = clnttcp_create(
669 (struct sockaddr_in *) a->ai_addr,
670 clp->prog, clp->vers, &sockp,
671 sendsz, recvsz)) == NULL) {
672 snprintf(rpc_errmsg, sizeof(rpc_errmsg),
673 "WARNING: can't create tcp rpc_clnt "
674 "for server %s for user with uid %d",
675 clp->servername, uid);
677 clnt_spcreateerror(rpc_errmsg));
680 } else if (a->ai_protocol == IPPROTO_UDP) {
681 const struct timeval timeout = {5, 0};
682 if ((rpc_clnt = clntudp_bufcreate(
683 (struct sockaddr_in *) a->ai_addr,
684 clp->prog, clp->vers, timeout,
685 &sockp, sendsz, recvsz)) == NULL) {
686 snprintf(rpc_errmsg, sizeof(rpc_errmsg),
687 "WARNING: can't create udp rpc_clnt "
688 "for server %s for user with uid %d",
689 clp->servername, uid);
691 clnt_spcreateerror(rpc_errmsg));
695 /* Shouldn't happen! */
696 printerr(0, "ERROR: requested protocol '%s', but "
697 "got addrinfo with protocol %d\n",
698 clp->protocol, a->ai_protocol);
701 /* We're done with this */
705 printerr(2, "creating context with server %s\n", clp->servicename);
706 auth = authgss_create_default(rpc_clnt, clp->servicename, &sec);
708 /* Our caller should print appropriate message */
709 printerr(2, "WARNING: Failed to create %s context for "
710 "user with uid %d for server %s\n",
711 (authtype == AUTHTYPE_KRB5 ? "krb5":"spkm3"),
712 uid, clp->servername);
717 rpc_clnt->cl_auth = auth;
718 *clnt_return = rpc_clnt;
723 if (sec.cred != GSS_C_NO_CREDENTIAL)
724 gss_release_cred(&min_stat, &sec.cred);
725 if (a != NULL) freeaddrinfo(a);
726 /* Restore euid to original value */
727 if ((save_uid != -1) && (setfsuid(save_uid) != uid)) {
728 printerr(0, "WARNING: Failed to restore fsuid"
729 " to uid %d from %d\n", save_uid, uid);
734 /* Only destroy here if failure. Otherwise, caller is responsible */
735 if (rpc_clnt) clnt_destroy(rpc_clnt);
742 * this code uses the userland rpcsec gss library to create a krb5
743 * context on behalf of the kernel
746 handle_krb5_upcall(struct clnt_info *clp)
749 CLIENT *rpc_clnt = NULL;
751 struct authgss_private_data pd;
752 gss_buffer_desc token;
753 char **credlist = NULL;
756 int create_resp = -1;
758 printerr(1, "handling krb5 upcall\n");
762 memset(&pd, 0, sizeof(struct authgss_private_data));
764 if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
765 printerr(0, "WARNING: failed reading uid from krb5 "
766 "upcall pipe: %s\n", strerror(errno));
770 if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0)) {
771 /* Tell krb5 gss which credentials cache to use */
772 for (dirname = ccachesearch; *dirname != NULL; dirname++) {
773 if (gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname) == 0)
774 create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
776 if (create_resp == 0)
780 if (create_resp != 0) {
781 if (uid == 0 && root_uses_machine_creds == 1) {
784 gssd_refresh_krb5_machine_credential(clp->servername,
787 * Get a list of credential cache names and try each
788 * of them until one works or we've tried them all
790 if (gssd_get_krb5_machine_cred_list(&credlist)) {
791 printerr(0, "ERROR: No credentials found "
792 "for connection to server %s\n",
794 goto out_return_error;
796 for (ccname = credlist; ccname && *ccname; ccname++) {
797 gssd_setup_krb5_machine_gss_ccache(*ccname);
798 if ((create_auth_rpc_client(clp, &rpc_clnt,
800 AUTHTYPE_KRB5)) == 0) {
805 printerr(2, "WARNING: Failed to create krb5 context "
806 "for user with uid %d with credentials "
807 "cache %s for server %s\n",
808 uid, *ccname, clp->servername);
810 gssd_free_krb5_machine_cred_list(credlist);
812 printerr(1, "WARNING: Failed to create krb5 context "
813 "for user with uid %d with any "
814 "credentials cache for server %s\n",
815 uid, clp->servername);
816 goto out_return_error;
819 printerr(1, "WARNING: Failed to create krb5 context "
820 "for user with uid %d for server %s\n",
821 uid, clp->servername);
822 goto out_return_error;
826 if (!authgss_get_private_data(auth, &pd)) {
827 printerr(1, "WARNING: Failed to obtain authentication "
828 "data for user with uid %d for server %s\n",
829 uid, clp->servername);
830 goto out_return_error;
833 if (serialize_context_for_kernel(pd.pd_ctx, &token, &krb5oid, NULL)) {
834 printerr(0, "WARNING: Failed to serialize krb5 context for "
835 "user with uid %d for server %s\n",
836 uid, clp->servername);
837 goto out_return_error;
840 do_downcall(clp->krb5_fd, uid, &pd, &token);
845 #ifndef HAVE_LIBTIRPC
846 if (pd.pd_ctx_hndl.length != 0)
847 authgss_free_private_data(&pd);
852 clnt_destroy(rpc_clnt);
856 do_error_downcall(clp->krb5_fd, uid, -1);
861 * this code uses the userland rpcsec gss library to create an spkm3
862 * context on behalf of the kernel
865 handle_spkm3_upcall(struct clnt_info *clp)
868 CLIENT *rpc_clnt = NULL;
870 struct authgss_private_data pd;
871 gss_buffer_desc token;
873 printerr(2, "handling spkm3 upcall\n");
878 if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) {
879 printerr(0, "WARNING: failed reading uid from spkm3 "
880 "upcall pipe: %s\n", strerror(errno));
884 if (create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, AUTHTYPE_SPKM3)) {
885 printerr(0, "WARNING: Failed to create spkm3 context for "
886 "user with uid %d\n", uid);
887 goto out_return_error;
890 if (!authgss_get_private_data(auth, &pd)) {
891 printerr(0, "WARNING: Failed to obtain authentication "
892 "data for user with uid %d for server %s\n",
893 uid, clp->servername);
894 goto out_return_error;
897 if (serialize_context_for_kernel(pd.pd_ctx, &token, &spkm3oid, NULL)) {
898 printerr(0, "WARNING: Failed to serialize spkm3 context for "
899 "user with uid %d for server\n",
900 uid, clp->servername);
901 goto out_return_error;
904 do_downcall(clp->spkm3_fd, uid, &pd, &token);
912 clnt_destroy(rpc_clnt);
916 do_error_downcall(clp->spkm3_fd, uid, -1);