1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
5 * Authors: Doug Rabson <dfr@rabson.org>
6 * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/param.h>
31 #include <sys/stat.h>
32 #include <sys/linker.h>
33 #include <sys/module.h>
34 #include <sys/queue.h>
35 #include <sys/socket.h>
36 #include <sys/sysctl.h>
37 #include <sys/syslog.h>
38 #include <ctype.h>
39 #include <dirent.h>
40 #include <err.h>
41 #include <errno.h>
42 #ifndef WITHOUT_KERBEROS
43 #include <krb5.h>
44 #endif
45 #include <netdb.h>
46 #include <pwd.h>
47 #include <signal.h>
48 #include <stdarg.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
53 #include <arpa/inet.h>
54 #include <netinet/in.h>
55 #include <gssapi/gssapi.h>
56 #include <rpc/rpc.h>
57 #include <rpc/rpc_com.h>
58
59 #include "gssd.h"
60
61 #ifndef _PATH_GSS_MECH
62 #define _PATH_GSS_MECH "/etc/gss/mech"
63 #endif
64 #define GSSD_CREDENTIAL_CACHE_FILE "/tmp/krb5cc_gssd"
65
66 struct gss_resource {
67 LIST_ENTRY(gss_resource) gr_link;
68 uint64_t gr_id; /* identifier exported to kernel */
69 void* gr_res; /* GSS-API resource pointer */
70 };
71 LIST_HEAD(gss_resource_list, gss_resource) gss_resources;
72 int gss_resource_count;
73 uint32_t gss_next_id;
74 uint32_t gss_start_time;
75 int debug_level;
76 static char ccfile_dirlist[PATH_MAX + 1], ccfile_substring[NAME_MAX + 1];
77 static char pref_realm[1024];
78 static int verbose;
79 static int hostbased_initiator_cred;
80 #ifndef WITHOUT_KERBEROS
81 /* 1.2.752.43.13.14 */
82 static gss_OID_desc gss_krb5_set_allowable_enctypes_x_desc =
83 {6, (void *) "\x2a\x85\x70\x2b\x0d\x0e"};
84 static gss_OID GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X =
85 &gss_krb5_set_allowable_enctypes_x_desc;
86 static gss_OID_desc gss_krb5_mech_oid_x_desc =
87 {9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
88 static gss_OID GSS_KRB5_MECH_OID_X =
89 &gss_krb5_mech_oid_x_desc;
90 #endif
91
92 static void gssd_load_mech(void);
93 static int find_ccache_file(const char *, uid_t, char *);
94 static int is_a_valid_tgt_cache(const char *, uid_t, int *, time_t *);
95 static void gssd_verbose_out(const char *, ...);
96 #ifndef WITHOUT_KERBEROS
97 static krb5_error_code gssd_get_cc_from_keytab(const char *);
98 static OM_uint32 gssd_get_user_cred(OM_uint32 *, uid_t, gss_cred_id_t *);
99 #endif
100 void gssd_terminate(int);
101
102 extern void gssd_1(struct svc_req *rqstp, SVCXPRT *transp);
103
104 int
main(int argc,char ** argv)105 main(int argc, char **argv)
106 {
107 /*
108 * We provide an RPC service on a Netlink socket. The kernel's GSS API
109 * code will multicast its calls, we will listen to them, receive them,
110 * process them and reply.
111 */
112 int oldmask, ch, debug, jailed;
113 SVCXPRT *xprt;
114 size_t jailed_size;
115
116 /*
117 * Initialize the credential cache file name substring and the
118 * search directory list.
119 */
120 strlcpy(ccfile_substring, "krb5cc_", sizeof(ccfile_substring));
121 ccfile_dirlist[0] = '\0';
122 pref_realm[0] = '\0';
123 debug = 0;
124 verbose = 0;
125 while ((ch = getopt(argc, argv, "dhvs:c:r:")) != -1) {
126 switch (ch) {
127 case 'd':
128 debug_level++;
129 break;
130 case 'h':
131 #ifndef WITHOUT_KERBEROS
132 /*
133 * Enable use of a host based initiator credential
134 * in the default keytab file.
135 */
136 hostbased_initiator_cred = 1;
137 #else
138 errx(1, "This option not available when built"
139 " without MK_KERBEROS\n");
140 #endif
141 break;
142 case 'v':
143 verbose = 1;
144 break;
145 case 's':
146 #ifndef WITHOUT_KERBEROS
147 /*
148 * Set the directory search list. This enables use of
149 * find_ccache_file() to search the directories for a
150 * suitable credentials cache file.
151 */
152 strlcpy(ccfile_dirlist, optarg, sizeof(ccfile_dirlist));
153 #else
154 errx(1, "This option not available when built"
155 " without MK_KERBEROS\n");
156 #endif
157 break;
158 case 'c':
159 /*
160 * Specify a non-default credential cache file
161 * substring.
162 */
163 strlcpy(ccfile_substring, optarg,
164 sizeof(ccfile_substring));
165 break;
166 case 'r':
167 /*
168 * Set the preferred realm for the credential cache tgt.
169 */
170 strlcpy(pref_realm, optarg, sizeof(pref_realm));
171 break;
172 default:
173 fprintf(stderr,
174 "usage: %s [-d] [-s dir-list] [-c file-substring]"
175 " [-r preferred-realm]\n", argv[0]);
176 exit(1);
177 break;
178 }
179 }
180
181 gssd_load_mech();
182
183 if (!debug_level) {
184 if (daemon(0, 0) != 0)
185 err(1, "Can't daemonize");
186 signal(SIGINT, SIG_IGN);
187 signal(SIGQUIT, SIG_IGN);
188 signal(SIGHUP, SIG_IGN);
189 }
190 signal(SIGTERM, gssd_terminate);
191 signal(SIGPIPE, gssd_terminate);
192
193 if ((xprt = svc_nl_create("kgss")) == NULL) {
194 if (debug_level == 0) {
195 syslog(LOG_ERR,
196 "Can't create transport for local gssd socket");
197 exit(1);
198 }
199 err(1, "Can't create transport for local gssd socket");
200 }
201 if (!svc_reg(xprt, GSSD, GSSDVERS, gssd_1, NULL)) {
202 if (debug_level == 0) {
203 syslog(LOG_ERR,
204 "Can't register service for local gssd socket");
205 exit(1);
206 }
207 err(1, "Can't register service for local gssd socket");
208 }
209
210 LIST_INIT(&gss_resources);
211 gss_next_id = 1;
212 gss_start_time = time(0);
213 svc_run();
214
215 return (0);
216 }
217
218 static void
gssd_load_mech(void)219 gssd_load_mech(void)
220 {
221 FILE *fp;
222 char buf[256];
223 char *p;
224 char *name, *oid, *lib, *kobj;
225
226 fp = fopen(_PATH_GSS_MECH, "r");
227 if (!fp)
228 return;
229
230 while (fgets(buf, sizeof(buf), fp)) {
231 if (*buf == '#')
232 continue;
233 p = buf;
234 name = strsep(&p, "\t\n ");
235 if (p) while (isspace(*p)) p++;
236 oid = strsep(&p, "\t\n ");
237 if (p) while (isspace(*p)) p++;
238 lib = strsep(&p, "\t\n ");
239 if (p) while (isspace(*p)) p++;
240 kobj = strsep(&p, "\t\n ");
241 if (!name || !oid || !lib || !kobj)
242 continue;
243
244 if (strcmp(kobj, "-")) {
245 /*
246 * Attempt to load the kernel module if its
247 * not already present.
248 */
249 if (modfind(kobj) < 0) {
250 if (kldload(kobj) < 0) {
251 fprintf(stderr,
252 "%s: can't find or load kernel module %s for %s\n",
253 getprogname(), kobj, name);
254 }
255 }
256 }
257 }
258 fclose(fp);
259 }
260
261 static void *
gssd_find_resource(uint64_t id)262 gssd_find_resource(uint64_t id)
263 {
264 struct gss_resource *gr;
265
266 if (!id)
267 return (NULL);
268
269 LIST_FOREACH(gr, &gss_resources, gr_link)
270 if (gr->gr_id == id)
271 return (gr->gr_res);
272
273 return (NULL);
274 }
275
276 static uint64_t
gssd_make_resource(void * res)277 gssd_make_resource(void *res)
278 {
279 struct gss_resource *gr;
280
281 if (!res)
282 return (0);
283
284 gr = malloc(sizeof(struct gss_resource));
285 if (!gr)
286 return (0);
287 gr->gr_id = (gss_next_id++) + ((uint64_t) gss_start_time << 32);
288 gr->gr_res = res;
289 LIST_INSERT_HEAD(&gss_resources, gr, gr_link);
290 gss_resource_count++;
291 if (debug_level > 1)
292 printf("%d resources allocated\n", gss_resource_count);
293
294 return (gr->gr_id);
295 }
296
297 static void
gssd_delete_resource(uint64_t id)298 gssd_delete_resource(uint64_t id)
299 {
300 struct gss_resource *gr;
301
302 LIST_FOREACH(gr, &gss_resources, gr_link) {
303 if (gr->gr_id == id) {
304 LIST_REMOVE(gr, gr_link);
305 free(gr);
306 gss_resource_count--;
307 if (debug_level > 1)
308 printf("%d resources allocated\n",
309 gss_resource_count);
310 return;
311 }
312 }
313 }
314
315 static void
gssd_verbose_out(const char * fmt,...)316 gssd_verbose_out(const char *fmt, ...)
317 {
318 va_list ap;
319
320 if (verbose != 0) {
321 va_start(ap, fmt);
322 if (debug_level == 0)
323 vsyslog(LOG_INFO | LOG_DAEMON, fmt, ap);
324 else
325 vfprintf(stderr, fmt, ap);
326 va_end(ap);
327 }
328 }
329
330 bool_t
gssd_null_1_svc(void * argp,void * result,struct svc_req * rqstp)331 gssd_null_1_svc(void *argp, void *result, struct svc_req *rqstp)
332 {
333
334 gssd_verbose_out("gssd_null: done\n");
335 return (TRUE);
336 }
337
338 bool_t
gssd_init_sec_context_1_svc(init_sec_context_args * argp,init_sec_context_res * result,struct svc_req * rqstp)339 gssd_init_sec_context_1_svc(init_sec_context_args *argp, init_sec_context_res *result, struct svc_req *rqstp)
340 {
341 gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
342 gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
343 gss_name_t name = GSS_C_NO_NAME;
344 char ccname[PATH_MAX + 5 + 1], *cp, *cp2;
345 int gotone, gotcred;
346 OM_uint32 min_stat;
347 #ifndef WITHOUT_KERBEROS
348 gss_buffer_desc principal_desc;
349 char enctype[sizeof(uint32_t)];
350 int key_enctype;
351 OM_uint32 maj_stat;
352 #endif
353
354 memset(result, 0, sizeof(*result));
355 if (hostbased_initiator_cred != 0 && argp->cred != 0 &&
356 argp->uid == 0) {
357 /*
358 * These credentials are for a host based initiator name
359 * in a keytab file, which should now have credentials
360 * in /tmp/krb5cc_gssd, because gss_acquire_cred() did
361 * the equivalent of "kinit -k".
362 */
363 snprintf(ccname, sizeof(ccname), "FILE:%s",
364 GSSD_CREDENTIAL_CACHE_FILE);
365 } else if (ccfile_dirlist[0] != '\0' && argp->cred == 0) {
366 /*
367 * For the "-s" case and no credentials provided as an
368 * argument, search the directory list for an appropriate
369 * credential cache file. If the search fails, return failure.
370 */
371 gotone = 0;
372 cp = ccfile_dirlist;
373 do {
374 cp2 = strchr(cp, ':');
375 if (cp2 != NULL)
376 *cp2 = '\0';
377 gotone = find_ccache_file(cp, argp->uid, ccname);
378 if (gotone != 0)
379 break;
380 if (cp2 != NULL)
381 *cp2++ = ':';
382 cp = cp2;
383 } while (cp != NULL && *cp != '\0');
384 if (gotone == 0) {
385 result->major_status = GSS_S_CREDENTIALS_EXPIRED;
386 gssd_verbose_out("gssd_init_sec_context: -s no"
387 " credential cache file found for uid=%d\n",
388 (int)argp->uid);
389 return (TRUE);
390 }
391 } else {
392 /*
393 * If there wasn't a "-s" option or the credentials have
394 * been provided as an argument, do it the old way.
395 * When credentials are provided, the uid should be root.
396 */
397 if (argp->cred != 0 && argp->uid != 0) {
398 if (debug_level == 0)
399 syslog(LOG_ERR, "gss_init_sec_context:"
400 " cred for non-root");
401 else
402 fprintf(stderr, "gss_init_sec_context:"
403 " cred for non-root\n");
404 }
405 snprintf(ccname, sizeof(ccname), "FILE:/tmp/krb5cc_%d",
406 (int) argp->uid);
407 }
408 setenv("KRB5CCNAME", ccname, TRUE);
409
410 if (argp->cred) {
411 cred = gssd_find_resource(argp->cred);
412 if (!cred) {
413 result->major_status = GSS_S_CREDENTIALS_EXPIRED;
414 gssd_verbose_out("gssd_init_sec_context: cred"
415 " resource not found\n");
416 return (TRUE);
417 }
418 }
419 if (argp->ctx) {
420 ctx = gssd_find_resource(argp->ctx);
421 if (!ctx) {
422 result->major_status = GSS_S_CONTEXT_EXPIRED;
423 gssd_verbose_out("gssd_init_sec_context: context"
424 " resource not found\n");
425 return (TRUE);
426 }
427 }
428 if (argp->name) {
429 name = gssd_find_resource(argp->name);
430 if (!name) {
431 result->major_status = GSS_S_BAD_NAME;
432 gssd_verbose_out("gssd_init_sec_context: name"
433 " resource not found\n");
434 return (TRUE);
435 }
436 }
437 gotcred = 0;
438
439 result->major_status = gss_init_sec_context(&result->minor_status,
440 cred, &ctx, name, argp->mech_type,
441 argp->req_flags, argp->time_req, argp->input_chan_bindings,
442 &argp->input_token, &result->actual_mech_type,
443 &result->output_token, &result->ret_flags, &result->time_rec);
444 gssd_verbose_out("gssd_init_sec_context: done major=0x%x minor=%d"
445 " uid=%d\n", (unsigned int)result->major_status,
446 (int)result->minor_status, (int)argp->uid);
447 if (gotcred != 0)
448 gss_release_cred(&min_stat, &cred);
449
450 if (result->major_status == GSS_S_COMPLETE
451 || result->major_status == GSS_S_CONTINUE_NEEDED) {
452 if (argp->ctx)
453 result->ctx = argp->ctx;
454 else
455 result->ctx = gssd_make_resource(ctx);
456 }
457
458 return (TRUE);
459 }
460
461 bool_t
gssd_accept_sec_context_1_svc(accept_sec_context_args * argp,accept_sec_context_res * result,struct svc_req * rqstp)462 gssd_accept_sec_context_1_svc(accept_sec_context_args *argp, accept_sec_context_res *result, struct svc_req *rqstp)
463 {
464 gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
465 gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
466 gss_name_t src_name;
467 gss_cred_id_t delegated_cred_handle;
468
469 memset(result, 0, sizeof(*result));
470 if (argp->ctx) {
471 ctx = gssd_find_resource(argp->ctx);
472 if (!ctx) {
473 result->major_status = GSS_S_CONTEXT_EXPIRED;
474 gssd_verbose_out("gssd_accept_sec_context: ctx"
475 " resource not found\n");
476 return (TRUE);
477 }
478 }
479 if (argp->cred) {
480 cred = gssd_find_resource(argp->cred);
481 if (!cred) {
482 result->major_status = GSS_S_CREDENTIALS_EXPIRED;
483 gssd_verbose_out("gssd_accept_sec_context: cred"
484 " resource not found\n");
485 return (TRUE);
486 }
487 }
488
489 memset(result, 0, sizeof(*result));
490 result->major_status = gss_accept_sec_context(&result->minor_status,
491 &ctx, cred, &argp->input_token, argp->input_chan_bindings,
492 &src_name, &result->mech_type, &result->output_token,
493 &result->ret_flags, &result->time_rec,
494 &delegated_cred_handle);
495 gssd_verbose_out("gssd_accept_sec_context: done major=0x%x minor=%d\n",
496 (unsigned int)result->major_status, (int)result->minor_status);
497
498 if (result->major_status == GSS_S_COMPLETE
499 || result->major_status == GSS_S_CONTINUE_NEEDED) {
500 if (argp->ctx)
501 result->ctx = argp->ctx;
502 else
503 result->ctx = gssd_make_resource(ctx);
504 result->src_name = gssd_make_resource(src_name);
505 result->delegated_cred_handle =
506 gssd_make_resource(delegated_cred_handle);
507 }
508
509 return (TRUE);
510 }
511
512 bool_t
gssd_delete_sec_context_1_svc(delete_sec_context_args * argp,delete_sec_context_res * result,struct svc_req * rqstp)513 gssd_delete_sec_context_1_svc(delete_sec_context_args *argp, delete_sec_context_res *result, struct svc_req *rqstp)
514 {
515 gss_ctx_id_t ctx = gssd_find_resource(argp->ctx);
516
517 if (ctx) {
518 result->major_status = gss_delete_sec_context(
519 &result->minor_status, &ctx, &result->output_token);
520 gssd_delete_resource(argp->ctx);
521 } else {
522 result->major_status = GSS_S_COMPLETE;
523 result->minor_status = 0;
524 }
525 gssd_verbose_out("gssd_delete_sec_context: done major=0x%x minor=%d\n",
526 (unsigned int)result->major_status, (int)result->minor_status);
527
528 return (TRUE);
529 }
530
531 bool_t
gssd_export_sec_context_1_svc(export_sec_context_args * argp,export_sec_context_res * result,struct svc_req * rqstp)532 gssd_export_sec_context_1_svc(export_sec_context_args *argp, export_sec_context_res *result, struct svc_req *rqstp)
533 {
534 gss_ctx_id_t ctx = gssd_find_resource(argp->ctx);
535
536 if (ctx) {
537 result->major_status = gss_export_sec_context(
538 &result->minor_status, &ctx,
539 &result->interprocess_token);
540 result->format = KGSS_HEIMDAL_1_1;
541 gssd_delete_resource(argp->ctx);
542 } else {
543 result->major_status = GSS_S_FAILURE;
544 result->minor_status = 0;
545 result->interprocess_token.length = 0;
546 result->interprocess_token.value = NULL;
547 }
548 gssd_verbose_out("gssd_export_sec_context: done major=0x%x minor=%d\n",
549 (unsigned int)result->major_status, (int)result->minor_status);
550
551 return (TRUE);
552 }
553
554 bool_t
gssd_import_name_1_svc(import_name_args * argp,import_name_res * result,struct svc_req * rqstp)555 gssd_import_name_1_svc(import_name_args *argp, import_name_res *result, struct svc_req *rqstp)
556 {
557 gss_name_t name;
558
559 result->major_status = gss_import_name(&result->minor_status,
560 &argp->input_name_buffer, argp->input_name_type, &name);
561 gssd_verbose_out("gssd_import_name: done major=0x%x minor=%d\n",
562 (unsigned int)result->major_status, (int)result->minor_status);
563
564 if (result->major_status == GSS_S_COMPLETE)
565 result->output_name = gssd_make_resource(name);
566 else
567 result->output_name = 0;
568
569 return (TRUE);
570 }
571
572 /*
573 * If the name is a numeric IP host address, do a DNS lookup on it and
574 * return the DNS name in a malloc'd string.
575 */
576 static char *
gssd_conv_ip_to_dns(int len,char * name)577 gssd_conv_ip_to_dns(int len, char *name)
578 {
579 struct sockaddr_in sin;
580 struct sockaddr_in6 sin6;
581 char *retcp;
582
583 retcp = NULL;
584 if (len > 0) {
585 retcp = mem_alloc(NI_MAXHOST);
586 memcpy(retcp, name, len);
587 retcp[len] = '\0';
588 if (inet_pton(AF_INET, retcp, &sin.sin_addr) != 0) {
589 sin.sin_family = AF_INET;
590 sin.sin_len = sizeof(sin);
591 sin.sin_port = 0;
592 if (getnameinfo((struct sockaddr *)&sin,
593 sizeof(sin), retcp, NI_MAXHOST,
594 NULL, 0, NI_NAMEREQD) != 0) {
595 mem_free(retcp, NI_MAXHOST);
596 return (NULL);
597 }
598 } else if (inet_pton(AF_INET6, retcp, &sin6.sin6_addr) != 0) {
599 sin6.sin6_family = AF_INET6;
600 sin6.sin6_len = sizeof(sin6);
601 sin6.sin6_port = 0;
602 if (getnameinfo((struct sockaddr *)&sin6,
603 sizeof(sin6), retcp, NI_MAXHOST,
604 NULL, 0, NI_NAMEREQD) != 0) {
605 mem_free(retcp, NI_MAXHOST);
606 return (NULL);
607 }
608 } else {
609 mem_free(retcp, NI_MAXHOST);
610 return (NULL);
611 }
612 gssd_verbose_out("gssd_conv_ip_to_dns: %s\n", retcp);
613 }
614 return (retcp);
615 }
616
617 bool_t
gssd_canonicalize_name_1_svc(canonicalize_name_args * argp,canonicalize_name_res * result,struct svc_req * rqstp)618 gssd_canonicalize_name_1_svc(canonicalize_name_args *argp, canonicalize_name_res *result, struct svc_req *rqstp)
619 {
620 gss_name_t name = gssd_find_resource(argp->input_name);
621 gss_name_t output_name;
622
623 memset(result, 0, sizeof(*result));
624 if (!name) {
625 result->major_status = GSS_S_BAD_NAME;
626 return (TRUE);
627 }
628
629 result->major_status = gss_canonicalize_name(&result->minor_status,
630 name, argp->mech_type, &output_name);
631 gssd_verbose_out("gssd_canonicalize_name: done major=0x%x minor=%d\n",
632 (unsigned int)result->major_status, (int)result->minor_status);
633
634 if (result->major_status == GSS_S_COMPLETE)
635 result->output_name = gssd_make_resource(output_name);
636 else
637 result->output_name = 0;
638
639 return (TRUE);
640 }
641
642 bool_t
gssd_export_name_1_svc(export_name_args * argp,export_name_res * result,struct svc_req * rqstp)643 gssd_export_name_1_svc(export_name_args *argp, export_name_res *result, struct svc_req *rqstp)
644 {
645 gss_name_t name = gssd_find_resource(argp->input_name);
646
647 memset(result, 0, sizeof(*result));
648 if (!name) {
649 result->major_status = GSS_S_BAD_NAME;
650 gssd_verbose_out("gssd_export_name: name resource not found\n");
651 return (TRUE);
652 }
653
654 result->major_status = gss_export_name(&result->minor_status,
655 name, &result->exported_name);
656 gssd_verbose_out("gssd_export_name: done major=0x%x minor=%d\n",
657 (unsigned int)result->major_status, (int)result->minor_status);
658
659 return (TRUE);
660 }
661
662 bool_t
gssd_release_name_1_svc(release_name_args * argp,release_name_res * result,struct svc_req * rqstp)663 gssd_release_name_1_svc(release_name_args *argp, release_name_res *result, struct svc_req *rqstp)
664 {
665 gss_name_t name = gssd_find_resource(argp->input_name);
666
667 if (name) {
668 result->major_status = gss_release_name(&result->minor_status,
669 &name);
670 gssd_delete_resource(argp->input_name);
671 } else {
672 result->major_status = GSS_S_COMPLETE;
673 result->minor_status = 0;
674 }
675 gssd_verbose_out("gssd_release_name: done major=0x%x minor=%d\n",
676 (unsigned int)result->major_status, (int)result->minor_status);
677
678 return (TRUE);
679 }
680
681 bool_t
gssd_pname_to_uid_1_svc(pname_to_uid_args * argp,pname_to_uid_res * result,struct svc_req * rqstp)682 gssd_pname_to_uid_1_svc(pname_to_uid_args *argp, pname_to_uid_res *result, struct svc_req *rqstp)
683 {
684 gss_name_t name = gssd_find_resource(argp->pname);
685 uid_t uid;
686 char buf[1024], *bufp;
687 struct passwd pwd, *pw;
688 size_t buflen;
689 int error;
690 static size_t buflen_hint = 1024;
691
692 memset(result, 0, sizeof(*result));
693 if (name) {
694 result->major_status =
695 gss_pname_to_uid(&result->minor_status,
696 name, argp->mech, &uid);
697 if (result->major_status == GSS_S_COMPLETE) {
698 result->uid = uid;
699 buflen = buflen_hint;
700 for (;;) {
701 pw = NULL;
702 bufp = buf;
703 if (buflen > sizeof(buf))
704 bufp = malloc(buflen);
705 if (bufp == NULL)
706 break;
707 error = getpwuid_r(uid, &pwd, bufp, buflen,
708 &pw);
709 if (error != ERANGE)
710 break;
711 if (buflen > sizeof(buf))
712 free(bufp);
713 buflen += 1024;
714 if (buflen > buflen_hint)
715 buflen_hint = buflen;
716 }
717 if (pw) {
718 int len = NGROUPS;
719 int groups[NGROUPS];
720 result->gid = pw->pw_gid;
721 getgrouplist(pw->pw_name, pw->pw_gid,
722 groups, &len);
723 result->gidlist.gidlist_len = len;
724 result->gidlist.gidlist_val =
725 mem_alloc(len * sizeof(int));
726 memcpy(result->gidlist.gidlist_val, groups,
727 len * sizeof(int));
728 gssd_verbose_out("gssd_pname_to_uid: mapped"
729 " to uid=%d, gid=%d\n", (int)result->uid,
730 (int)result->gid);
731 } else {
732 result->gid = 65534;
733 result->gidlist.gidlist_len = 0;
734 result->gidlist.gidlist_val = NULL;
735 gssd_verbose_out("gssd_pname_to_uid: mapped"
736 " to uid=%d, but no groups\n",
737 (int)result->uid);
738 }
739 if (bufp != NULL && buflen > sizeof(buf))
740 free(bufp);
741 } else
742 gssd_verbose_out("gssd_pname_to_uid: failed major=0x%x"
743 " minor=%d\n", (unsigned int)result->major_status,
744 (int)result->minor_status);
745 } else {
746 result->major_status = GSS_S_BAD_NAME;
747 result->minor_status = 0;
748 gssd_verbose_out("gssd_pname_to_uid: no name\n");
749 }
750
751 return (TRUE);
752 }
753
754 bool_t
gssd_acquire_cred_1_svc(acquire_cred_args * argp,acquire_cred_res * result,struct svc_req * rqstp)755 gssd_acquire_cred_1_svc(acquire_cred_args *argp, acquire_cred_res *result, struct svc_req *rqstp)
756 {
757 gss_name_t desired_name = GSS_C_NO_NAME;
758 gss_cred_id_t cred;
759 char ccname[PATH_MAX + 5 + 1], *cp, *cp2;
760 int gotone;
761 #ifndef WITHOUT_KERBEROS
762 gss_buffer_desc namebuf;
763 uint32_t minstat;
764 krb5_error_code kret;
765 #endif
766
767 memset(result, 0, sizeof(*result));
768 if (argp->desired_name) {
769 desired_name = gssd_find_resource(argp->desired_name);
770 if (!desired_name) {
771 result->major_status = GSS_S_BAD_NAME;
772 gssd_verbose_out("gssd_acquire_cred: no desired name"
773 " found\n");
774 return (TRUE);
775 }
776 }
777
778 #ifndef WITHOUT_KERBEROS
779 if (hostbased_initiator_cred != 0 && argp->desired_name != 0 &&
780 argp->uid == 0 && argp->cred_usage == GSS_C_INITIATE) {
781 /* This is a host based initiator name in the keytab file. */
782 snprintf(ccname, sizeof(ccname), "FILE:%s",
783 GSSD_CREDENTIAL_CACHE_FILE);
784 setenv("KRB5CCNAME", ccname, TRUE);
785 result->major_status = gss_display_name(&result->minor_status,
786 desired_name, &namebuf, NULL);
787 gssd_verbose_out("gssd_acquire_cred: desired name for host "
788 "based initiator cred major=0x%x minor=%d\n",
789 (unsigned int)result->major_status,
790 (int)result->minor_status);
791 if (result->major_status != GSS_S_COMPLETE)
792 return (TRUE);
793 if (namebuf.length > PATH_MAX + 5) {
794 result->minor_status = 0;
795 result->major_status = GSS_S_FAILURE;
796 return (TRUE);
797 }
798 memcpy(ccname, namebuf.value, namebuf.length);
799 ccname[namebuf.length] = '\0';
800 if ((cp = strchr(ccname, '@')) != NULL)
801 *cp = '/';
802 kret = gssd_get_cc_from_keytab(ccname);
803 gssd_verbose_out("gssd_acquire_cred: using keytab entry for "
804 "%s, kerberos ret=%d\n", ccname, (int)kret);
805 gss_release_buffer(&minstat, &namebuf);
806 if (kret != 0) {
807 result->minor_status = kret;
808 result->major_status = GSS_S_FAILURE;
809 return (TRUE);
810 }
811 } else
812 #endif /* !WITHOUT_KERBEROS */
813 if (ccfile_dirlist[0] != '\0' && argp->desired_name == 0) {
814 /*
815 * For the "-s" case and no name provided as an
816 * argument, search the directory list for an appropriate
817 * credential cache file. If the search fails, return failure.
818 */
819 gotone = 0;
820 cp = ccfile_dirlist;
821 do {
822 cp2 = strchr(cp, ':');
823 if (cp2 != NULL)
824 *cp2 = '\0';
825 gotone = find_ccache_file(cp, argp->uid, ccname);
826 if (gotone != 0)
827 break;
828 if (cp2 != NULL)
829 *cp2++ = ':';
830 cp = cp2;
831 } while (cp != NULL && *cp != '\0');
832 if (gotone == 0) {
833 result->major_status = GSS_S_CREDENTIALS_EXPIRED;
834 gssd_verbose_out("gssd_acquire_cred: no cred cache"
835 " file found\n");
836 return (TRUE);
837 }
838 setenv("KRB5CCNAME", ccname, TRUE);
839 } else {
840 /*
841 * If there wasn't a "-s" option or the name has
842 * been provided as an argument, do it the old way.
843 * When a name is provided, it will normally exist in the
844 * default keytab file and the uid will be root.
845 */
846 if (argp->desired_name != 0 && argp->uid != 0) {
847 if (debug_level == 0)
848 syslog(LOG_ERR, "gss_acquire_cred:"
849 " principal_name for non-root");
850 else
851 fprintf(stderr, "gss_acquire_cred:"
852 " principal_name for non-root\n");
853 }
854 snprintf(ccname, sizeof(ccname), "FILE:/tmp/krb5cc_%d",
855 (int) argp->uid);
856 setenv("KRB5CCNAME", ccname, TRUE);
857 }
858
859 result->major_status = gss_acquire_cred(&result->minor_status,
860 desired_name, argp->time_req, argp->desired_mechs,
861 argp->cred_usage, &cred, &result->actual_mechs, &result->time_rec);
862 gssd_verbose_out("gssd_acquire_cred: done major=0x%x minor=%d\n",
863 (unsigned int)result->major_status, (int)result->minor_status);
864
865 if (result->major_status == GSS_S_COMPLETE)
866 result->output_cred = gssd_make_resource(cred);
867 else
868 result->output_cred = 0;
869
870 return (TRUE);
871 }
872
873 bool_t
gssd_set_cred_option_1_svc(set_cred_option_args * argp,set_cred_option_res * result,struct svc_req * rqstp)874 gssd_set_cred_option_1_svc(set_cred_option_args *argp, set_cred_option_res *result, struct svc_req *rqstp)
875 {
876 gss_cred_id_t cred = gssd_find_resource(argp->cred);
877
878 memset(result, 0, sizeof(*result));
879 if (!cred) {
880 result->major_status = GSS_S_CREDENTIALS_EXPIRED;
881 gssd_verbose_out("gssd_set_cred: no credentials\n");
882 return (TRUE);
883 }
884
885 result->major_status = gss_set_cred_option(&result->minor_status,
886 &cred, argp->option_name, &argp->option_value);
887 gssd_verbose_out("gssd_set_cred: done major=0x%x minor=%d\n",
888 (unsigned int)result->major_status, (int)result->minor_status);
889
890 return (TRUE);
891 }
892
893 bool_t
gssd_release_cred_1_svc(release_cred_args * argp,release_cred_res * result,struct svc_req * rqstp)894 gssd_release_cred_1_svc(release_cred_args *argp, release_cred_res *result, struct svc_req *rqstp)
895 {
896 gss_cred_id_t cred = gssd_find_resource(argp->cred);
897
898 if (cred) {
899 result->major_status = gss_release_cred(&result->minor_status,
900 &cred);
901 gssd_delete_resource(argp->cred);
902 } else {
903 result->major_status = GSS_S_COMPLETE;
904 result->minor_status = 0;
905 }
906 gssd_verbose_out("gssd_release_cred: done major=0x%x minor=%d\n",
907 (unsigned int)result->major_status, (int)result->minor_status);
908
909 return (TRUE);
910 }
911
912 bool_t
gssd_display_status_1_svc(display_status_args * argp,display_status_res * result,struct svc_req * rqstp)913 gssd_display_status_1_svc(display_status_args *argp, display_status_res *result, struct svc_req *rqstp)
914 {
915
916 result->message_context = argp->message_context;
917 result->major_status = gss_display_status(&result->minor_status,
918 argp->status_value, argp->status_type, argp->mech_type,
919 &result->message_context, &result->status_string);
920 gssd_verbose_out("gssd_display_status: done major=0x%x minor=%d\n",
921 (unsigned int)result->major_status, (int)result->minor_status);
922
923 return (TRUE);
924 }
925
926 bool_t
gssd_ip_to_dns_1_svc(ip_to_dns_args * argp,ip_to_dns_res * result,struct svc_req * rqstp)927 gssd_ip_to_dns_1_svc(ip_to_dns_args *argp, ip_to_dns_res *result, struct svc_req *rqstp)
928 {
929 char *host;
930
931 memset(result, 0, sizeof(*result));
932 /* Check to see if the name is actually an IP address. */
933 host = gssd_conv_ip_to_dns(argp->ip_addr.ip_addr_len,
934 argp->ip_addr.ip_addr_val);
935 if (host != NULL) {
936 result->major_status = GSS_S_COMPLETE;
937 result->dns_name.dns_name_len = strlen(host);
938 result->dns_name.dns_name_val = host;
939 return (TRUE);
940 }
941 result->major_status = GSS_S_FAILURE;
942 return (TRUE);
943 }
944
945 int
gssd_1_freeresult(SVCXPRT * transp,xdrproc_t xdr_result,caddr_t result)946 gssd_1_freeresult(SVCXPRT *transp, xdrproc_t xdr_result, caddr_t result)
947 {
948 /*
949 * We don't use XDR to free the results - anything which was
950 * allocated came from GSS-API. We use xdr_result to figure
951 * out what to do.
952 */
953 OM_uint32 junk;
954
955 if (xdr_result == (xdrproc_t) xdr_init_sec_context_res) {
956 init_sec_context_res *p = (init_sec_context_res *) result;
957 gss_release_buffer(&junk, &p->output_token);
958 } else if (xdr_result == (xdrproc_t) xdr_accept_sec_context_res) {
959 accept_sec_context_res *p = (accept_sec_context_res *) result;
960 gss_release_buffer(&junk, &p->output_token);
961 } else if (xdr_result == (xdrproc_t) xdr_delete_sec_context_res) {
962 delete_sec_context_res *p = (delete_sec_context_res *) result;
963 gss_release_buffer(&junk, &p->output_token);
964 } else if (xdr_result == (xdrproc_t) xdr_export_sec_context_res) {
965 export_sec_context_res *p = (export_sec_context_res *) result;
966 if (p->interprocess_token.length)
967 memset(p->interprocess_token.value, 0,
968 p->interprocess_token.length);
969 gss_release_buffer(&junk, &p->interprocess_token);
970 } else if (xdr_result == (xdrproc_t) xdr_export_name_res) {
971 export_name_res *p = (export_name_res *) result;
972 gss_release_buffer(&junk, &p->exported_name);
973 } else if (xdr_result == (xdrproc_t) xdr_acquire_cred_res) {
974 acquire_cred_res *p = (acquire_cred_res *) result;
975 gss_release_oid_set(&junk, &p->actual_mechs);
976 } else if (xdr_result == (xdrproc_t) xdr_pname_to_uid_res) {
977 pname_to_uid_res *p = (pname_to_uid_res *) result;
978 if (p->gidlist.gidlist_val)
979 free(p->gidlist.gidlist_val);
980 } else if (xdr_result == (xdrproc_t) xdr_display_status_res) {
981 display_status_res *p = (display_status_res *) result;
982 gss_release_buffer(&junk, &p->status_string);
983 }
984
985 return (TRUE);
986 }
987
988 /*
989 * Search a directory for the most likely candidate to be used as the
990 * credential cache for a uid. If successful, return 1 and fill the
991 * file's path id into "rpath". Otherwise, return 0.
992 */
993 static int
find_ccache_file(const char * dirpath,uid_t uid,char * rpath)994 find_ccache_file(const char *dirpath, uid_t uid, char *rpath)
995 {
996 DIR *dirp;
997 struct dirent *dp;
998 struct stat sb;
999 time_t exptime, oexptime;
1000 int gotone, len, rating, orating;
1001 char namepath[PATH_MAX + 5 + 1];
1002 char retpath[PATH_MAX + 5 + 1];
1003
1004 dirp = opendir(dirpath);
1005 if (dirp == NULL)
1006 return (0);
1007 gotone = 0;
1008 orating = 0;
1009 oexptime = 0;
1010 while ((dp = readdir(dirp)) != NULL) {
1011 len = snprintf(namepath, sizeof(namepath), "%s/%s", dirpath,
1012 dp->d_name);
1013 if (len < sizeof(namepath) &&
1014 (hostbased_initiator_cred == 0 || strcmp(namepath,
1015 GSSD_CREDENTIAL_CACHE_FILE) != 0) &&
1016 strstr(dp->d_name, ccfile_substring) != NULL &&
1017 lstat(namepath, &sb) >= 0 &&
1018 sb.st_uid == uid &&
1019 S_ISREG(sb.st_mode)) {
1020 len = snprintf(namepath, sizeof(namepath), "FILE:%s/%s",
1021 dirpath, dp->d_name);
1022 if (len < sizeof(namepath) &&
1023 is_a_valid_tgt_cache(namepath, uid, &rating,
1024 &exptime) != 0) {
1025 if (gotone == 0 || rating > orating ||
1026 (rating == orating && exptime > oexptime)) {
1027 orating = rating;
1028 oexptime = exptime;
1029 strcpy(retpath, namepath);
1030 gotone = 1;
1031 }
1032 }
1033 }
1034 }
1035 closedir(dirp);
1036 if (gotone != 0) {
1037 strcpy(rpath, retpath);
1038 return (1);
1039 }
1040 return (0);
1041 }
1042
1043 /*
1044 * Try to determine if the file is a valid tgt cache file.
1045 * Check that the file has a valid tgt for a principal.
1046 * If it does, return 1, otherwise return 0.
1047 * It also returns a "rating" and the expiry time for the TGT, when found.
1048 * This "rating" is higher based on heuristics that make it more
1049 * likely to be the correct credential cache file to use. It can
1050 * be used by the caller, along with expiry time, to select from
1051 * multiple credential cache files.
1052 */
1053 static int
is_a_valid_tgt_cache(const char * filepath,uid_t uid,int * retrating,time_t * retexptime)1054 is_a_valid_tgt_cache(const char *filepath, uid_t uid, int *retrating,
1055 time_t *retexptime)
1056 {
1057 #ifndef WITHOUT_KERBEROS
1058 krb5_context context;
1059 krb5_principal princ;
1060 krb5_ccache ccache;
1061 krb5_error_code retval;
1062 krb5_cc_cursor curse;
1063 krb5_creds krbcred;
1064 int gotone, orating, rating, ret;
1065 struct passwd *pw;
1066 char *cp, *cp2, *pname;
1067 time_t exptime;
1068
1069 /* Find a likely name for the uid principal. */
1070 pw = getpwuid(uid);
1071
1072 /*
1073 * Do a bunch of krb5 library stuff to try and determine if
1074 * this file is a credentials cache with an appropriate TGT
1075 * in it.
1076 */
1077 retval = krb5_init_context(&context);
1078 if (retval != 0)
1079 return (0);
1080 retval = krb5_cc_resolve(context, filepath, &ccache);
1081 if (retval != 0) {
1082 krb5_free_context(context);
1083 return (0);
1084 }
1085 ret = 0;
1086 orating = 0;
1087 exptime = 0;
1088 retval = krb5_cc_start_seq_get(context, ccache, &curse);
1089 if (retval == 0) {
1090 while ((retval = krb5_cc_next_cred(context, ccache, &curse,
1091 &krbcred)) == 0) {
1092 gotone = 0;
1093 rating = 0;
1094 retval = krb5_unparse_name(context, krbcred.server,
1095 &pname);
1096 if (retval == 0) {
1097 cp = strchr(pname, '/');
1098 if (cp != NULL) {
1099 *cp++ = '\0';
1100 if (strcmp(pname, "krbtgt") == 0 &&
1101 krbcred.times.endtime > time(NULL)
1102 ) {
1103 gotone = 1;
1104 /*
1105 * Test to see if this is a
1106 * tgt for cross-realm auth.
1107 * Rate it higher, if it is not.
1108 */
1109 cp2 = strchr(cp, '@');
1110 if (cp2 != NULL) {
1111 *cp2++ = '\0';
1112 if (strcmp(cp, cp2) ==
1113 0)
1114 rating++;
1115 }
1116 }
1117 }
1118 free(pname);
1119 }
1120 if (gotone != 0) {
1121 retval = krb5_unparse_name(context,
1122 krbcred.client, &pname);
1123 if (retval == 0) {
1124 cp = strchr(pname, '@');
1125 if (cp != NULL) {
1126 *cp++ = '\0';
1127 if (pw != NULL && strcmp(pname,
1128 pw->pw_name) == 0)
1129 rating++;
1130 if (strchr(pname, '/') == NULL)
1131 rating++;
1132 if (pref_realm[0] != '\0' &&
1133 strcmp(cp, pref_realm) == 0)
1134 rating++;
1135 }
1136 }
1137 free(pname);
1138 if (rating > orating) {
1139 orating = rating;
1140 exptime = krbcred.times.endtime;
1141 } else if (rating == orating &&
1142 krbcred.times.endtime > exptime)
1143 exptime = krbcred.times.endtime;
1144 ret = 1;
1145 }
1146 krb5_free_cred_contents(context, &krbcred);
1147 }
1148 krb5_cc_end_seq_get(context, ccache, &curse);
1149 }
1150 krb5_cc_close(context, ccache);
1151 krb5_free_context(context);
1152 if (ret != 0) {
1153 *retrating = orating;
1154 *retexptime = exptime;
1155 }
1156 return (ret);
1157 #else /* WITHOUT_KERBEROS */
1158 return (0);
1159 #endif /* !WITHOUT_KERBEROS */
1160 }
1161
1162 #ifndef WITHOUT_KERBEROS
1163 /*
1164 * This function attempts to do essentially a "kinit -k" for the principal
1165 * name provided as the argument, so that there will be a TGT in the
1166 * credential cache.
1167 */
1168 static krb5_error_code
gssd_get_cc_from_keytab(const char * name)1169 gssd_get_cc_from_keytab(const char *name)
1170 {
1171 krb5_error_code ret, opt_ret, princ_ret, cc_ret, kt_ret, cred_ret;
1172 krb5_context context;
1173 krb5_principal principal;
1174 krb5_keytab kt;
1175 krb5_creds cred;
1176 krb5_get_init_creds_opt *opt;
1177 krb5_deltat start_time = 0;
1178 krb5_ccache ccache;
1179
1180 ret = krb5_init_context(&context);
1181 if (ret != 0)
1182 return (ret);
1183 opt_ret = cc_ret = kt_ret = cred_ret = 1; /* anything non-zero */
1184 princ_ret = ret = krb5_parse_name(context, name, &principal);
1185 if (ret == 0)
1186 opt_ret = ret = krb5_get_init_creds_opt_alloc(context, &opt);
1187 if (ret == 0)
1188 cc_ret = ret = krb5_cc_default(context, &ccache);
1189 if (ret == 0)
1190 ret = krb5_cc_initialize(context, ccache, principal);
1191 if (ret == 0) {
1192 krb5_get_init_creds_opt_set_default_flags(context, "gssd",
1193 krb5_principal_get_realm(context, principal), opt);
1194 kt_ret = ret = krb5_kt_default(context, &kt);
1195 }
1196 if (ret == 0)
1197 cred_ret = ret = krb5_get_init_creds_keytab(context, &cred,
1198 principal, kt, start_time, NULL, opt);
1199 if (ret == 0)
1200 ret = krb5_cc_store_cred(context, ccache, &cred);
1201 if (kt_ret == 0)
1202 krb5_kt_close(context, kt);
1203 if (cc_ret == 0)
1204 krb5_cc_close(context, ccache);
1205 if (opt_ret == 0)
1206 krb5_get_init_creds_opt_free(context, opt);
1207 if (princ_ret == 0)
1208 krb5_free_principal(context, principal);
1209 if (cred_ret == 0)
1210 krb5_free_cred_contents(context, &cred);
1211 krb5_free_context(context);
1212 return (ret);
1213 }
1214
1215 /*
1216 * Acquire a gss credential for a uid.
1217 */
1218 static OM_uint32
gssd_get_user_cred(OM_uint32 * min_statp,uid_t uid,gss_cred_id_t * credp)1219 gssd_get_user_cred(OM_uint32 *min_statp, uid_t uid, gss_cred_id_t *credp)
1220 {
1221 gss_buffer_desc principal_desc;
1222 gss_name_t name;
1223 OM_uint32 maj_stat, min_stat;
1224 gss_OID_set mechlist;
1225 struct passwd *pw;
1226
1227 pw = getpwuid(uid);
1228 if (pw == NULL) {
1229 *min_statp = 0;
1230 return (GSS_S_FAILURE);
1231 }
1232
1233 /*
1234 * The mechanism must be set to KerberosV for acquisition
1235 * of credentials to work reliably.
1236 */
1237 maj_stat = gss_create_empty_oid_set(min_statp, &mechlist);
1238 if (maj_stat != GSS_S_COMPLETE)
1239 return (maj_stat);
1240 maj_stat = gss_add_oid_set_member(min_statp, GSS_KRB5_MECH_OID_X,
1241 &mechlist);
1242 if (maj_stat != GSS_S_COMPLETE) {
1243 gss_release_oid_set(&min_stat, &mechlist);
1244 return (maj_stat);
1245 }
1246
1247 principal_desc.value = (void *)pw->pw_name;
1248 principal_desc.length = strlen(pw->pw_name);
1249 maj_stat = gss_import_name(min_statp, &principal_desc,
1250 GSS_C_NT_USER_NAME, &name);
1251 if (maj_stat != GSS_S_COMPLETE) {
1252 gss_release_oid_set(&min_stat, &mechlist);
1253 return (maj_stat);
1254 }
1255 /* Acquire the credentials. */
1256 maj_stat = gss_acquire_cred(min_statp, name, 0, mechlist,
1257 GSS_C_INITIATE, credp, NULL, NULL);
1258 gss_release_name(&min_stat, &name);
1259 gss_release_oid_set(&min_stat, &mechlist);
1260 return (maj_stat);
1261 }
1262 #endif /* !WITHOUT_KERBEROS */
1263
gssd_terminate(int sig __unused)1264 void gssd_terminate(int sig __unused)
1265 {
1266
1267 #ifndef WITHOUT_KERBEROS
1268 if (hostbased_initiator_cred != 0)
1269 unlink(GSSD_CREDENTIAL_CACHE_FILE);
1270 #endif
1271 exit(0);
1272 }
1273
1274