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.
45 #include <sys/param.h>
47 #include <sys/socket.h>
48 #include <arpa/inet.h>
49 #include <sys/fsuid.h>
62 #include <gssapi/gssapi.h>
67 #include <libcfs/util/param.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 TAILQ_HEAD(clnt_list_head, clnt_info) clnt_list;
104 struct pollfd * pollarray;
106 int pollsize; /* the size of pollaray (in pollfd's) */
109 destroy_client(struct clnt_info *clp)
111 printerr(3, "clp %p: dirname %s, krb5fd %d\n", clp, clp->dirname, clp->krb5_fd);
112 if (clp->krb5_poll_index != -1)
113 memset(&pollarray[clp->krb5_poll_index], 0,
114 sizeof(struct pollfd));
115 if (clp->spkm3_poll_index != -1)
116 memset(&pollarray[clp->spkm3_poll_index], 0,
117 sizeof(struct pollfd));
118 if (clp->dir_fd != -1) close(clp->dir_fd);
119 if (clp->krb5_fd != -1) close(clp->krb5_fd);
120 if (clp->spkm3_fd != -1) close(clp->spkm3_fd);
121 if (clp->dirname) free(clp->dirname);
122 if (clp->servicename) free(clp->servicename);
126 static struct clnt_info *
127 insert_new_clnt(void)
129 struct clnt_info *clp = NULL;
131 if (!(clp = (struct clnt_info *)calloc(1,sizeof(struct clnt_info)))) {
132 printerr(0, "ERROR: can't malloc clnt_info: %s\n",
136 clp->krb5_poll_index = -1;
137 clp->spkm3_poll_index = -1;
142 TAILQ_INSERT_HEAD(&clnt_list, clp, list);
148 process_clnt_dir_files(struct clnt_info * clp)
153 if (clp->krb5_fd == -1) {
154 snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname);
155 clp->krb5_fd = open(kname, O_RDWR);
157 if (clp->spkm3_fd == -1) {
158 snprintf(sname, sizeof(sname), "%s/spkm3", clp->dirname);
159 clp->spkm3_fd = open(sname, O_RDWR);
161 if((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
167 get_poll_index(int *ind)
172 for (i=0; i<FD_ALLOC_BLOCK; i++) {
173 if (pollarray[i].events == 0) {
179 printerr(0, "ERROR: No pollarray slots open\n");
187 insert_clnt_poll(struct clnt_info *clp)
189 if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
190 if (get_poll_index(&clp->krb5_poll_index)) {
191 printerr(0, "ERROR: Too many krb5 clients\n");
194 pollarray[clp->krb5_poll_index].fd = clp->krb5_fd;
195 pollarray[clp->krb5_poll_index].events |= POLLIN;
196 printerr(2, "monitoring krb5 channel under %s\n",
200 if ((clp->spkm3_fd != -1) && (clp->spkm3_poll_index == -1)) {
201 if (get_poll_index(&clp->spkm3_poll_index)) {
202 printerr(0, "ERROR: Too many spkm3 clients\n");
205 pollarray[clp->spkm3_poll_index].fd = clp->spkm3_fd;
206 pollarray[clp->spkm3_poll_index].events |= POLLIN;
213 process_clnt_dir(char *dir)
215 struct clnt_info * clp;
217 if (!(clp = insert_new_clnt()))
218 goto fail_destroy_client;
220 if (!(clp->dirname = calloc(strlen(dir) + 1, 1))) {
221 goto fail_destroy_client;
223 memcpy(clp->dirname, dir, strlen(dir));
224 if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
225 printerr(0, "ERROR: can't open %s: %s\n",
226 clp->dirname, strerror(errno));
227 goto fail_destroy_client;
229 fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL);
230 fcntl(clp->dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MULTISHOT);
232 if (process_clnt_dir_files(clp))
233 goto fail_keep_client;
235 if (insert_clnt_poll(clp))
236 goto fail_destroy_client;
242 TAILQ_REMOVE(&clnt_list, clp, list);
246 /* We couldn't find some subdirectories, but we keep the client
247 * around in case we get a notification on the directory when the
248 * subdirectories are created. */
252 init_client_list(void)
254 TAILQ_INIT(&clnt_list);
255 /* Eventually plan to grow/shrink poll array: */
256 pollsize = FD_ALLOC_BLOCK;
257 pollarray = calloc(pollsize, sizeof(struct pollfd));
260 struct clnt_info *clnt_list_first_entry(void)
262 return clnt_list.tqh_first;
266 * This is run after a DNOTIFY signal, and should clear up any
267 * directories that are no longer around, and re-scan any existing
268 * directories, since the DNOTIFY could have been in there.
271 update_old_clients(struct dirent **namelist, int size)
273 struct clnt_info *clp;
277 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
279 for (i=0; i < size; i++) {
280 if (!strcmp(clp->dirname, namelist[i]->d_name)) {
286 printerr(2, "destroying client %s\n", clp->dirname);
287 saveprev = clp->list.tqe_prev;
288 TAILQ_REMOVE(&clnt_list, clp, list);
293 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
294 if (!process_clnt_dir_files(clp))
295 insert_clnt_poll(clp);
299 /* Search for a client by directory name, return 1 if found, 0 otherwise */
301 find_client(char *dirname)
303 struct clnt_info *clp;
305 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
306 if (!strcmp(clp->dirname, dirname))
311 /* Used to read (and re-read) list of clients, set up poll array. */
313 update_client_list(void)
315 char lustre_dir[PATH_MAX];
316 struct dirent lustre_dirent = { .d_name = "lustre" };
317 struct dirent *namelist[1];
321 if (chdir(pipefs_dir) < 0) {
322 printerr(0, "ERROR: can't chdir to %s: %s\n",
323 pipefs_dir, strerror(errno));
327 snprintf(lustre_dir, sizeof(lustre_dir), "%s/%s", pipefs_dir, "lustre");
328 if (stat(lustre_dir, &statbuf) == 0) {
329 namelist[0] = &lustre_dirent;
331 printerr(2, "re-processing lustre directory\n");
335 printerr(2, "lustre directory not exist\n");
338 update_old_clients(namelist, j);
339 for (i=0; i < j; i++) {
340 if (i < FD_ALLOC_BLOCK && !find_client(namelist[i]->d_name))
341 process_clnt_dir(namelist[i]->d_name);
348 /* Context creation response. */
349 struct lustre_gss_init_res {
350 gss_buffer_desc gr_ctx; /* context handle */
351 unsigned int gr_major; /* major status */
352 unsigned int gr_minor; /* minor status */
353 unsigned int gr_win; /* sequence window */
354 gss_buffer_desc gr_token; /* token */
357 struct lustre_gss_data {
359 int lgd_lustre_svc; /* mds/oss */
360 int lgd_uid; /* uid */
361 char *lgd_uuid; /* client device uuid */
362 gss_name_t lgd_name; /* service name */
364 gss_OID lgd_mech; /* mech OID */
365 unsigned int lgd_req_flags; /* request flags */
366 gss_cred_id_t lgd_cred; /* credential */
367 gss_ctx_id_t lgd_ctx; /* session context */
368 gss_buffer_desc lgd_rmt_ctx; /* remote handle of context */
369 uint32_t lgd_seq_win; /* sequence window */
376 do_downcall(int k5_fd, struct lgssd_upcall_data *updata,
377 struct lustre_gss_data *lgd, gss_buffer_desc *context_token)
379 char *buf = NULL, *p = NULL, *end = NULL;
380 unsigned int timeout = 0; /* XXX decide on a reasonable value */
381 unsigned int buf_size = 0;
383 printerr(2, "doing downcall\n");
384 buf_size = sizeof(updata->seq) + sizeof(timeout) +
385 sizeof(lgd->lgd_seq_win) +
386 sizeof(lgd->lgd_rmt_ctx.length) + lgd->lgd_rmt_ctx.length +
387 sizeof(context_token->length) + context_token->length;
388 p = buf = malloc(buf_size);
389 end = buf + buf_size;
391 if (WRITE_BYTES(&p, end, updata->seq)) goto out_err;
392 /* Not setting any timeout for now: */
393 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
394 if (WRITE_BYTES(&p, end, lgd->lgd_seq_win)) goto out_err;
395 if (write_buffer(&p, end, &lgd->lgd_rmt_ctx)) goto out_err;
396 if (write_buffer(&p, end, context_token)) goto out_err;
398 lgssd_mutex_get(lgssd_mutex_downcall);
399 if (write(k5_fd, buf, p - buf) < p - buf) {
400 lgssd_mutex_put(lgssd_mutex_downcall);
403 lgssd_mutex_put(lgssd_mutex_downcall);
409 printerr(0, "ERROR: Failed to write downcall!\n");
414 do_error_downcall(int k5_fd, uint32_t seq, int rpc_err, int gss_err)
417 char *p = buf, *end = buf + 1024;
418 unsigned int timeout = 0;
421 printerr(1, "doing error downcall\n");
423 if (WRITE_BYTES(&p, end, seq)) goto out_err;
424 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
425 /* use seq_win = 0 to indicate an error: */
426 if (WRITE_BYTES(&p, end, zero)) goto out_err;
427 if (WRITE_BYTES(&p, end, rpc_err)) goto out_err;
428 if (WRITE_BYTES(&p, end, gss_err)) goto out_err;
430 lgssd_mutex_get(lgssd_mutex_downcall);
431 if (write(k5_fd, buf, p - buf) < p - buf) {
432 lgssd_mutex_put(lgssd_mutex_downcall);
435 lgssd_mutex_put(lgssd_mutex_downcall);
438 printerr(0, "Failed to write error downcall!\n");
443 int do_negotiation(struct lustre_gss_data *lgd,
444 gss_buffer_desc *gss_token,
445 struct lustre_gss_init_res *gr,
448 struct lgssd_ioctl_param param;
456 pw = getpwuid(lgd->lgd_uid);
458 printerr(0, "no uid %u in local user database\n",
463 param.version = GSSD_INTERFACE_VERSION_V1;
464 param.uuid = lgd->lgd_uuid;
465 param.lustre_svc = lgd->lgd_lustre_svc;
466 param.uid = lgd->lgd_uid;
467 param.gid = pw->pw_gid;
468 param.send_token_size = gss_token->length;
469 param.send_token = (char *) gss_token->value;
470 param.reply_buf_size = sizeof(outbuf);
471 param.reply_buf = outbuf;
473 if (cfs_get_param_paths(&path, "sptlrpc/gss/init_channel") != 0)
476 fd = open(path.gl_pathv[0], O_RDWR);
478 printerr(0, "can't open file %s\n", path.gl_pathv[0]);
483 rc = write(fd, ¶m, sizeof(param));
484 if (rc != sizeof(param)) {
485 printerr(0, "lustre ioctl err: %d\n", strerror(errno));
490 printerr(0, "status: %d (%s)\n",
491 param.status, strerror((int)param.status));
492 if (param.status == -ETIMEDOUT) {
493 /* kernel return -ETIMEDOUT means the rpc timedout,
494 * we should notify the caller to reinitiate the
495 * gss negotiation, by return -ERESTART
497 lgd->lgd_rpc_err = -ERESTART;
498 lgd->lgd_gss_err = 0;
500 lgd->lgd_rpc_err = param.status;
501 lgd->lgd_gss_err = 0;
506 p = (unsigned int *)outbuf;
511 gr->gr_ctx.length = *p++;
512 gr->gr_ctx.value = malloc(gr->gr_ctx.length);
513 memcpy(gr->gr_ctx.value, p, gr->gr_ctx.length);
514 p += (((gr->gr_ctx.length + 3) & ~3) / 4);
516 gr->gr_token.length = *p++;
517 gr->gr_token.value = malloc(gr->gr_token.length);
518 memcpy(gr->gr_token.value, p, gr->gr_token.length);
519 p += (((gr->gr_token.length + 3) & ~3) / 4);
521 printerr(2, "do_negotiation: receive handle len %d, token len %d\n",
522 gr->gr_ctx.length, gr->gr_token.length);
527 cfs_free_param_data(&path);
532 int gssd_refresh_lgd(struct lustre_gss_data *lgd)
534 struct lustre_gss_init_res gr;
535 gss_buffer_desc *recv_tokenp, send_token;
536 OM_uint32 maj_stat, min_stat, call_stat, ret_flags;
538 /* GSS context establishment loop. */
539 memset(&gr, 0, sizeof(gr));
540 recv_tokenp = GSS_C_NO_BUFFER;
543 /* print the token we just received */
544 if (recv_tokenp != GSS_C_NO_BUFFER) {
545 printerr(3, "The received token length %d\n",
546 recv_tokenp->length);
547 print_hexl(3, recv_tokenp->value, recv_tokenp->length);
550 maj_stat = gss_init_sec_context(&min_stat,
559 NULL, /* used mech */
562 NULL); /* time rec */
564 if (recv_tokenp != GSS_C_NO_BUFFER) {
565 gss_release_buffer(&min_stat, &gr.gr_token);
566 recv_tokenp = GSS_C_NO_BUFFER;
568 if (maj_stat != GSS_S_COMPLETE &&
569 maj_stat != GSS_S_CONTINUE_NEEDED) {
570 pgsserr("gss_init_sec_context", maj_stat, min_stat,
574 if (send_token.length != 0) {
575 memset(&gr, 0, sizeof(gr));
577 /* print the token we are about to send */
578 printerr(3, "token being sent length %d\n",
580 print_hexl(3, send_token.value, send_token.length);
582 call_stat = do_negotiation(lgd, &send_token, &gr, 0);
583 gss_release_buffer(&min_stat, &send_token);
585 if (call_stat != 0 ||
586 (gr.gr_major != GSS_S_COMPLETE &&
587 gr.gr_major != GSS_S_CONTINUE_NEEDED)) {
588 printerr(0, "call stat %d, major stat 0x%x\n",
589 (int)call_stat, gr.gr_major);
593 if (gr.gr_ctx.length != 0) {
594 if (lgd->lgd_rmt_ctx.value)
595 gss_release_buffer(&min_stat,
597 lgd->lgd_rmt_ctx = gr.gr_ctx;
599 if (gr.gr_token.length != 0) {
600 if (maj_stat != GSS_S_CONTINUE_NEEDED)
602 recv_tokenp = &gr.gr_token;
606 /* GSS_S_COMPLETE => check gss header verifier,
607 * usually checked in gss_validate
609 if (maj_stat == GSS_S_COMPLETE) {
610 lgd->lgd_established = 1;
611 lgd->lgd_seq_win = gr.gr_win;
615 /* End context negotiation loop. */
616 if (!lgd->lgd_established) {
617 if (gr.gr_token.length != 0)
618 gss_release_buffer(&min_stat, &gr.gr_token);
620 printerr(0, "context negotiation failed\n");
624 printerr(2, "successfully refreshed lgd\n");
629 int gssd_create_lgd(struct clnt_info *clp,
630 struct lustre_gss_data *lgd,
631 struct lgssd_upcall_data *updata,
634 gss_buffer_desc sname;
635 OM_uint32 maj_stat, min_stat;
638 lgd->lgd_established = 0;
639 lgd->lgd_lustre_svc = updata->svc;
640 lgd->lgd_uid = updata->uid;
641 lgd->lgd_uuid = updata->obd;
645 lgd->lgd_mech = (gss_OID) &krb5oid;
646 lgd->lgd_req_flags = GSS_C_MUTUAL_FLAG;
649 lgd->lgd_mech = (gss_OID) &spkm3oid;
650 /* XXX sec.req_flags = GSS_C_ANON_FLAG;
651 * Need a way to switch....
653 lgd->lgd_req_flags = GSS_C_MUTUAL_FLAG;
656 printerr(0, "Invalid authentication type (%d)\n", authtype);
660 lgd->lgd_cred = GSS_C_NO_CREDENTIAL;
661 lgd->lgd_ctx = GSS_C_NO_CONTEXT;
662 lgd->lgd_rmt_ctx = (gss_buffer_desc) GSS_C_EMPTY_BUFFER;
663 lgd->lgd_seq_win = 0;
665 sname.value = clp->servicename;
666 sname.length = strlen(clp->servicename);
668 maj_stat = gss_import_name(&min_stat, &sname,
669 (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
671 if (maj_stat != GSS_S_COMPLETE) {
672 pgsserr(0, maj_stat, min_stat, lgd->lgd_mech);
676 retval = gssd_refresh_lgd(lgd);
678 if (lgd->lgd_name != GSS_C_NO_NAME)
679 gss_release_name(&min_stat, &lgd->lgd_name);
681 if (lgd->lgd_cred != GSS_C_NO_CREDENTIAL)
682 gss_release_cred(&min_stat, &lgd->lgd_cred);
689 void gssd_free_lgd(struct lustre_gss_data *lgd)
691 gss_buffer_t token = GSS_C_NO_BUFFER;
692 OM_uint32 maj_stat, min_stat;
694 if (lgd->lgd_ctx == GSS_C_NO_CONTEXT)
697 maj_stat = gss_delete_sec_context(&min_stat, &lgd->lgd_ctx, token);
701 int construct_service_name(struct clnt_info *clp,
702 struct lgssd_upcall_data *ud)
704 const int buflen = 256;
707 if (clp->servicename) {
708 free(clp->servicename);
709 clp->servicename = NULL;
712 if (lnet_nid2hostname(ud->nid, name, buflen))
715 clp->servicename = malloc(32 + strlen(name));
716 if (!clp->servicename) {
717 printerr(0, "can't alloc memory\n");
720 sprintf(clp->servicename, "%s@%s",
721 ud->svc == LUSTRE_GSS_SVC_MDS ?
722 GSSD_SERVICE_MDS : GSSD_SERVICE_OSS,
724 printerr(2, "constructed servicename: %s\n", clp->servicename);
729 * this code uses the userland rpcsec gss library to create a krb5
730 * context on behalf of the kernel
733 handle_krb5_upcall(struct clnt_info *clp)
736 gss_buffer_desc token = { 0, NULL };
737 struct lgssd_upcall_data updata;
738 struct lustre_gss_data lgd;
739 char **credlist = NULL;
743 printerr(2, "handling krb5 upcall\n");
745 memset(&lgd, 0, sizeof(lgd));
746 lgd.lgd_rpc_err = -EPERM; /* default error code */
748 read_rc = read(clp->krb5_fd, &updata, sizeof(updata));
750 printerr(0, "WARNING: failed reading from krb5 "
751 "upcall pipe: %s\n", strerror(errno));
753 } else if (read_rc != sizeof(updata)) {
754 printerr(0, "upcall data mismatch: length %d, expect %d\n",
755 read_rc, sizeof(updata));
757 /* the sequence number must be the first field. if read >= 4
758 * bytes then we know at least sequence is fine, try to send
759 * error notification nicely.
762 do_error_downcall(clp->krb5_fd, updata.seq, -EPERM, 0);
766 /* FIXME temporary fix, do this before fork.
767 * in case of errors could have memory leak!!!
769 if (updata.uid == 0) {
770 if (gssd_get_krb5_machine_cred_list(&credlist)) {
771 printerr(0, "ERROR: Failed to obtain machine "
773 do_error_downcall(clp->krb5_fd, updata.seq, -EPERM, 0);
778 /* fork child process */
781 printerr(0, "can't fork: %s\n", strerror(errno));
782 do_error_downcall(clp->krb5_fd, updata.seq, -EPERM, 0);
784 } else if (pid > 0) {
785 printerr(2, "forked child process: %d\n", pid);
789 printerr(1, "krb5 upcall: seq %u, uid %u, svc %u, nid 0x%llx, obd %s\n",
790 updata.seq, updata.uid, updata.svc, updata.nid, updata.obd);
792 if (updata.svc != LUSTRE_GSS_SVC_MDS &&
793 updata.svc != LUSTRE_GSS_SVC_OSS) {
794 printerr(0, "invalid svc %d\n", updata.svc);
795 lgd.lgd_rpc_err = -EPROTO;
796 goto out_return_error;
798 updata.obd[sizeof(updata.obd)-1] = '\0';
800 if (construct_service_name(clp, &updata)) {
801 printerr(0, "failed to construct service name\n");
802 goto out_return_error;
805 if (updata.uid == 0) {
809 * Get a list of credential cache names and try each
810 * of them until one works or we've tried them all
813 if (gssd_get_krb5_machine_cred_list(&credlist)) {
814 printerr(0, "ERROR: Failed to obtain machine "
815 "credentials for %s\n", clp->servicename);
816 goto out_return_error;
819 for (ccname = credlist; ccname && *ccname; ccname++) {
820 gssd_setup_krb5_machine_gss_ccache(*ccname);
821 if ((gssd_create_lgd(clp, &lgd, &updata,
822 AUTHTYPE_KRB5)) == 0) {
827 printerr(2, "WARNING: Failed to create krb5 context "
828 "for user with uid %d with credentials "
829 "cache %s for service %s\n",
830 updata.uid, *ccname, clp->servicename);
832 gssd_free_krb5_machine_cred_list(credlist);
834 printerr(0, "ERROR: Failed to create krb5 context "
835 "for user with uid %d with any "
836 "credentials cache for service %s\n",
837 updata.uid, clp->servicename);
838 goto out_return_error;
842 /* Tell krb5 gss which credentials cache to use */
843 gssd_setup_krb5_user_gss_ccache(updata.uid, clp->servicename);
845 if ((gssd_create_lgd(clp, &lgd, &updata, AUTHTYPE_KRB5)) != 0) {
846 printerr(0, "WARNING: Failed to create krb5 context "
847 "for user with uid %d for service %s\n",
848 updata.uid, clp->servicename);
849 goto out_return_error;
853 if (serialize_context_for_kernel(lgd.lgd_ctx, &token, &krb5oid)) {
854 printerr(0, "WARNING: Failed to serialize krb5 context for "
855 "user with uid %d for service %s\n",
856 updata.uid, clp->servicename);
857 goto out_return_error;
860 printerr(1, "refreshed: %u@%s for %s\n",
861 updata.uid, updata.obd, clp->servicename);
862 do_downcall(clp->krb5_fd, &updata, &lgd, &token);
869 exit(0); /* i'm child process */
872 do_error_downcall(clp->krb5_fd, updata.seq,
873 lgd.lgd_rpc_err, lgd.lgd_gss_err);