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. */
251 init_client_list(void)
253 TAILQ_INIT(&clnt_list);
254 /* Eventually plan to grow/shrink poll array: */
255 pollsize = FD_ALLOC_BLOCK;
256 pollarray = calloc(pollsize, sizeof(struct pollfd));
260 * This is run after a DNOTIFY signal, and should clear up any
261 * directories that are no longer around, and re-scan any existing
262 * directories, since the DNOTIFY could have been in there.
265 update_old_clients(struct dirent **namelist, int size)
267 struct clnt_info *clp;
271 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
273 for (i=0; i < size; i++) {
274 if (!strcmp(clp->dirname, namelist[i]->d_name)) {
280 printerr(2, "destroying client %s\n", clp->dirname);
281 saveprev = clp->list.tqe_prev;
282 TAILQ_REMOVE(&clnt_list, clp, list);
287 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
288 if (!process_clnt_dir_files(clp))
289 insert_clnt_poll(clp);
293 /* Search for a client by directory name, return 1 if found, 0 otherwise */
295 find_client(char *dirname)
297 struct clnt_info *clp;
299 for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
300 if (!strcmp(clp->dirname, dirname))
305 /* Used to read (and re-read) list of clients, set up poll array. */
307 update_client_list(void)
309 char lustre_dir[PATH_MAX];
310 struct dirent lustre_dirent = { .d_name = "lustre" };
311 struct dirent *namelist[1];
315 if (chdir(pipefs_dir) < 0) {
316 printerr(0, "ERROR: can't chdir to %s: %s\n",
317 pipefs_dir, strerror(errno));
321 snprintf(lustre_dir, sizeof(lustre_dir), "%s/%s", pipefs_dir, "lustre");
322 if (stat(lustre_dir, &statbuf) == 0) {
323 namelist[0] = &lustre_dirent;
325 printerr(2, "re-processing lustre directory\n");
329 printerr(2, "lustre directory not exist\n");
332 update_old_clients(namelist, j);
333 for (i=0; i < j; i++) {
334 if (i < FD_ALLOC_BLOCK && !find_client(namelist[i]->d_name))
335 process_clnt_dir(namelist[i]->d_name);
342 /* Context creation response. */
343 struct lustre_gss_init_res {
344 gss_buffer_desc gr_ctx; /* context handle */
345 unsigned int gr_major; /* major status */
346 unsigned int gr_minor; /* minor status */
347 unsigned int gr_win; /* sequence window */
348 gss_buffer_desc gr_token; /* token */
351 struct lustre_gss_data {
353 int lgd_lustre_svc; /* mds/oss */
354 int lgd_uid; /* uid */
355 char *lgd_uuid; /* client device uuid */
356 gss_name_t lgd_name; /* service name */
358 gss_OID lgd_mech; /* mech OID */
359 unsigned int lgd_req_flags; /* request flags */
360 gss_cred_id_t lgd_cred; /* credential */
361 gss_ctx_id_t lgd_ctx; /* session context */
362 gss_buffer_desc lgd_rmt_ctx; /* remote handle of context */
363 uint32_t lgd_seq_win; /* sequence window */
370 do_downcall(int k5_fd, struct lgssd_upcall_data *updata,
371 struct lustre_gss_data *lgd, gss_buffer_desc *context_token)
373 char *buf = NULL, *p = NULL, *end = NULL;
374 unsigned int timeout = 0; /* XXX decide on a reasonable value */
375 unsigned int buf_size = 0;
377 printerr(2, "doing downcall\n");
378 buf_size = sizeof(updata->seq) + sizeof(timeout) +
379 sizeof(lgd->lgd_seq_win) +
380 sizeof(lgd->lgd_rmt_ctx.length) + lgd->lgd_rmt_ctx.length +
381 sizeof(context_token->length) + context_token->length;
382 p = buf = malloc(buf_size);
383 end = buf + buf_size;
385 if (WRITE_BYTES(&p, end, updata->seq)) goto out_err;
386 /* Not setting any timeout for now: */
387 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
388 if (WRITE_BYTES(&p, end, lgd->lgd_seq_win)) goto out_err;
389 if (write_buffer(&p, end, &lgd->lgd_rmt_ctx)) goto out_err;
390 if (write_buffer(&p, end, context_token)) goto out_err;
392 lgssd_mutex_get(lgssd_mutex_downcall);
393 if (write(k5_fd, buf, p - buf) < p - buf) {
394 lgssd_mutex_put(lgssd_mutex_downcall);
397 lgssd_mutex_put(lgssd_mutex_downcall);
403 printerr(0, "ERROR: Failed to write downcall!\n");
408 do_error_downcall(int k5_fd, uint32_t seq, int rpc_err, int gss_err)
411 char *p = buf, *end = buf + 1024;
412 unsigned int timeout = 0;
415 printerr(1, "doing error downcall\n");
417 if (WRITE_BYTES(&p, end, seq)) goto out_err;
418 if (WRITE_BYTES(&p, end, timeout)) goto out_err;
419 /* use seq_win = 0 to indicate an error: */
420 if (WRITE_BYTES(&p, end, zero)) goto out_err;
421 if (WRITE_BYTES(&p, end, rpc_err)) goto out_err;
422 if (WRITE_BYTES(&p, end, gss_err)) goto out_err;
424 lgssd_mutex_get(lgssd_mutex_downcall);
425 if (write(k5_fd, buf, p - buf) < p - buf) {
426 lgssd_mutex_put(lgssd_mutex_downcall);
429 lgssd_mutex_put(lgssd_mutex_downcall);
432 printerr(0, "Failed to write error downcall!\n");
437 int do_negotiation(struct lustre_gss_data *lgd,
438 gss_buffer_desc *gss_token,
439 struct lustre_gss_init_res *gr,
442 struct lgssd_ioctl_param param;
450 pw = getpwuid(lgd->lgd_uid);
452 printerr(0, "no uid %u in local user database\n",
457 param.version = GSSD_INTERFACE_VERSION_V1;
458 param.uuid = lgd->lgd_uuid;
459 param.lustre_svc = lgd->lgd_lustre_svc;
460 param.uid = lgd->lgd_uid;
461 param.gid = pw->pw_gid;
462 param.send_token_size = gss_token->length;
463 param.send_token = (char *) gss_token->value;
464 param.reply_buf_size = sizeof(outbuf);
465 param.reply_buf = outbuf;
467 if (cfs_get_param_paths(&path, "sptlrpc/gss/init_channel") != 0)
470 fd = open(path.gl_pathv[0], O_RDWR);
472 printerr(0, "can't open file %s\n", path.gl_pathv[0]);
477 rc = write(fd, ¶m, sizeof(param));
478 if (rc != sizeof(param)) {
479 printerr(0, "lustre ioctl err: %d\n", strerror(errno));
484 printerr(0, "status: %d (%s)\n",
485 param.status, strerror((int)param.status));
486 if (param.status == -ETIMEDOUT) {
487 /* kernel return -ETIMEDOUT means the rpc timedout,
488 * we should notify the caller to reinitiate the
489 * gss negotiation, by return -ERESTART
491 lgd->lgd_rpc_err = -ERESTART;
492 lgd->lgd_gss_err = 0;
494 lgd->lgd_rpc_err = param.status;
495 lgd->lgd_gss_err = 0;
500 p = (unsigned int *)outbuf;
505 gr->gr_ctx.length = *p++;
506 gr->gr_ctx.value = malloc(gr->gr_ctx.length);
507 memcpy(gr->gr_ctx.value, p, gr->gr_ctx.length);
508 p += (((gr->gr_ctx.length + 3) & ~3) / 4);
510 gr->gr_token.length = *p++;
511 gr->gr_token.value = malloc(gr->gr_token.length);
512 memcpy(gr->gr_token.value, p, gr->gr_token.length);
513 p += (((gr->gr_token.length + 3) & ~3) / 4);
515 printerr(2, "do_negotiation: receive handle len %d, token len %d\n",
516 gr->gr_ctx.length, gr->gr_token.length);
521 cfs_free_param_data(&path);
526 int gssd_refresh_lgd(struct lustre_gss_data *lgd)
528 struct lustre_gss_init_res gr;
529 gss_buffer_desc *recv_tokenp, send_token;
530 OM_uint32 maj_stat, min_stat, call_stat, ret_flags;
532 /* GSS context establishment loop. */
533 memset(&gr, 0, sizeof(gr));
534 recv_tokenp = GSS_C_NO_BUFFER;
537 /* print the token we just received */
538 if (recv_tokenp != GSS_C_NO_BUFFER) {
539 printerr(3, "The received token length %d\n",
540 recv_tokenp->length);
541 print_hexl(3, recv_tokenp->value, recv_tokenp->length);
544 maj_stat = gss_init_sec_context(&min_stat,
553 NULL, /* used mech */
556 NULL); /* time rec */
558 if (recv_tokenp != GSS_C_NO_BUFFER) {
559 gss_release_buffer(&min_stat, &gr.gr_token);
560 recv_tokenp = GSS_C_NO_BUFFER;
562 if (maj_stat != GSS_S_COMPLETE &&
563 maj_stat != GSS_S_CONTINUE_NEEDED) {
564 pgsserr("gss_init_sec_context", maj_stat, min_stat,
568 if (send_token.length != 0) {
569 memset(&gr, 0, sizeof(gr));
571 /* print the token we are about to send */
572 printerr(3, "token being sent length %d\n",
574 print_hexl(3, send_token.value, send_token.length);
576 call_stat = do_negotiation(lgd, &send_token, &gr, 0);
577 gss_release_buffer(&min_stat, &send_token);
579 if (call_stat != 0 ||
580 (gr.gr_major != GSS_S_COMPLETE &&
581 gr.gr_major != GSS_S_CONTINUE_NEEDED)) {
582 printerr(0, "call stat %d, major stat 0x%x\n",
583 (int)call_stat, gr.gr_major);
587 if (gr.gr_ctx.length != 0) {
588 if (lgd->lgd_rmt_ctx.value)
589 gss_release_buffer(&min_stat,
591 lgd->lgd_rmt_ctx = gr.gr_ctx;
593 if (gr.gr_token.length != 0) {
594 if (maj_stat != GSS_S_CONTINUE_NEEDED)
596 recv_tokenp = &gr.gr_token;
600 /* GSS_S_COMPLETE => check gss header verifier,
601 * usually checked in gss_validate
603 if (maj_stat == GSS_S_COMPLETE) {
604 lgd->lgd_established = 1;
605 lgd->lgd_seq_win = gr.gr_win;
609 /* End context negotiation loop. */
610 if (!lgd->lgd_established) {
611 if (gr.gr_token.length != 0)
612 gss_release_buffer(&min_stat, &gr.gr_token);
614 printerr(0, "context negotiation failed\n");
618 printerr(2, "successfully refreshed lgd\n");
623 int gssd_create_lgd(struct clnt_info *clp,
624 struct lustre_gss_data *lgd,
625 struct lgssd_upcall_data *updata,
628 gss_buffer_desc sname;
629 OM_uint32 maj_stat, min_stat;
632 lgd->lgd_established = 0;
633 lgd->lgd_lustre_svc = updata->svc;
634 lgd->lgd_uid = updata->uid;
635 lgd->lgd_uuid = updata->obd;
639 lgd->lgd_mech = (gss_OID) &krb5oid;
640 lgd->lgd_req_flags = GSS_C_MUTUAL_FLAG;
643 lgd->lgd_mech = (gss_OID) &spkm3oid;
644 /* XXX sec.req_flags = GSS_C_ANON_FLAG;
645 * Need a way to switch....
647 lgd->lgd_req_flags = GSS_C_MUTUAL_FLAG;
650 printerr(0, "Invalid authentication type (%d)\n", authtype);
654 lgd->lgd_cred = GSS_C_NO_CREDENTIAL;
655 lgd->lgd_ctx = GSS_C_NO_CONTEXT;
656 lgd->lgd_rmt_ctx = (gss_buffer_desc) GSS_C_EMPTY_BUFFER;
657 lgd->lgd_seq_win = 0;
659 sname.value = clp->servicename;
660 sname.length = strlen(clp->servicename);
662 maj_stat = gss_import_name(&min_stat, &sname,
663 (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
665 if (maj_stat != GSS_S_COMPLETE) {
666 pgsserr(0, maj_stat, min_stat, lgd->lgd_mech);
670 retval = gssd_refresh_lgd(lgd);
672 if (lgd->lgd_name != GSS_C_NO_NAME)
673 gss_release_name(&min_stat, &lgd->lgd_name);
675 if (lgd->lgd_cred != GSS_C_NO_CREDENTIAL)
676 gss_release_cred(&min_stat, &lgd->lgd_cred);
683 void gssd_free_lgd(struct lustre_gss_data *lgd)
685 gss_buffer_t token = GSS_C_NO_BUFFER;
686 OM_uint32 maj_stat, min_stat;
688 if (lgd->lgd_ctx == GSS_C_NO_CONTEXT)
691 maj_stat = gss_delete_sec_context(&min_stat, &lgd->lgd_ctx, token);
695 int construct_service_name(struct clnt_info *clp,
696 struct lgssd_upcall_data *ud)
698 const int buflen = 256;
701 if (clp->servicename) {
702 free(clp->servicename);
703 clp->servicename = NULL;
706 if (lnet_nid2hostname(ud->nid, name, buflen))
709 clp->servicename = malloc(32 + strlen(name));
710 if (!clp->servicename) {
711 printerr(0, "can't alloc memory\n");
714 sprintf(clp->servicename, "%s@%s",
715 ud->svc == LUSTRE_GSS_SVC_MDS ?
716 GSSD_SERVICE_MDS : GSSD_SERVICE_OSS,
718 printerr(2, "constructed servicename: %s\n", clp->servicename);
723 * this code uses the userland rpcsec gss library to create a krb5
724 * context on behalf of the kernel
727 handle_krb5_upcall(struct clnt_info *clp)
730 gss_buffer_desc token = { 0, NULL };
731 struct lgssd_upcall_data updata;
732 struct lustre_gss_data lgd;
733 char **credlist = NULL;
737 printerr(2, "handling krb5 upcall\n");
739 memset(&lgd, 0, sizeof(lgd));
740 lgd.lgd_rpc_err = -EPERM; /* default error code */
742 read_rc = read(clp->krb5_fd, &updata, sizeof(updata));
744 printerr(0, "WARNING: failed reading from krb5 "
745 "upcall pipe: %s\n", strerror(errno));
747 } else if (read_rc != sizeof(updata)) {
748 printerr(0, "upcall data mismatch: length %d, expect %d\n",
749 read_rc, sizeof(updata));
751 /* the sequence number must be the first field. if read >= 4
752 * bytes then we know at least sequence is fine, try to send
753 * error notification nicely.
756 do_error_downcall(clp->krb5_fd, updata.seq, -EPERM, 0);
760 /* FIXME temporary fix, do this before fork.
761 * in case of errors could have memory leak!!!
763 if (updata.uid == 0) {
764 if (gssd_get_krb5_machine_cred_list(&credlist)) {
765 printerr(0, "ERROR: Failed to obtain machine "
767 do_error_downcall(clp->krb5_fd, updata.seq, -EPERM, 0);
772 /* fork child process */
775 printerr(0, "can't fork: %s\n", strerror(errno));
776 do_error_downcall(clp->krb5_fd, updata.seq, -EPERM, 0);
778 } else if (pid > 0) {
779 printerr(2, "forked child process: %d\n", pid);
783 printerr(1, "krb5 upcall: seq %u, uid %u, svc %u, nid 0x%llx, obd %s\n",
784 updata.seq, updata.uid, updata.svc, updata.nid, updata.obd);
786 if (updata.svc != LUSTRE_GSS_SVC_MDS &&
787 updata.svc != LUSTRE_GSS_SVC_OSS) {
788 printerr(0, "invalid svc %d\n", updata.svc);
789 lgd.lgd_rpc_err = -EPROTO;
790 goto out_return_error;
792 updata.obd[sizeof(updata.obd)-1] = '\0';
794 if (construct_service_name(clp, &updata)) {
795 printerr(0, "failed to construct service name\n");
796 goto out_return_error;
799 if (updata.uid == 0) {
803 * Get a list of credential cache names and try each
804 * of them until one works or we've tried them all
807 if (gssd_get_krb5_machine_cred_list(&credlist)) {
808 printerr(0, "ERROR: Failed to obtain machine "
809 "credentials for %s\n", clp->servicename);
810 goto out_return_error;
813 for (ccname = credlist; ccname && *ccname; ccname++) {
814 gssd_setup_krb5_machine_gss_ccache(*ccname);
815 if ((gssd_create_lgd(clp, &lgd, &updata,
816 AUTHTYPE_KRB5)) == 0) {
821 printerr(2, "WARNING: Failed to create krb5 context "
822 "for user with uid %d with credentials "
823 "cache %s for service %s\n",
824 updata.uid, *ccname, clp->servicename);
826 gssd_free_krb5_machine_cred_list(credlist);
828 printerr(0, "ERROR: Failed to create krb5 context "
829 "for user with uid %d with any "
830 "credentials cache for service %s\n",
831 updata.uid, clp->servicename);
832 goto out_return_error;
836 /* Tell krb5 gss which credentials cache to use */
837 gssd_setup_krb5_user_gss_ccache(updata.uid, clp->servicename);
839 if ((gssd_create_lgd(clp, &lgd, &updata, AUTHTYPE_KRB5)) != 0) {
840 printerr(0, "WARNING: Failed to create krb5 context "
841 "for user with uid %d for service %s\n",
842 updata.uid, clp->servicename);
843 goto out_return_error;
847 if (serialize_context_for_kernel(lgd.lgd_ctx, &token, &krb5oid)) {
848 printerr(0, "WARNING: Failed to serialize krb5 context for "
849 "user with uid %d for service %s\n",
850 updata.uid, clp->servicename);
851 goto out_return_error;
854 printerr(1, "refreshed: %u@%s for %s\n",
855 updata.uid, updata.obd, clp->servicename);
856 do_downcall(clp->krb5_fd, &updata, &lgd, &token);
863 exit(0); /* i'm child process */
866 do_error_downcall(clp->krb5_fd, updata.seq,
867 lgd.lgd_rpc_err, lgd.lgd_gss_err);