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 struct pollfd * pollarray;
104 int pollsize; /* the size of pollaray (in pollfd's) */
107 destroy_client(struct clnt_info *clp)
109 printerr(3, "clp %p: dirname %s, krb5fd %d\n", clp, clp->dirname, clp->krb5_fd);
110 if (clp->krb5_poll_index != -1)
111 memset(&pollarray[clp->krb5_poll_index], 0,
112 sizeof(struct pollfd));
113 if (clp->spkm3_poll_index != -1)
114 memset(&pollarray[clp->spkm3_poll_index], 0,
115 sizeof(struct pollfd));
116 if (clp->dir_fd != -1) close(clp->dir_fd);
117 if (clp->krb5_fd != -1) close(clp->krb5_fd);
118 if (clp->spkm3_fd != -1) close(clp->spkm3_fd);
119 if (clp->dirname) free(clp->dirname);
120 if (clp->servicename) free(clp->servicename);
124 static struct clnt_info *
125 insert_new_clnt(void)
127 struct clnt_info *clp = NULL;
129 if (!(clp = (struct clnt_info *)calloc(1,sizeof(struct clnt_info)))) {
130 printerr(0, "ERROR: can't malloc clnt_info: %s\n",
134 clp->krb5_poll_index = -1;
135 clp->spkm3_poll_index = -1;
140 TAILQ_INSERT_HEAD(&clnt_list, clp, list);
146 process_clnt_dir_files(struct clnt_info * clp)
151 if (clp->krb5_fd == -1) {
152 snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname);
153 clp->krb5_fd = open(kname, O_RDWR);
155 if (clp->spkm3_fd == -1) {
156 snprintf(sname, sizeof(sname), "%s/spkm3", clp->dirname);
157 clp->spkm3_fd = open(sname, O_RDWR);
159 if((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
165 get_poll_index(int *ind)
170 for (i=0; i<FD_ALLOC_BLOCK; i++) {
171 if (pollarray[i].events == 0) {
177 printerr(0, "ERROR: No pollarray slots open\n");
185 insert_clnt_poll(struct clnt_info *clp)
187 if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
188 if (get_poll_index(&clp->krb5_poll_index)) {
189 printerr(0, "ERROR: Too many krb5 clients\n");
192 pollarray[clp->krb5_poll_index].fd = clp->krb5_fd;
193 pollarray[clp->krb5_poll_index].events |= POLLIN;
194 printerr(2, "monitoring krb5 channel under %s\n",
198 if ((clp->spkm3_fd != -1) && (clp->spkm3_poll_index == -1)) {
199 if (get_poll_index(&clp->spkm3_poll_index)) {
200 printerr(0, "ERROR: Too many spkm3 clients\n");
203 pollarray[clp->spkm3_poll_index].fd = clp->spkm3_fd;
204 pollarray[clp->spkm3_poll_index].events |= POLLIN;
211 process_clnt_dir(char *dir)
213 struct clnt_info * clp;
215 if (!(clp = insert_new_clnt()))
216 goto fail_destroy_client;
218 if (!(clp->dirname = calloc(strlen(dir) + 1, 1))) {
219 goto fail_destroy_client;
221 memcpy(clp->dirname, dir, strlen(dir));
222 if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
223 printerr(0, "ERROR: can't open %s: %s\n",
224 clp->dirname, strerror(errno));
225 goto fail_destroy_client;
227 fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL);
228 fcntl(clp->dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MULTISHOT);
230 if (process_clnt_dir_files(clp))
231 goto fail_keep_client;
233 if (insert_clnt_poll(clp))
234 goto fail_destroy_client;
240 TAILQ_REMOVE(&clnt_list, clp, list);
244 /* We couldn't find some subdirectories, but we keep the client
245 * around in case we get a notification on the directory when the
246 * subdirectories are created. */
250 init_client_list(void)
252 TAILQ_INIT(&clnt_list);
253 /* Eventually plan to grow/shrink poll array: */
254 pollsize = FD_ALLOC_BLOCK;
255 pollarray = calloc(pollsize, sizeof(struct pollfd));
259 * This is run after a DNOTIFY signal, and should clear up any
260 * directories that are no longer around, and re-scan any existing
261 * directories, since the DNOTIFY could have been in there.
264 update_old_clients(struct dirent **namelist, int size)
266 struct clnt_info *clp;
270 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
272 for (i=0; i < size; i++) {
273 if (!strcmp(clp->dirname, namelist[i]->d_name)) {
279 printerr(2, "destroying client %s\n", clp->dirname);
280 saveprev = clp->list.tqe_prev;
281 TAILQ_REMOVE(&clnt_list, clp, list);
286 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
287 if (!process_clnt_dir_files(clp))
288 insert_clnt_poll(clp);
292 /* Search for a client by directory name, return 1 if found, 0 otherwise */
294 find_client(char *dirname)
296 struct clnt_info *clp;
298 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
299 if (!strcmp(clp->dirname, dirname))
304 /* Used to read (and re-read) list of clients, set up poll array. */
306 update_client_list(void)
308 char lustre_dir[PATH_MAX];
309 struct dirent lustre_dirent = { .d_name = "lustre" };
310 struct dirent *namelist[1];
314 if (chdir(pipefs_dir) < 0) {
315 printerr(0, "ERROR: can't chdir to %s: %s\n",
316 pipefs_dir, strerror(errno));
320 snprintf(lustre_dir, sizeof(lustre_dir), "%s/%s", pipefs_dir, "lustre");
321 if (stat(lustre_dir, &statbuf) == 0) {
322 namelist[0] = &lustre_dirent;
324 printerr(2, "re-processing lustre directory\n");
328 printerr(2, "lustre directory not exist\n");
331 update_old_clients(namelist, j);
332 for (i=0; i < j; i++) {
333 if (i < FD_ALLOC_BLOCK && !find_client(namelist[i]->d_name))
334 process_clnt_dir(namelist[i]->d_name);
341 /* Context creation response. */
342 struct lustre_gss_init_res {
343 gss_buffer_desc gr_ctx; /* context handle */
344 unsigned int gr_major; /* major status */
345 unsigned int gr_minor; /* minor status */
346 unsigned int gr_win; /* sequence window */
347 gss_buffer_desc gr_token; /* token */
350 struct lustre_gss_data {
352 int lgd_lustre_svc; /* mds/oss */
353 int lgd_uid; /* uid */
354 char *lgd_uuid; /* client device uuid */
355 gss_name_t lgd_name; /* service name */
357 gss_OID lgd_mech; /* mech OID */
358 unsigned int lgd_req_flags; /* request flags */
359 gss_cred_id_t lgd_cred; /* credential */
360 gss_ctx_id_t lgd_ctx; /* session context */
361 gss_buffer_desc lgd_rmt_ctx; /* remote handle of context */
362 uint32_t lgd_seq_win; /* sequence window */
369 do_downcall(int k5_fd, struct lgssd_upcall_data *updata,
370 struct lustre_gss_data *lgd, gss_buffer_desc *context_token)
372 char *buf = NULL, *p = NULL, *end = NULL;
373 unsigned int timeout = 0; /* XXX decide on a reasonable value */
374 unsigned int buf_size = 0;
376 printerr(2, "doing downcall\n");
377 buf_size = sizeof(updata->seq) + sizeof(timeout) +
378 sizeof(lgd->lgd_seq_win) +
379 sizeof(lgd->lgd_rmt_ctx.length) + lgd->lgd_rmt_ctx.length +
380 sizeof(context_token->length) + context_token->length;
381 p = buf = malloc(buf_size);
382 end = buf + buf_size;
384 if (WRITE_BYTES(&p, end, updata->seq)) goto out_err;
385 /* Not setting any timeout for now: */
386 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
387 if (WRITE_BYTES(&p, end, lgd->lgd_seq_win)) goto out_err;
388 if (write_buffer(&p, end, &lgd->lgd_rmt_ctx)) goto out_err;
389 if (write_buffer(&p, end, context_token)) goto out_err;
391 lgssd_mutex_get(lgssd_mutex_downcall);
392 if (write(k5_fd, buf, p - buf) < p - buf) {
393 lgssd_mutex_put(lgssd_mutex_downcall);
396 lgssd_mutex_put(lgssd_mutex_downcall);
402 printerr(0, "ERROR: Failed to write downcall!\n");
407 do_error_downcall(int k5_fd, uint32_t seq, int rpc_err, int gss_err)
410 char *p = buf, *end = buf + 1024;
411 unsigned int timeout = 0;
414 printerr(1, "doing error downcall\n");
416 if (WRITE_BYTES(&p, end, seq)) goto out_err;
417 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
418 /* use seq_win = 0 to indicate an error: */
419 if (WRITE_BYTES(&p, end, zero)) goto out_err;
420 if (WRITE_BYTES(&p, end, rpc_err)) goto out_err;
421 if (WRITE_BYTES(&p, end, gss_err)) goto out_err;
423 lgssd_mutex_get(lgssd_mutex_downcall);
424 if (write(k5_fd, buf, p - buf) < p - buf) {
425 lgssd_mutex_put(lgssd_mutex_downcall);
428 lgssd_mutex_put(lgssd_mutex_downcall);
431 printerr(0, "Failed to write error downcall!\n");
436 int do_negotiation(struct lustre_gss_data *lgd,
437 gss_buffer_desc *gss_token,
438 struct lustre_gss_init_res *gr,
441 struct lgssd_ioctl_param param;
449 pw = getpwuid(lgd->lgd_uid);
451 printerr(0, "no uid %u in local user database\n",
456 param.version = GSSD_INTERFACE_VERSION_V1;
457 param.uuid = lgd->lgd_uuid;
458 param.lustre_svc = lgd->lgd_lustre_svc;
459 param.uid = lgd->lgd_uid;
460 param.gid = pw->pw_gid;
461 param.send_token_size = gss_token->length;
462 param.send_token = (char *) gss_token->value;
463 param.reply_buf_size = sizeof(outbuf);
464 param.reply_buf = outbuf;
466 if (cfs_get_param_paths(&path, "sptlrpc/gss/init_channel") != 0)
469 fd = open(path.gl_pathv[0], O_RDWR);
471 printerr(0, "can't open file %s\n", path.gl_pathv[0]);
476 rc = write(fd, ¶m, sizeof(param));
477 if (rc != sizeof(param)) {
478 printerr(0, "lustre ioctl err: %d\n", strerror(errno));
483 printerr(0, "status: %d (%s)\n",
484 param.status, strerror((int)param.status));
485 if (param.status == -ETIMEDOUT) {
486 /* kernel return -ETIMEDOUT means the rpc timedout,
487 * we should notify the caller to reinitiate the
488 * gss negotiation, by return -ERESTART
490 lgd->lgd_rpc_err = -ERESTART;
491 lgd->lgd_gss_err = 0;
493 lgd->lgd_rpc_err = param.status;
494 lgd->lgd_gss_err = 0;
499 p = (unsigned int *)outbuf;
504 gr->gr_ctx.length = *p++;
505 gr->gr_ctx.value = malloc(gr->gr_ctx.length);
506 memcpy(gr->gr_ctx.value, p, gr->gr_ctx.length);
507 p += (((gr->gr_ctx.length + 3) & ~3) / 4);
509 gr->gr_token.length = *p++;
510 gr->gr_token.value = malloc(gr->gr_token.length);
511 memcpy(gr->gr_token.value, p, gr->gr_token.length);
512 p += (((gr->gr_token.length + 3) & ~3) / 4);
514 printerr(2, "do_negotiation: receive handle len %d, token len %d\n",
515 gr->gr_ctx.length, gr->gr_token.length);
520 cfs_free_param_data(&path);
525 int gssd_refresh_lgd(struct lustre_gss_data *lgd)
527 struct lustre_gss_init_res gr;
528 gss_buffer_desc *recv_tokenp, send_token;
529 OM_uint32 maj_stat, min_stat, call_stat, ret_flags;
531 /* GSS context establishment loop. */
532 memset(&gr, 0, sizeof(gr));
533 recv_tokenp = GSS_C_NO_BUFFER;
536 /* print the token we just received */
537 if (recv_tokenp != GSS_C_NO_BUFFER) {
538 printerr(3, "The received token length %d\n",
539 recv_tokenp->length);
540 print_hexl(3, recv_tokenp->value, recv_tokenp->length);
543 maj_stat = gss_init_sec_context(&min_stat,
552 NULL, /* used mech */
555 NULL); /* time rec */
557 if (recv_tokenp != GSS_C_NO_BUFFER) {
558 gss_release_buffer(&min_stat, &gr.gr_token);
559 recv_tokenp = GSS_C_NO_BUFFER;
561 if (maj_stat != GSS_S_COMPLETE &&
562 maj_stat != GSS_S_CONTINUE_NEEDED) {
563 pgsserr("gss_init_sec_context", maj_stat, min_stat,
567 if (send_token.length != 0) {
568 memset(&gr, 0, sizeof(gr));
570 /* print the token we are about to send */
571 printerr(3, "token being sent length %d\n",
573 print_hexl(3, send_token.value, send_token.length);
575 call_stat = do_negotiation(lgd, &send_token, &gr, 0);
576 gss_release_buffer(&min_stat, &send_token);
578 if (call_stat != 0 ||
579 (gr.gr_major != GSS_S_COMPLETE &&
580 gr.gr_major != GSS_S_CONTINUE_NEEDED)) {
581 printerr(0, "call stat %d, major stat 0x%x\n",
582 (int)call_stat, gr.gr_major);
586 if (gr.gr_ctx.length != 0) {
587 if (lgd->lgd_rmt_ctx.value)
588 gss_release_buffer(&min_stat,
590 lgd->lgd_rmt_ctx = gr.gr_ctx;
592 if (gr.gr_token.length != 0) {
593 if (maj_stat != GSS_S_CONTINUE_NEEDED)
595 recv_tokenp = &gr.gr_token;
599 /* GSS_S_COMPLETE => check gss header verifier,
600 * usually checked in gss_validate
602 if (maj_stat == GSS_S_COMPLETE) {
603 lgd->lgd_established = 1;
604 lgd->lgd_seq_win = gr.gr_win;
608 /* End context negotiation loop. */
609 if (!lgd->lgd_established) {
610 if (gr.gr_token.length != 0)
611 gss_release_buffer(&min_stat, &gr.gr_token);
613 printerr(0, "context negotiation failed\n");
617 printerr(2, "successfully refreshed lgd\n");
622 int gssd_create_lgd(struct clnt_info *clp,
623 struct lustre_gss_data *lgd,
624 struct lgssd_upcall_data *updata,
627 gss_buffer_desc sname;
628 OM_uint32 maj_stat, min_stat;
631 lgd->lgd_established = 0;
632 lgd->lgd_lustre_svc = updata->svc;
633 lgd->lgd_uid = updata->uid;
634 lgd->lgd_uuid = updata->obd;
638 lgd->lgd_mech = (gss_OID) &krb5oid;
639 lgd->lgd_req_flags = GSS_C_MUTUAL_FLAG;
642 lgd->lgd_mech = (gss_OID) &spkm3oid;
643 /* XXX sec.req_flags = GSS_C_ANON_FLAG;
644 * Need a way to switch....
646 lgd->lgd_req_flags = GSS_C_MUTUAL_FLAG;
649 printerr(0, "Invalid authentication type (%d)\n", authtype);
653 lgd->lgd_cred = GSS_C_NO_CREDENTIAL;
654 lgd->lgd_ctx = GSS_C_NO_CONTEXT;
655 lgd->lgd_rmt_ctx = (gss_buffer_desc) GSS_C_EMPTY_BUFFER;
656 lgd->lgd_seq_win = 0;
658 sname.value = clp->servicename;
659 sname.length = strlen(clp->servicename);
661 maj_stat = gss_import_name(&min_stat, &sname,
662 (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
664 if (maj_stat != GSS_S_COMPLETE) {
665 pgsserr(0, maj_stat, min_stat, lgd->lgd_mech);
669 retval = gssd_refresh_lgd(lgd);
671 if (lgd->lgd_name != GSS_C_NO_NAME)
672 gss_release_name(&min_stat, &lgd->lgd_name);
674 if (lgd->lgd_cred != GSS_C_NO_CREDENTIAL)
675 gss_release_cred(&min_stat, &lgd->lgd_cred);
682 void gssd_free_lgd(struct lustre_gss_data *lgd)
684 gss_buffer_t token = GSS_C_NO_BUFFER;
685 OM_uint32 maj_stat, min_stat;
687 if (lgd->lgd_ctx == GSS_C_NO_CONTEXT)
690 maj_stat = gss_delete_sec_context(&min_stat, &lgd->lgd_ctx, token);
694 int construct_service_name(struct clnt_info *clp,
695 struct lgssd_upcall_data *ud)
697 const int buflen = 256;
700 if (clp->servicename) {
701 free(clp->servicename);
702 clp->servicename = NULL;
705 if (lnet_nid2hostname(ud->nid, name, buflen))
708 clp->servicename = malloc(32 + strlen(name));
709 if (!clp->servicename) {
710 printerr(0, "can't alloc memory\n");
713 sprintf(clp->servicename, "%s@%s",
714 ud->svc == LUSTRE_GSS_SVC_MDS ?
715 GSSD_SERVICE_MDS : GSSD_SERVICE_OSS,
717 printerr(2, "constructed servicename: %s\n", clp->servicename);
722 * this code uses the userland rpcsec gss library to create a krb5
723 * context on behalf of the kernel
726 handle_krb5_upcall(struct clnt_info *clp)
729 gss_buffer_desc token = { 0, NULL };
730 struct lgssd_upcall_data updata;
731 struct lustre_gss_data lgd;
732 char **credlist = NULL;
736 printerr(2, "handling krb5 upcall\n");
738 memset(&lgd, 0, sizeof(lgd));
739 lgd.lgd_rpc_err = -EPERM; /* default error code */
741 read_rc = read(clp->krb5_fd, &updata, sizeof(updata));
743 printerr(0, "WARNING: failed reading from krb5 "
744 "upcall pipe: %s\n", strerror(errno));
746 } else if (read_rc != sizeof(updata)) {
747 printerr(0, "upcall data mismatch: length %d, expect %d\n",
748 read_rc, sizeof(updata));
750 /* the sequence number must be the first field. if read >= 4
751 * bytes then we know at least sequence is fine, try to send
752 * error notification nicely.
755 do_error_downcall(clp->krb5_fd, updata.seq, -EPERM, 0);
759 /* FIXME temporary fix, do this before fork.
760 * in case of errors could have memory leak!!!
762 if (updata.uid == 0) {
763 if (gssd_get_krb5_machine_cred_list(&credlist)) {
764 printerr(0, "ERROR: Failed to obtain machine "
766 do_error_downcall(clp->krb5_fd, updata.seq, -EPERM, 0);
771 /* fork child process */
774 printerr(0, "can't fork: %s\n", strerror(errno));
775 do_error_downcall(clp->krb5_fd, updata.seq, -EPERM, 0);
777 } else if (pid > 0) {
778 printerr(2, "forked child process: %d\n", pid);
782 printerr(1, "krb5 upcall: seq %u, uid %u, svc %u, nid 0x%llx, obd %s\n",
783 updata.seq, updata.uid, updata.svc, updata.nid, updata.obd);
785 if (updata.svc != LUSTRE_GSS_SVC_MDS &&
786 updata.svc != LUSTRE_GSS_SVC_OSS) {
787 printerr(0, "invalid svc %d\n", updata.svc);
788 lgd.lgd_rpc_err = -EPROTO;
789 goto out_return_error;
791 updata.obd[sizeof(updata.obd)-1] = '\0';
793 if (construct_service_name(clp, &updata)) {
794 printerr(0, "failed to construct service name\n");
795 goto out_return_error;
798 if (updata.uid == 0) {
802 * Get a list of credential cache names and try each
803 * of them until one works or we've tried them all
806 if (gssd_get_krb5_machine_cred_list(&credlist)) {
807 printerr(0, "ERROR: Failed to obtain machine "
808 "credentials for %s\n", clp->servicename);
809 goto out_return_error;
812 for (ccname = credlist; ccname && *ccname; ccname++) {
813 gssd_setup_krb5_machine_gss_ccache(*ccname);
814 if ((gssd_create_lgd(clp, &lgd, &updata,
815 AUTHTYPE_KRB5)) == 0) {
820 printerr(2, "WARNING: Failed to create krb5 context "
821 "for user with uid %d with credentials "
822 "cache %s for service %s\n",
823 updata.uid, *ccname, clp->servicename);
825 gssd_free_krb5_machine_cred_list(credlist);
827 printerr(0, "ERROR: Failed to create krb5 context "
828 "for user with uid %d with any "
829 "credentials cache for service %s\n",
830 updata.uid, clp->servicename);
831 goto out_return_error;
835 /* Tell krb5 gss which credentials cache to use */
836 gssd_setup_krb5_user_gss_ccache(updata.uid, clp->servicename);
838 if ((gssd_create_lgd(clp, &lgd, &updata, AUTHTYPE_KRB5)) != 0) {
839 printerr(0, "WARNING: Failed to create krb5 context "
840 "for user with uid %d for service %s\n",
841 updata.uid, clp->servicename);
842 goto out_return_error;
846 if (serialize_context_for_kernel(lgd.lgd_ctx, &token, &krb5oid)) {
847 printerr(0, "WARNING: Failed to serialize krb5 context for "
848 "user with uid %d for service %s\n",
849 updata.uid, clp->servicename);
850 goto out_return_error;
853 printerr(1, "refreshed: %u@%s for %s\n",
854 updata.uid, updata.obd, clp->servicename);
855 do_downcall(clp->krb5_fd, &updata, &lgd, &token);
862 exit(0); /* i'm child process */
865 do_error_downcall(clp->krb5_fd, updata.seq,
866 lgd.lgd_rpc_err, lgd.lgd_gss_err);