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