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>
68 #include <uapi/linux/lustre/lgss.h>
74 #include "krb5_util.h"
80 * array of struct pollfd suitable to pass to poll. initialized to
81 * zero - a zero struct is ignored by poll() because the events mask is 0.
84 * linked list of struct clnt_info which associates a clntXXX directory
85 * with an index into pollarray[], and other basic data about that client.
87 * Directory structure: created by the kernel nfs client
88 * {pipefs_nfsdir}/clntXX : one per rpc_clnt struct in the kernel
89 * {pipefs_nfsdir}/clntXX/krb5 : read uid for which kernel wants
90 * a context, write the resulting context
91 * {pipefs_nfsdir}/clntXX/info : stores info such as server name
94 * Poll all {pipefs_nfsdir}/clntXX/krb5 files. When ready, data read
95 * is a uid; performs rpcsec_gss context initialization protocol to
96 * get a cred for that user. Writes result to corresponding krb5 file
97 * in a form the kernel code will understand.
98 * In addition, we make sure we are notified whenever anything is
99 * created or destroyed in {pipefs_nfsdir} or in an of the clntXX directories,
100 * and rescan the whole {pipefs_nfsdir} when this happens.
103 TAILQ_HEAD(clnt_list_head, clnt_info) clnt_list;
105 struct pollfd * pollarray;
107 int pollsize; /* the size of pollaray (in pollfd's) */
110 destroy_client(struct clnt_info *clp)
112 printerr(3, "clp %p: dirname %s, krb5fd %d\n", clp, clp->dirname, clp->krb5_fd);
113 if (clp->krb5_poll_index != -1)
114 memset(&pollarray[clp->krb5_poll_index], 0,
115 sizeof(struct pollfd));
116 if (clp->spkm3_poll_index != -1)
117 memset(&pollarray[clp->spkm3_poll_index], 0,
118 sizeof(struct pollfd));
119 if (clp->dir_fd != -1) close(clp->dir_fd);
120 if (clp->krb5_fd != -1) close(clp->krb5_fd);
121 if (clp->spkm3_fd != -1) close(clp->spkm3_fd);
122 if (clp->dirname) free(clp->dirname);
123 if (clp->servicename) free(clp->servicename);
127 static struct clnt_info *
128 insert_new_clnt(void)
130 struct clnt_info *clp = NULL;
132 if (!(clp = (struct clnt_info *)calloc(1,sizeof(struct clnt_info)))) {
133 printerr(0, "ERROR: can't malloc clnt_info: %s\n",
137 clp->krb5_poll_index = -1;
138 clp->spkm3_poll_index = -1;
143 TAILQ_INSERT_HEAD(&clnt_list, clp, list);
149 process_clnt_dir_files(struct clnt_info * clp)
154 if (clp->krb5_fd == -1) {
155 snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname);
156 clp->krb5_fd = open(kname, O_RDWR);
158 if (clp->spkm3_fd == -1) {
159 snprintf(sname, sizeof(sname), "%s/spkm3", clp->dirname);
160 clp->spkm3_fd = open(sname, O_RDWR);
162 if((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
168 get_poll_index(int *ind)
173 for (i=0; i<FD_ALLOC_BLOCK; i++) {
174 if (pollarray[i].events == 0) {
180 printerr(0, "ERROR: No pollarray slots open\n");
188 insert_clnt_poll(struct clnt_info *clp)
190 if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
191 if (get_poll_index(&clp->krb5_poll_index)) {
192 printerr(0, "ERROR: Too many krb5 clients\n");
195 pollarray[clp->krb5_poll_index].fd = clp->krb5_fd;
196 pollarray[clp->krb5_poll_index].events |= POLLIN;
197 printerr(2, "monitoring krb5 channel under %s\n",
201 if ((clp->spkm3_fd != -1) && (clp->spkm3_poll_index == -1)) {
202 if (get_poll_index(&clp->spkm3_poll_index)) {
203 printerr(0, "ERROR: Too many spkm3 clients\n");
206 pollarray[clp->spkm3_poll_index].fd = clp->spkm3_fd;
207 pollarray[clp->spkm3_poll_index].events |= POLLIN;
214 process_clnt_dir(char *dir)
216 struct clnt_info * clp;
218 if (!(clp = insert_new_clnt()))
219 goto fail_destroy_client;
221 if (!(clp->dirname = calloc(strlen(dir) + 1, 1))) {
222 goto fail_destroy_client;
224 memcpy(clp->dirname, dir, strlen(dir));
225 if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
226 printerr(0, "ERROR: can't open %s: %s\n",
227 clp->dirname, strerror(errno));
228 goto fail_destroy_client;
230 fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL);
231 fcntl(clp->dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MULTISHOT);
233 if (process_clnt_dir_files(clp))
234 goto fail_keep_client;
236 if (insert_clnt_poll(clp))
237 goto fail_destroy_client;
243 TAILQ_REMOVE(&clnt_list, clp, list);
247 /* We couldn't find some subdirectories, but we keep the client
248 * around in case we get a notification on the directory when the
249 * subdirectories are created. */
253 init_client_list(void)
255 TAILQ_INIT(&clnt_list);
256 /* Eventually plan to grow/shrink poll array: */
257 pollsize = FD_ALLOC_BLOCK;
258 pollarray = calloc(pollsize, sizeof(struct pollfd));
261 struct clnt_info *clnt_list_first_entry(void)
263 return clnt_list.tqh_first;
267 * This is run after a DNOTIFY signal, and should clear up any
268 * directories that are no longer around, and re-scan any existing
269 * directories, since the DNOTIFY could have been in there.
272 update_old_clients(struct dirent **namelist, int size)
274 struct clnt_info *clp;
278 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
280 for (i=0; i < size; i++) {
281 if (!strcmp(clp->dirname, namelist[i]->d_name)) {
287 printerr(2, "destroying client %s\n", clp->dirname);
288 saveprev = clp->list.tqe_prev;
289 TAILQ_REMOVE(&clnt_list, clp, list);
294 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
295 if (!process_clnt_dir_files(clp))
296 insert_clnt_poll(clp);
300 /* Search for a client by directory name, return 1 if found, 0 otherwise */
302 find_client(char *dirname)
304 struct clnt_info *clp;
306 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
307 if (!strcmp(clp->dirname, dirname))
312 /* Used to read (and re-read) list of clients, set up poll array. */
314 update_client_list(void)
316 char lustre_dir[PATH_MAX];
317 struct dirent lustre_dirent = { .d_name = "lustre" };
318 struct dirent *namelist[1];
322 if (chdir(pipefs_dir) < 0) {
323 printerr(0, "ERROR: can't chdir to %s: %s\n",
324 pipefs_dir, strerror(errno));
328 snprintf(lustre_dir, sizeof(lustre_dir), "%s/%s", pipefs_dir, "lustre");
329 if (stat(lustre_dir, &statbuf) == 0) {
330 namelist[0] = &lustre_dirent;
332 printerr(2, "re-processing lustre directory\n");
336 printerr(2, "lustre directory not exist\n");
339 update_old_clients(namelist, j);
340 for (i=0; i < j; i++) {
341 if (i < FD_ALLOC_BLOCK && !find_client(namelist[i]->d_name))
342 process_clnt_dir(namelist[i]->d_name);
349 /* Context creation response. */
350 struct lustre_gss_init_res {
351 gss_buffer_desc gr_ctx; /* context handle */
352 unsigned int gr_major; /* major status */
353 unsigned int gr_minor; /* minor status */
354 unsigned int gr_win; /* sequence window */
355 gss_buffer_desc gr_token; /* token */
358 struct lustre_gss_data {
360 int lgd_lustre_svc; /* mds/oss */
361 int lgd_uid; /* uid */
362 char *lgd_uuid; /* client device uuid */
363 gss_name_t lgd_name; /* service name */
365 gss_OID lgd_mech; /* mech OID */
366 unsigned int lgd_req_flags; /* request flags */
367 gss_cred_id_t lgd_cred; /* credential */
368 gss_ctx_id_t lgd_ctx; /* session context */
369 gss_buffer_desc lgd_rmt_ctx; /* remote handle of context */
370 uint32_t lgd_seq_win; /* sequence window */
377 do_downcall(int k5_fd, struct lgssd_upcall_data *updata,
378 struct lustre_gss_data *lgd, gss_buffer_desc *context_token)
380 char *buf = NULL, *p = NULL, *end = NULL;
381 unsigned int timeout = 0; /* XXX decide on a reasonable value */
382 unsigned int buf_size = 0;
384 printerr(2, "doing downcall\n");
385 buf_size = sizeof(updata->seq) + sizeof(timeout) +
386 sizeof(lgd->lgd_seq_win) +
387 sizeof(lgd->lgd_rmt_ctx.length) + lgd->lgd_rmt_ctx.length +
388 sizeof(context_token->length) + context_token->length;
389 p = buf = malloc(buf_size);
390 end = buf + buf_size;
392 if (WRITE_BYTES(&p, end, updata->seq)) goto out_err;
393 /* Not setting any timeout for now: */
394 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
395 if (WRITE_BYTES(&p, end, lgd->lgd_seq_win)) goto out_err;
396 if (write_buffer(&p, end, &lgd->lgd_rmt_ctx)) goto out_err;
397 if (write_buffer(&p, end, context_token)) goto out_err;
399 lgssd_mutex_get(lgssd_mutex_downcall);
400 if (write(k5_fd, buf, p - buf) < p - buf) {
401 lgssd_mutex_put(lgssd_mutex_downcall);
404 lgssd_mutex_put(lgssd_mutex_downcall);
410 printerr(0, "ERROR: Failed to write downcall!\n");
415 do_error_downcall(int k5_fd, uint32_t seq, int rpc_err, int gss_err)
418 char *p = buf, *end = buf + 1024;
419 unsigned int timeout = 0;
422 printerr(1, "doing error downcall\n");
424 if (WRITE_BYTES(&p, end, seq)) goto out_err;
425 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
426 /* use seq_win = 0 to indicate an error: */
427 if (WRITE_BYTES(&p, end, zero)) goto out_err;
428 if (WRITE_BYTES(&p, end, rpc_err)) goto out_err;
429 if (WRITE_BYTES(&p, end, gss_err)) goto out_err;
431 lgssd_mutex_get(lgssd_mutex_downcall);
432 if (write(k5_fd, buf, p - buf) < p - buf) {
433 lgssd_mutex_put(lgssd_mutex_downcall);
436 lgssd_mutex_put(lgssd_mutex_downcall);
439 printerr(0, "Failed to write error downcall!\n");
444 int do_negotiation(struct lustre_gss_data *lgd,
445 gss_buffer_desc *gss_token,
446 struct lustre_gss_init_res *gr,
449 struct lgssd_ioctl_param param;
457 pw = getpwuid(lgd->lgd_uid);
459 printerr(0, "no uid %u in local user database\n",
464 param.version = GSSD_INTERFACE_VERSION_V1;
465 param.uuid = lgd->lgd_uuid;
466 param.lustre_svc = lgd->lgd_lustre_svc;
467 param.uid = lgd->lgd_uid;
468 param.gid = pw->pw_gid;
469 param.send_token_size = gss_token->length;
470 param.send_token = (char *) gss_token->value;
471 param.reply_buf_size = sizeof(outbuf);
472 param.reply_buf = outbuf;
474 if (cfs_get_param_paths(&path, "sptlrpc/gss/init_channel") != 0)
477 fd = open(path.gl_pathv[0], O_RDWR);
479 printerr(0, "can't open file %s\n", path.gl_pathv[0]);
484 rc = write(fd, ¶m, sizeof(param));
485 if (rc != sizeof(param)) {
486 printerr(0, "lustre ioctl err: %d\n", strerror(errno));
491 printerr(0, "status: %d (%s)\n",
492 param.status, strerror((int)param.status));
493 if (param.status == -ETIMEDOUT) {
494 /* kernel return -ETIMEDOUT means the rpc timedout,
495 * we should notify the caller to reinitiate the
496 * gss negotiation, by return -ERESTART
498 lgd->lgd_rpc_err = -ERESTART;
499 lgd->lgd_gss_err = 0;
501 lgd->lgd_rpc_err = param.status;
502 lgd->lgd_gss_err = 0;
507 p = (unsigned int *)outbuf;
512 gr->gr_ctx.length = *p++;
513 gr->gr_ctx.value = malloc(gr->gr_ctx.length);
514 memcpy(gr->gr_ctx.value, p, gr->gr_ctx.length);
515 p += (((gr->gr_ctx.length + 3) & ~3) / 4);
517 gr->gr_token.length = *p++;
518 gr->gr_token.value = malloc(gr->gr_token.length);
519 memcpy(gr->gr_token.value, p, gr->gr_token.length);
520 p += (((gr->gr_token.length + 3) & ~3) / 4);
522 printerr(2, "do_negotiation: receive handle len %d, token len %d\n",
523 gr->gr_ctx.length, gr->gr_token.length);
528 cfs_free_param_data(&path);
533 int gssd_refresh_lgd(struct lustre_gss_data *lgd)
535 struct lustre_gss_init_res gr;
536 gss_buffer_desc *recv_tokenp, send_token;
537 OM_uint32 maj_stat, min_stat, call_stat, ret_flags;
539 /* GSS context establishment loop. */
540 memset(&gr, 0, sizeof(gr));
541 recv_tokenp = GSS_C_NO_BUFFER;
544 /* print the token we just received */
545 if (recv_tokenp != GSS_C_NO_BUFFER) {
546 printerr(3, "The received token length %d\n",
547 recv_tokenp->length);
548 print_hexl(3, recv_tokenp->value, recv_tokenp->length);
551 maj_stat = gss_init_sec_context(&min_stat,
560 NULL, /* used mech */
563 NULL); /* time rec */
565 if (recv_tokenp != GSS_C_NO_BUFFER) {
566 gss_release_buffer(&min_stat, &gr.gr_token);
567 recv_tokenp = GSS_C_NO_BUFFER;
569 if (maj_stat != GSS_S_COMPLETE &&
570 maj_stat != GSS_S_CONTINUE_NEEDED) {
571 pgsserr("gss_init_sec_context", maj_stat, min_stat,
575 if (send_token.length != 0) {
576 memset(&gr, 0, sizeof(gr));
578 /* print the token we are about to send */
579 printerr(3, "token being sent length %d\n",
581 print_hexl(3, send_token.value, send_token.length);
583 call_stat = do_negotiation(lgd, &send_token, &gr, 0);
584 gss_release_buffer(&min_stat, &send_token);
586 if (call_stat != 0 ||
587 (gr.gr_major != GSS_S_COMPLETE &&
588 gr.gr_major != GSS_S_CONTINUE_NEEDED)) {
589 printerr(0, "call stat %d, major stat 0x%x\n",
590 (int)call_stat, gr.gr_major);
594 if (gr.gr_ctx.length != 0) {
595 if (lgd->lgd_rmt_ctx.value)
596 gss_release_buffer(&min_stat,
598 lgd->lgd_rmt_ctx = gr.gr_ctx;
600 if (gr.gr_token.length != 0) {
601 if (maj_stat != GSS_S_CONTINUE_NEEDED)
603 recv_tokenp = &gr.gr_token;
607 /* GSS_S_COMPLETE => check gss header verifier,
608 * usually checked in gss_validate
610 if (maj_stat == GSS_S_COMPLETE) {
611 lgd->lgd_established = 1;
612 lgd->lgd_seq_win = gr.gr_win;
616 /* End context negotiation loop. */
617 if (!lgd->lgd_established) {
618 if (gr.gr_token.length != 0)
619 gss_release_buffer(&min_stat, &gr.gr_token);
621 printerr(0, "context negotiation failed\n");
625 printerr(2, "successfully refreshed lgd\n");
630 int gssd_create_lgd(struct clnt_info *clp,
631 struct lustre_gss_data *lgd,
632 struct lgssd_upcall_data *updata,
635 gss_buffer_desc sname;
636 OM_uint32 maj_stat, min_stat;
639 lgd->lgd_established = 0;
640 lgd->lgd_lustre_svc = updata->svc;
641 lgd->lgd_uid = updata->uid;
642 lgd->lgd_uuid = updata->obd;
646 lgd->lgd_mech = (gss_OID) &krb5oid;
647 lgd->lgd_req_flags = GSS_C_MUTUAL_FLAG;
650 lgd->lgd_mech = (gss_OID) &spkm3oid;
651 /* XXX sec.req_flags = GSS_C_ANON_FLAG;
652 * Need a way to switch....
654 lgd->lgd_req_flags = GSS_C_MUTUAL_FLAG;
657 printerr(0, "Invalid authentication type (%d)\n", authtype);
661 lgd->lgd_cred = GSS_C_NO_CREDENTIAL;
662 lgd->lgd_ctx = GSS_C_NO_CONTEXT;
663 lgd->lgd_rmt_ctx = (gss_buffer_desc) GSS_C_EMPTY_BUFFER;
664 lgd->lgd_seq_win = 0;
666 sname.value = clp->servicename;
667 sname.length = strlen(clp->servicename);
669 maj_stat = gss_import_name(&min_stat, &sname,
670 (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
672 if (maj_stat != GSS_S_COMPLETE) {
673 pgsserr(0, maj_stat, min_stat, lgd->lgd_mech);
677 retval = gssd_refresh_lgd(lgd);
679 if (lgd->lgd_name != GSS_C_NO_NAME)
680 gss_release_name(&min_stat, &lgd->lgd_name);
682 if (lgd->lgd_cred != GSS_C_NO_CREDENTIAL)
683 gss_release_cred(&min_stat, &lgd->lgd_cred);
690 void gssd_free_lgd(struct lustre_gss_data *lgd)
692 gss_buffer_t token = GSS_C_NO_BUFFER;
693 OM_uint32 maj_stat, min_stat;
695 if (lgd->lgd_ctx == GSS_C_NO_CONTEXT)
698 maj_stat = gss_delete_sec_context(&min_stat, &lgd->lgd_ctx, token);
702 int construct_service_name(struct clnt_info *clp,
703 struct lgssd_upcall_data *ud)
705 const int buflen = 256;
708 if (clp->servicename) {
709 free(clp->servicename);
710 clp->servicename = NULL;
713 if (lnet_nid2hostname(ud->nid, name, buflen))
716 clp->servicename = malloc(32 + strlen(name));
717 if (!clp->servicename) {
718 printerr(0, "can't alloc memory\n");
721 sprintf(clp->servicename, "%s@%s",
722 ud->svc == LUSTRE_GSS_SVC_MDS ?
723 GSSD_SERVICE_MDS : GSSD_SERVICE_OSS,
725 printerr(2, "constructed servicename: %s\n", clp->servicename);
730 * this code uses the userland rpcsec gss library to create a krb5
731 * context on behalf of the kernel
734 handle_krb5_upcall(struct clnt_info *clp)
737 gss_buffer_desc token = { 0, NULL };
738 struct lgssd_upcall_data updata;
739 struct lustre_gss_data lgd;
740 char **credlist = NULL;
744 printerr(2, "handling krb5 upcall\n");
746 memset(&lgd, 0, sizeof(lgd));
747 lgd.lgd_rpc_err = -EPERM; /* default error code */
749 read_rc = read(clp->krb5_fd, &updata, sizeof(updata));
751 printerr(0, "WARNING: failed reading from krb5 "
752 "upcall pipe: %s\n", strerror(errno));
754 } else if (read_rc != sizeof(updata)) {
755 printerr(0, "upcall data mismatch: length %d, expect %d\n",
756 read_rc, sizeof(updata));
758 /* the sequence number must be the first field. if read >= 4
759 * bytes then we know at least sequence is fine, try to send
760 * error notification nicely.
763 do_error_downcall(clp->krb5_fd, updata.seq, -EPERM, 0);
767 /* FIXME temporary fix, do this before fork.
768 * in case of errors could have memory leak!!!
770 if (updata.uid == 0) {
771 if (gssd_get_krb5_machine_cred_list(&credlist)) {
772 printerr(0, "ERROR: Failed to obtain machine "
774 do_error_downcall(clp->krb5_fd, updata.seq, -EPERM, 0);
779 /* fork child process */
782 printerr(0, "can't fork: %s\n", strerror(errno));
783 do_error_downcall(clp->krb5_fd, updata.seq, -EPERM, 0);
785 } else if (pid > 0) {
786 printerr(2, "forked child process: %d\n", pid);
790 printerr(1, "krb5 upcall: seq %u, uid %u, svc %u, nid 0x%llx, obd %s\n",
791 updata.seq, updata.uid, updata.svc, updata.nid, updata.obd);
793 if (updata.svc != LUSTRE_GSS_SVC_MDS &&
794 updata.svc != LUSTRE_GSS_SVC_OSS) {
795 printerr(0, "invalid svc %d\n", updata.svc);
796 lgd.lgd_rpc_err = -EPROTO;
797 goto out_return_error;
799 updata.obd[sizeof(updata.obd)-1] = '\0';
801 if (construct_service_name(clp, &updata)) {
802 printerr(0, "failed to construct service name\n");
803 goto out_return_error;
806 if (updata.uid == 0) {
810 * Get a list of credential cache names and try each
811 * of them until one works or we've tried them all
814 if (gssd_get_krb5_machine_cred_list(&credlist)) {
815 printerr(0, "ERROR: Failed to obtain machine "
816 "credentials for %s\n", clp->servicename);
817 goto out_return_error;
820 for (ccname = credlist; ccname && *ccname; ccname++) {
821 gssd_setup_krb5_machine_gss_ccache(*ccname);
822 if ((gssd_create_lgd(clp, &lgd, &updata,
823 AUTHTYPE_KRB5)) == 0) {
828 printerr(2, "WARNING: Failed to create krb5 context "
829 "for user with uid %d with credentials "
830 "cache %s for service %s\n",
831 updata.uid, *ccname, clp->servicename);
833 gssd_free_krb5_machine_cred_list(credlist);
835 printerr(0, "ERROR: Failed to create krb5 context "
836 "for user with uid %d with any "
837 "credentials cache for service %s\n",
838 updata.uid, clp->servicename);
839 goto out_return_error;
843 /* Tell krb5 gss which credentials cache to use */
844 gssd_setup_krb5_user_gss_ccache(updata.uid, clp->servicename);
846 if ((gssd_create_lgd(clp, &lgd, &updata, AUTHTYPE_KRB5)) != 0) {
847 printerr(0, "WARNING: Failed to create krb5 context "
848 "for user with uid %d for service %s\n",
849 updata.uid, clp->servicename);
850 goto out_return_error;
854 if (serialize_context_for_kernel(lgd.lgd_ctx, &token, &krb5oid)) {
855 printerr(0, "WARNING: Failed to serialize krb5 context for "
856 "user with uid %d for service %s\n",
857 updata.uid, clp->servicename);
858 goto out_return_error;
861 printerr(1, "refreshed: %u@%s for %s\n",
862 updata.uid, updata.obd, clp->servicename);
863 do_downcall(clp->krb5_fd, &updata, &lgd, &token);
870 exit(0); /* i'm child process */
873 do_error_downcall(clp->krb5_fd, updata.seq,
874 lgd.lgd_rpc_err, lgd.lgd_gss_err);