1/* 2 * Copyright (c) 2006-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23/* 24 * gssd daemon. 25 * 26 * Gssd is used to proxy requests from the kernel to set up or accept GSS 27 * security contexts. The kernel makes up calls to these routines here via 28 * mach messaging as defined by gssd_mach.defs. Launchd is used to set up 29 * a task special port in both the start up context and in the per session 30 * context. The supplied plist that launchd uses for the start up context, 31 * /System/Library/LaunchDaemons/com.apple.gssd.plist, will set the program 32 * name to /usr/sbin/gssd, and in the per user session context, found at 33 * /System/Library/LaunchAgents/com.apple.gssd.plist, launchd will set the 34 * program name to gssd-agent. By using a special task port, we can fetch 35 * a send right from the task making a secure mount call in the kernel. 36 * Launchd will own the receive right and will thus start this daemon on 37 * demand as defined in the above plists. Since the daemon is invoked in 38 * the correct context, the GSS-API will be able to obtain the appropriate 39 * credentials with gss acquire cred. 40 * 41 * This daemon will set up the context and then wait for a spell (TIMEOUT below) 42 * to service any other requests. If no requests come we simply exit and 43 * let launchd restart us if necessary on the next mount request. In this way 44 * we are not using system resources unnecessarily and we're pretty well 45 * protected from any bad consequences of any resource leaks. 46 */ 47 48#include <bsm/audit.h> 49#include <bsm/libbsm.h> 50#include <libkern/OSAtomic.h> 51#include <sys/param.h> 52#include <sys/time.h> 53#include <mach/mach.h> 54#include <mach/mach_error.h> 55#include <servers/bootstrap.h> 56#include <uuid/uuid.h> 57 58#include <bootstrap_priv.h> 59#include <asl.h> 60#include <asl_private.h> 61#include <ctype.h> 62#include <errno.h> 63#include <grp.h> 64#include <membership.h> 65#include <netdb.h> 66#include <notify.h> 67#include <pthread.h> 68#include <pwd.h> 69#include <signal.h> 70#include <stdbool.h> 71#include <stdio.h> 72#include <stdlib.h> 73#include <string.h> 74#include <unistd.h> 75#include <vproc.h> 76#ifdef VDEBUG 77#include <time.h> 78#include "/usr/local/include/vproc_priv.h" 79#endif 80 81#include <Heimdal/com_err.h> 82#include <Heimdal/krb5.h> 83#include <GSS/gssapi.h> 84#include <GSS/gssapi_krb5.h> 85#include <GSS/gssapi_ntlm.h> 86#include <GSS/gssapi_spnego.h> 87#include <GSS/gssapi_spi.h> 88 89#include "gssd.h" 90#include "gssd/gssd_mach.h" 91#include "gssd_machServer.h" 92 93mach_port_t gssd_receive_right; 94 95union MaxMsgSize { 96 union __RequestUnion__gssd_mach_subsystem req; 97 union __ReplyUnion__gssd_mach_subsystem rep; 98}; 99 100#define MAX_GSSD_MSG_SIZE (sizeof (union MaxMsgSize) + MAX_TRAILER_SIZE) 101 102 103 104 105#define APPLE_PREFIX "com.apple." /* Bootstrap name prefix */ 106#define MAXLABEL 256 /* Max bootstrap name */ 107#define MAXTHREADS 64 /* Max number of service threads */ 108#define NOBODY (uint32_t)-2 /* Default nobody user/group id */ 109#define TIMEOUT 30 /* 30 seconds and then bye. */ 110#define SHUTDOWN_TIMEOUT 2 /* timeout gets set to this after TERM signal */ 111 112#define NFS_SERVICE "nfs" 113#define NFS_SERVICE_LEN 3 114#define IS_NFS_SERVICE(s) ((strncmp((s), NFS_SERVICE, NFS_SERVICE_LEN) == 0) && \ 115 ((s)[NFS_SERVICE_LEN] == '/' || (s)[NFS_SERVICE_LEN] == '@')) 116 117krb5_enctype NFS_ENCTYPES[] = { 118 ENCTYPE_DES_CBC_CRC, 119 ENCTYPE_DES_CBC_MD5, 120 ENCTYPE_DES_CBC_MD4, 121 ENCTYPE_DES3_CBC_SHA1 122}; 123 124#define NUM_NFS_ENCTYPES ((uint32_t)(sizeof(NFS_ENCTYPES)/sizeof(krb5_enctype))) 125 126 127static uint32_t uid_to_gss_name(uint32_t *, uid_t, gss_OID, gss_name_t *); 128static char * get_next_kerb_component(char *); 129static uint32_t gss_name_to_ucred(uint32_t *, gss_name_t, uid_t *, gid_t *, uint32_t *); 130static char * lowercase(char *); 131static char * canonicalize_host(const char *, char **); 132static uint32_t str_to_svc_names(uint32_t *, const char *, gss_name_t *, uint32_t *); 133static void gssd_init(void); 134static void * receive_message(void *); 135static void new_worker_thread(void); 136static void end_worker_thread(void); 137static void compute_new_timeout(struct timespec *); 138static void * shutdown_thread(void *); 139static void disable_timeout(int); 140static void * timeout_thread(void *); 141static void vm_alloc_buffer(gss_buffer_t, uint8_t **, uint32_t *); 142static uint32_t GetSessionKey(uint32_t *, gss_OID mech, gss_ctx_id_t *, gssd_byte_buffer *, 143 mach_msg_type_number_t *); 144static uint32_t badcall(char *, uint32_t *, gssd_ctx *, gssd_cred *, uint32_t *, 145 gssd_byte_buffer *, mach_msg_type_number_t *, 146 gssd_byte_buffer *, mach_msg_type_number_t *); 147 148static time_t timeout = TIMEOUT; /* Seconds to wait before exiting */ 149static int die = 0; /* Simulate server death. Testing only */ 150static int bye = 0; /* Force clean shutdown flag. */ 151static int no_canon = 0; /* Don't canonicalize host names */ 152static int acquire_default = 0; /* Don't acquire default credentials in do_acquire_cred */ 153static int maxthreads = MAXTHREADS; /* Maximum number of service threads. */ 154static int numthreads = 0; /* Current number of service threads */ 155static int kernel_only = TRUE; /* Restricts mach_gss_lookup for kernel only */ 156static pthread_mutex_t numthreads_lock[1]; /* lock to protect above */ 157static pthread_cond_t numthreads_cv[1]; /* To signal when we're below max. */ 158static pthread_attr_t attr[1]; /* Needed to create detached threads */ 159static pthread_t timeout_thr; /* Thread sees if we've been inactive and exits */ 160static pthread_t shutdown_thr; /* Thread to handle signals */ 161 162/* Counters used in debugging for init and accept context */ 163static volatile int32_t initCnt = 0; 164static volatile int32_t initErr = 0; 165 166static volatile int32_t acceptCnt = 0; 167static volatile int32_t acceptErr = 0; 168 169uid_t NobodyUid = NOBODY; 170gid_t NobodyGid = NOBODY; 171 172char *local_host; /* our FQDN */ 173long GetPWMaxRSz; /* Storage size for password entry */ 174 175sigset_t waitset[1]; /* Signals that we wait for */ 176sigset_t contset[1]; /* Signals that we don't exit from */ 177 178/* 179 * OID table for supported mechs. This is index by the enumeration type mechtype 180 * found in gss_mach_types.h. 181 */ 182static gss_OID mechtab[] = { 183 NULL, /* Place holder for GSS_KRB5_MECHANISM */ 184 NULL, /* Place holder for GSS_SPNEGO_MECHANISM */ 185 NULL, /* Place holder for GSS_NTLM_MECHANISM */ 186 NULL, /* Place holder for GSS_IAKERB_MECHANISM */ 187 NULL 188}; 189 190 191/* 192 * Hopefully Heimdal will fix this in their library and this can go away. 193 */ 194 195#ifdef WIN2K_HACK 196static size_t 197derlen(uint8_t **dptr, uint8_t *eptr) 198{ 199 int i; 200 uint8_t *p = *dptr; 201 size_t len = 0; 202 203 if (*p & 0x80) { 204 for (i = *p & 0x7f; i > 0 && (eptr == NULL || (p < eptr)); i--) 205 len = (len << 8) + *++p; 206 } else 207 len = *p; 208 209 *dptr = p + 1; 210 211 return (len); 212} 213 214#define ADVANCE(p, l, e) do { \ 215 (p) += (l); \ 216 DEBUG(4, "Advancing %d bytes\n", (int)(l)); \ 217 if ((p) > (e)) { \ 218 DEBUG(4, "Defective p = %p e = %p\n", (p), (e)); \ 219 return (GSS_S_DEFECTIVE_TOKEN); \ 220 } \ 221 } while (0) 222 223#define CHK(p, v, e) (((p) >= (e) || *(p) != (v)) ? 0 : 1) 224 225static size_t 226encode_derlen(size_t len, size_t max, uint8_t *value) 227{ 228 size_t i; 229 size_t count, len_save = len; 230 231 if (len < 0x80) { 232 if (max > 0 && value) 233 value[0] = len; 234 return 1; 235 } 236 237 for (count = 0; len; count++) 238 len >>= 8; 239 240 len = len_save; 241 if (value && max > count) { 242 for (i = count; i > 0; i--, len >>= 8) { 243 value[i] = (len & 0xff ); 244 } 245 value[0] = (0x80 | count); 246 } 247 /* Extra octet to hold the count of length bytes */ 248 return (count + 1); 249} 250 251#define SEQUENCE 0x30 252#define CONTEXT 0xA0 253#define ENUM 0x0A 254#define OCTETSTRING 0x04 255 256/* 257 * Windows 2k is including a bogus MIC in the return token from the server 258 * which fails in the gss_init_sec_context call. The mic appears to always be 259 * another copy of the kerberos AP_REP token. Go figure. At any rate this 260 * routine takes the input token, ASN1 decodes it and if there is a bad Mic 261 * removes it and adjust the token so that it is valid again. We should move 262 * this into the kerberos library when we have enough experience that this routine 263 * covers all the w2k cases. 264 */ 265 266static uint32_t 267spnego_win2k_hack(gss_buffer_t token) 268{ 269 uint8_t *ptr, *eptr, *response, *start, *end; 270 size_t len, rlen, seqlen, seqlenbytes, negresplen, negresplenbytes, tlen; 271 272 ptr = token->value; 273 eptr = ptr + token->length; 274 275 DEBUG(3, "token value\n"); 276 HEXDUMP(e, token->value, token->length); 277 278 279 /* CHOICE [1] negTokenResp */ 280 if (!CHK(ptr, (CONTEXT | 1), eptr)) 281 return (GSS_S_DEFECTIVE_TOKEN); 282 ADVANCE(ptr, 1, eptr); 283 len = derlen(&ptr, eptr); 284 /* Sequence */ 285 if (!CHK(ptr, SEQUENCE, eptr)) 286 return (GSS_S_DEFECTIVE_TOKEN); 287 ADVANCE(ptr, 1, eptr); 288 len = derlen(&ptr, eptr); 289 /* Save start of first element in sequence [0] enum*/ 290 start = ptr; 291 if (!CHK(ptr, (CONTEXT | 0), eptr)) 292 return (GSS_S_DEFECTIVE_TOKEN); 293 ADVANCE(ptr, 1, eptr); 294 len = derlen(&ptr, eptr); 295 if (len != 3) 296 return (GSS_S_DEFECTIVE_TOKEN); 297 if (!CHK(ptr, ENUM, eptr)) 298 return (GSS_S_DEFECTIVE_TOKEN); 299 ADVANCE(ptr, 1, eptr); 300 len = derlen(&ptr, eptr); 301 if (len != 1) 302 return (GSS_S_DEFECTIVE_TOKEN); 303 if (!CHK(ptr, 0x0, eptr)) /* != ACCEPT_COMPLETE */ 304 return (GSS_S_DEFECTIVE_TOKEN); 305 ADVANCE(ptr, 1, eptr); 306 /* Get the mech type accepted */ 307 if (!CHK(ptr, (CONTEXT | 1), eptr)) 308 return (GSS_S_DEFECTIVE_TOKEN); 309 ADVANCE(ptr, 1, eptr); 310 len = derlen(&ptr, eptr); 311 /* Skip past the oid bytes -- should check for kerberos? */ 312 ADVANCE(ptr, len, eptr); 313 /* Check for the response token */ 314 if (!CHK(ptr, (CONTEXT | 2), eptr)) 315 return (GSS_S_DEFECTIVE_TOKEN); 316 ADVANCE(ptr, 1, eptr); 317 len = derlen(&ptr, eptr); 318 if (!CHK(ptr, OCTETSTRING, eptr)) 319 return (GSS_S_DEFECTIVE_TOKEN); 320 ADVANCE(ptr, 1, eptr); 321 rlen = derlen(&ptr, eptr); 322 response = ptr; 323 /* Skip rest of response token */ 324 ADVANCE(ptr, rlen, eptr); 325 if (ptr == eptr) 326 /* No mic part so nothing to do */ 327 return (GSS_S_COMPLETE); 328 end = ptr; /* Save the end of the token */ 329 /* See if we have a mechMic */ 330 if (!CHK(ptr, (CONTEXT | 3), eptr)) 331 return (GSS_S_DEFECTIVE_TOKEN); 332 ADVANCE(ptr, 1, eptr); 333 len = derlen(&ptr, eptr); 334 if (!CHK(ptr, OCTETSTRING, eptr)) 335 return (GSS_S_DEFECTIVE_TOKEN); 336 ADVANCE(ptr, 1, eptr); 337 len = derlen(&ptr, eptr); 338 if (len != rlen || ptr + rlen != eptr || memcmp(response, ptr, rlen) != 0) { 339 DEBUG(3, "Mic does not equal response %p %p %p len = %d rlen = %d\n", 340 ptr, ptr + rlen, eptr, (int)len, (int)rlen); 341 return (GSS_S_DEFECTIVE_TOKEN); 342 } 343 344 /* 345 * Ok we have a bogus mic, lets chop it off. This is the length value 346 * of the sequence in the negTokenResp 347 */ 348 seqlen = end - start; 349 350 /* Number of bytes to ecode the length */ 351 seqlenbytes = encode_derlen(seqlen, 0, 0); 352 /* 353 * Length of the sequence in the negToken response. Note we add one 354 * for the sequence tag itself 355 */ 356 negresplen = seqlen + seqlenbytes + 1; 357 negresplenbytes = encode_derlen(negresplen, 0, 0); 358 /* 359 * Total negTokenResp length 360 */ 361 tlen = negresplen + negresplenbytes + 1; /* One for the context 1 tag */ 362 /* 363 * Now we do surgery on the token, 364 */ 365 ptr = token->value; 366 *ptr++ = CONTEXT | 1; 367 encode_derlen(negresplen, negresplenbytes, ptr); 368 ptr += negresplenbytes; 369 *ptr++ = SEQUENCE; 370 encode_derlen(seqlen, seqlenbytes, ptr); 371 ptr += seqlenbytes; 372 memmove(ptr, start, seqlen); 373 token->length = tlen; 374 375 DEBUG(3, "Returning token"); 376 HEXDUMP(3, token->value, token->length); 377 378 return (GSS_S_COMPLETE); 379} 380#endif 381 382static kern_return_t 383checkin_or_register(char *service, mach_port_t *server_port) 384{ 385 kern_return_t kr; 386 387 /* 388 * Check in with launchd to get the receive right. 389 * N.B. Since we're using a task special port, if launchd 390 * does not have the receive right we can't get it. 391 * And since we should always be started by launchd 392 * this should always succeed. 393 */ 394 395 kr = bootstrap_check_in(bootstrap_port, service, server_port); 396 if (kr == BOOTSTRAP_SUCCESS) 397 return (KERN_SUCCESS); 398 399 Log("Could not checkin for receive right: %s\n", bootstrap_strerror(kr)); 400 401 /* This should never happen */ 402 403 kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, server_port); 404 if (kr != KERN_SUCCESS) { 405 Log("mach_port_allocation failed: %s\n", mach_error_string(kr)); 406 return (kr); 407 } 408 409 kr = mach_port_insert_right(mach_task_self(), *server_port, *server_port, MACH_MSG_TYPE_MAKE_SEND); 410 if (kr != KERN_SUCCESS) { 411 Log("mach_port_insert_right failed: %s\n", mach_error_string(kr)); 412 return (kr); 413 } 414 415 kr = bootstrap_register2(bootstrap_port, service, *server_port, 0); 416 if (kr != KERN_SUCCESS) { 417 Log("bootstrap_register2 failed: %s\n", mach_error_string(kr)); 418 return (kr); 419 } 420 421 return (kr); 422} 423 424static int 425uuidstr2sessioninfo(const char *uuid_str, uid_t *uid, au_asid_t *asid) 426{ 427 union { 428 uuid_t uuid; 429 struct { 430 uid_t uid; 431 au_asid_t asid; 432 } info; 433 } u; 434 435 if (uuid_parse(uuid_str, u.uuid)) 436 return (-1); 437 438 *uid = u.info.uid; 439 *asid = u.info.asid; 440 441 return (0); 442} 443 444static void 445sessioninfo2uuid(uid_t uid, au_asid_t asid, uuid_t uuid) 446{ 447 union { 448 uuid_t uuid; 449 struct { 450 uid_t uid; 451 au_asid_t asid; 452 } info; 453 } u; 454 455 uuid_clear(u.uuid); 456 u.info.uid = uid; 457 u.info.asid = asid; 458 uuid_copy(uuid, u.uuid); 459} 460 461static int 462join_session(au_asid_t asid, __unused const char *instance) 463{ 464 int err; 465 au_asid_t asid2; 466 mach_port_name_t session_port; 467 468 err = audit_session_port(asid, &session_port); 469 if (err) { 470 Log("Could not get audit session port for %d: %s", asid, strerror(errno)); 471 /* %%% we should see if we can unregister the sub-job? */ 472 return (-1); 473 } 474 475 asid2 = audit_session_join(session_port); 476 mach_port_deallocate(current_task(), session_port); 477 478 if (asid2 != asid) { 479 Log("Joined session %d but wound up in session %d", asid, asid2); 480 return (-1); 481 } 482 return (0); 483} 484 485/* 486 * Return TRUE if the audit session id is valid, FALSE otherwise 487 */ 488static int 489check_session(au_asid_t asid) 490{ 491 int err; 492 mach_port_name_t session_port; 493 494 if (asid == AU_DEFAUDITSID || asid == AU_ASSIGN_ASID) { 495 Info("Received special audit session id of %d", asid); 496 return (FALSE); 497 } 498 499 err = audit_session_port(asid, &session_port); 500 if (err) { 501 Log("Audit session id %d is in invalid: %s", asid, strerror(errno)); 502 return (FALSE); 503 } 504 505 mach_port_deallocate(current_task(), session_port); 506 return (TRUE); 507} 508 509au_asid_t my_asid = AU_DEFAUDITSID; 510 511static void 512set_identity(void) 513{ 514 const char *instance = getenv("LaunchInstanceID"); 515 auditinfo_addr_t ai; 516 au_asid_t asid = -1; 517 uid_t euid = geteuid(); 518 519 if (getaudit_addr(&ai, sizeof(auditinfo_addr_t))) 520 Debug("getaudit failed: %s", strerror(errno)); 521 else 522 asid = ai.ai_asid; 523 524 Debug("asid = %d euid = %d, instance = %s", ai.ai_asid, 525 euid, instance ? instance : "not set"); 526 if (instance && geteuid() == 0) { 527 uid_t uid; 528 529 if (uuidstr2sessioninfo(instance, &uid, &asid)) 530 Log("Could not parse LaunchInstanceID: %s", instance); 531 else { 532 if (join_session(asid, instance) == 0) 533 setuid(uid); 534 } 535 } 536 537 /* Get my actual audit session id for checkout */ 538 if (getaudit_addr(&ai, sizeof(auditinfo_addr_t))) 539 Log("getaudit failed: %s", strerror(errno)); 540 else 541 my_asid = ai.ai_asid; 542 if (asid != my_asid || getuid() != euid) 543 Info("My identity changed to asid = %d auid = %d uid = %d", ai.ai_asid, ai.ai_auid, getuid()); 544} 545 546static int 547check_audit(audit_token_t atok, int kernonly) 548{ 549 uid_t uid, euid, ruid; 550 gid_t egid, rgid; 551 pid_t pid; 552 au_asid_t asid; 553 int ok; 554 static audit_token_t kern_audit_token = KERNEL_AUDIT_TOKEN_VALUE; 555 556 audit_token_to_au32(atok, &uid, &euid, &egid, &ruid, &rgid, &pid, &asid, NULL); 557 DEBUG(9, "Received audit token: uid = %d, euid = %d, egid = %d, ruid = %d rgid = %d, pid = %d, asid = %d atid = %d", 558 uid, euid, egid, ruid, rgid, pid, asid, atok.val[7]); 559 560 ok = (memcmp(&atok, &kern_audit_token, sizeof (audit_token_t)) == 0); 561 if (!ok && !kernonly) { 562 Debug("gssd asid = %d gssd uid = %d remote pid = %d remote asid = %d remote euid = %d", 563 my_asid, getuid(), pid, asid, euid); 564 ok = (asid == my_asid || (euid && euid == getuid())); 565 } 566 if (!ok) 567 Log("Process %d in session %d as user %d was denied by gssd[%d] for session %d as user %d", pid, asid, euid, getpid(), my_asid, getuid()); 568 569 return (ok); 570} 571 572/* 573 * This daemon is to be started by launchd, as such it follows the following 574 * launchd rules: 575 * We don't: 576 * call daemon(3) 577 * call fork and having the parent process exit 578 * change uids or gids. 579 * set up the current working directory or chroot. 580 * set the session id 581 * change stdio to /dev/null. 582 * call setrusage(2) 583 * call setpriority(2) 584 * Ignore SIGTERM. 585 * We are launched on demand 586 * and we catch SIGTERM to exit cleanly. 587 * 588 * In practice daemonizing in the classic unix sense would probably be ok 589 * since we get invoke by traffic on a task_special_port, but we will play 590 * by the rules, its even easier to boot. 591 */ 592 593char label_buf[MAXLABEL]; 594char *bname = label_buf; 595 596int main(int argc, char *argv[]) 597{ 598 kern_return_t kr; 599 int error; 600 int ch; 601 int debug_opt = 0; 602 603 /* If launchd is redirecting these to files they'll be blocked */ 604 /* buffered. Probably not what you want. */ 605 setlinebuf(stdout); 606 setlinebuf(stderr); 607 608 /* Figure out our bootstrap name based on what we are called. */ 609 setprogname(argv[0]); 610 strlcpy(label_buf, APPLE_PREFIX, sizeof(label_buf)); 611 strlcat(label_buf, getprogname(), sizeof(label_buf)); 612 613 while ((ch = getopt(argc, argv, "b:Cdhm:n:t:DT")) != -1) { 614 switch (ch) { 615 case 'C': 616 no_canon = 1; 617 break; 618 case 'd': /* Debug */ 619 debug_opt++; 620 break; 621 case 'm': 622 maxthreads = atoi(optarg); 623 if (maxthreads < 1) 624 maxthreads = MAXTHREADS; 625 break; 626 case 'b': 627 case 'n': 628 bname = optarg; 629 break; 630 case 't': 631 timeout = atoi(optarg); 632 if (timeout < 10) 633 timeout = TIMEOUT; 634 break; 635 case 'D': 636 acquire_default = 1; 637 break; 638 case 'T': 639 kernel_only = FALSE; 640 break; 641 case 'h': 642 /* FALLTHROUGH */ 643 default: 644 Log("usage: %s [-Cdht] [-m threads] " 645 "[-n bootstrap name]\n", argv[0]); 646 exit(EXIT_FAILURE); 647 } 648 } 649 650/* 651 * Currently we don't do anything else with argc, argv. 652 * 653 * argc -= optind; 654 * argv += optind; 655 */ 656 kr = checkin_or_register(bname, &gssd_receive_right); 657 if (kr != KERN_SUCCESS) 658 exit(EXIT_FAILURE); 659 660 sigemptyset(waitset); 661 sigaddset(waitset, SIGQUIT); 662 if (!traced() && !in_foreground(2)) 663 sigaddset(waitset, SIGINT); 664 sigaddset(waitset, SIGHUP); 665 sigaddset(waitset, SIGUSR1); 666 sigaddset(waitset, SIGUSR2); 667 *contset = *waitset; 668 sigaddset(waitset, SIGTERM); 669 pthread_sigmask(SIG_BLOCK, waitset, NULL); 670 671 (void) pthread_mutex_init(numthreads_lock, NULL); 672 (void) pthread_cond_init(numthreads_cv, NULL); 673 (void) pthread_attr_init(attr); 674 (void) pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED); 675 676 /* Allow set_debug_level to disable our timeout */ 677 set_debug_level_init(disable_timeout); 678 /* Set initial debug_level */ 679 set_debug_level(debug_opt); 680 /* Check to see if the master asl filter is set */ 681 set_debug_level(-1); 682 683 /* Set our session and uid if needed */ 684 set_identity(); 685 686 687 gssd_init(); 688 689 /* Create signal handling thread */ 690 error = pthread_create(&shutdown_thr, attr, shutdown_thread, NULL); 691 if (error) { 692 Log("unable to create shutdown thread: %s", strerror(error)); 693 exit(EXIT_FAILURE); 694 } 695 696 /* Create time out thread */ 697 error = pthread_create(&timeout_thr, NULL, timeout_thread, NULL); 698 if (error) { 699 Log("unable to create time out thread: %s", strerror(error)); 700 exit(EXIT_FAILURE); 701 } 702 703#ifdef VDEBUG 704 { 705 time_t now; 706 if (debug == 2) 707 vproc_transaction_begin(NULL); 708 709 now = time(NULL); 710 DEBUG(3, "starting %s with transaction count = %lu, " 711 "standby count = %lu\n", ctime(&now), 712 (unsigned long)_vproc_transaction_count(), 713 (unsigned long)_vproc_standby_count()); 714 } 715#endif 716 717 /* 718 * Kick off a thread to wait for a message. Shamelessly stolen from 719 * automountd. 720 */ 721 new_worker_thread(); 722 723 /* Wait for time out */ 724 pthread_join(timeout_thr, NULL); 725 726 DEBUG(3, "Time out exiting. Number of threads is %d\n", numthreads); 727 728 pthread_attr_destroy(attr); 729 730 DEBUG(2, "Total %d init_sec_context errors out of %d calls\n", initErr, initCnt); 731 DEBUG(2, "Total %d accept_sec_context errors out of %d calls\n", acceptErr, acceptCnt); 732 733#ifdef VDEBUG 734 DEBUG(3, "exiting with transaction count = %lu, " 735 "standby count = %lu\n", 736 (unsigned long) _vproc_transaction_count(), 737 (unsigned long) _vproc_standby_count()); 738#endif 739 return (0); 740} 741 742static int 743get_local_realms(krb5_realm **realms) 744{ 745 int error; 746 krb5_context kctx; 747 748 if (realms == NULL) 749 return (FALSE); 750 *realms = NULL; 751 error = krb5_init_context(&kctx); 752 if (error) { 753 Log("Could not get kerberos context"); 754 krb5_free_context(kctx); 755 return (FALSE); 756 } 757 error = krb5_get_default_realms(kctx, realms); 758 if (error) { 759 Log("Could not get kerbose default realms"); 760 krb5_free_context(kctx); 761 return (FALSE); 762 } 763 return (TRUE); 764} 765 766static void 767free_local_realms(krb5_realm *realms) 768{ 769 int error; 770 krb5_context kctx; 771 772 if (realms == NULL) 773 return; 774 775 error = krb5_init_context(&kctx); 776 if (error) { 777 Log("Could not get kerberos context"); 778 return; 779 } 780 (void )krb5_free_host_realm(kctx, realms); 781 krb5_free_context(kctx); 782} 783 784/* 785 * Given a uid and name type convert it to a gss_name_t 786 */ 787static uint32_t 788uid_to_gss_name(uint32_t *minor, uid_t uid, gss_OID oid, gss_name_t *name) 789{ 790 char pwbuf[GetPWMaxRSz]; 791 struct passwd *pwd, pwent; 792 char *princ_str; 793 gss_buffer_desc buf_name; 794 uint32_t major; 795 size_t len; 796 size_t realmlen; 797 krb5_realm *realms = NULL; 798 krb5_realm default_realm = NULL; 799 int rc; 800 801 *minor = 0; 802 803 rc = getpwuid_r(uid, &pwent, pwbuf, sizeof(pwbuf), &pwd); 804 if (rc != 0 || pwd == NULL) 805 return (GSS_S_UNAUTHORIZED); 806 807 if (get_local_realms(&realms)) 808 default_realm = *realms; 809 810 realmlen = default_realm ? strlen(default_realm) : 0; 811 len = strlen(pwd->pw_name) + 1 + realmlen + 1; 812 len = maximum(len, 10); /* max string rep for uids */ 813 len = maximum(len, 5 + strlen(local_host) + 1 + realmlen + 1); 814 if ((princ_str = malloc(len)) == NULL) { 815 free_local_realms(realms); 816 return (GSS_S_FAILURE); 817 } 818 if (gss_oid_equal(oid, GSS_KRB5_NT_PRINCIPAL_NAME)) { 819 if (pwd->pw_uid == 0) { 820 /* use the host principal */ 821 if (default_realm) 822 snprintf(princ_str, len, 823 "host/%s@%s", local_host, default_realm); 824 else 825 snprintf(princ_str, len, "host/%s", local_host); 826 } else { 827 if (default_realm) 828 snprintf(princ_str, len, 829 "%s@%s", pwd->pw_name, default_realm); 830 else 831 snprintf(princ_str, len, "%s", pwd->pw_name); 832 } 833 } 834 else if (gss_oid_equal(oid, GSS_C_NT_USER_NAME)) 835 snprintf(princ_str, len, "%s", pwd->pw_name); 836 else if (gss_oid_equal(oid, GSS_C_NT_STRING_UID_NAME)) 837 snprintf(princ_str, len, "%d", pwd->pw_uid); 838 else if (gss_oid_equal(oid, GSS_C_NT_MACHINE_UID_NAME)) 839 memcpy(princ_str, &pwd->pw_uid, sizeof(pwd->pw_uid)); 840 else if (gss_oid_equal(oid, GSS_C_NT_HOSTBASED_SERVICE) && pwd->pw_uid == 0) 841 snprintf(princ_str, len, "host@%s", local_host); 842 else { 843 free(princ_str); 844 free_local_realms(realms); 845 return (GSS_S_FAILURE); 846 } 847 848 str_to_buf(princ_str, &buf_name); 849 850 DEBUG(2, "importing name %s\n", princ_str); 851 852 major = gss_import_name(minor, &buf_name, oid, name); 853 854 free(princ_str); 855 free_local_realms(realms); 856 857 return (major); 858} 859 860/* 861 * get_next_kerb_component. Get the next kerberos component from string. 862 */ 863static char * 864get_next_kerb_component(char *str) 865{ 866 char *s, *p; 867 868 /* 869 * Its possible to include "/" and "@" in the leading 870 * components of a kerberos principal name if they 871 * are back slashed escaped, as in, fo\/o\@@realm. 872 */ 873 874 s = str; 875 do { 876 p = strpbrk(s, "/@\\"); 877 s = (p && *p == '\\' && *(p+1)) ? p + 2 : NULL; 878 } while (s); 879 880 return (p); 881} 882 883 884/* 885 * getucred: Given a user name return the corresponding uid and gid list. 886 * Note the first gid in the list is the principal (passwd entry) gid. 887 * 888 * Return: True on success of False on failure. Note on failure, *uid and *gid 889 * are set to nobody and *ngroups is set to 1. 890 */ 891static bool 892getucred(const char *uname, uid_t *uid, gid_t *gids, uint32_t *ngroups) 893{ 894 struct passwd *pwd, pwent; 895 char pwdbuf[GetPWMaxRSz]; 896 *uid = NobodyUid; 897 *gids = NobodyGid; 898 *ngroups = 1; 899 900 (void) getpwnam_r(uname, &pwent, pwdbuf, sizeof(pwdbuf), &pwd); 901 if (pwd) { 902 *uid = pwd->pw_uid; 903 *ngroups = NGROUPS_MAX; 904 if (getgrouplist(uname, pwd->pw_gid, 905 (int *)gids, (int *)ngroups) == -1) { 906 /* Best we can do is just return the principal gid */ 907 *gids = pwd->pw_gid; 908 *ngroups = 1; 909 } 910 return (true); 911 } 912 return (false); 913} 914 915/* 916 * Given a gss_name_t convert it to a local uid. We use an optional list 917 * of kerberos realm names to try if name can't be resolve to a passwd 918 * entry directly after converting it to a display name. 919 */ 920static uint32_t 921gss_name_to_ucred_1(uint32_t *minor, gss_name_t name, 922 uid_t *uid, gid_t *gids, uint32_t *ngroups) 923{ 924 uint32_t major; 925 char *name_str = NULL; 926 gss_buffer_desc buf; 927 gss_OID oid = GSS_C_NO_OID; 928 char **rlm, *this_realm, *uname; 929 bool gotname; 930 krb5_realm *realms = NULL; 931 932 *minor = 0; 933 934 /* 935 * Convert name to text string and fetch the name type. 936 */ 937 major = gss_display_name(minor, name, &buf, &oid); 938 if (major != GSS_S_COMPLETE) 939 return (major); 940 941 name_str = buf_to_str(&buf); 942 if (name_str == NULL) 943 return (GSS_S_FAILURE); 944 945 uname = name_str; 946 947 /* 948 * See if we get lucky and the string version of the name 949 * can be found. 950 */ 951 952 if ((gotname = getucred(uname, uid, gids, ngroups))) 953 goto out; 954 955 if (gss_oid_equal(oid, GSS_KRB5_NT_PRINCIPAL_NAME)) { 956 /* 957 * If we failed the above lookup and we're a kerberos name 958 * and if the realm of the name is one of our local realms, 959 * try looking up the first component and see if its a user we 960 * know. We ignore any instance part here, i.e., we assume 961 * user@realm and user/instance@realm are the same for all 962 * instances. 963 */ 964 this_realm = strrchr(name_str, '@'); 965 if (this_realm == NULL) 966 goto out; 967 this_realm++; 968 if (!get_local_realms(&realms)) 969 goto out; 970 for(rlm = realms; rlm && *rlm; rlm++) { 971 if (strncmp(this_realm, *rlm, buf.length) == 0) { 972 char *p; 973 974 p = get_next_kerb_component(name_str); 975 if (p) 976 *p = '\0'; 977 978 gotname = getucred(uname, uid, gids, ngroups); 979 goto out; 980 } 981 } 982 } 983out: 984 if (!gotname) 985 Log("Directory Service could not map %s to unix credentials. Directory Service problem?\n", uname); 986 else 987 Info("Directory Service mapped %s to uid %d", uname, *uid); 988 989 free(uname); 990 free_local_realms(realms); 991 992 return (uint32_t)(gotname ? GSS_S_COMPLETE : GSS_S_FAILURE); 993} 994 995/* 996 * Given a gss_name_t convert it to a local uid. 997 */ 998static uint32_t 999gss_name_to_ucred(uint32_t *min, gss_name_t name, 1000 uid_t *uid, gid_t *gids, uint32_t *ngroups) 1001{ 1002 uint32_t maj, ms; 1003 gss_buffer_desc xname; 1004 uuid_t uu; 1005 int ret; 1006 int type; 1007 struct passwd *pwd, pwent; 1008 char pwdbuf[GetPWMaxRSz]; 1009 *uid = NobodyUid; 1010 *gids = NobodyGid; 1011 *ngroups = 1; 1012 1013 maj = gss_export_name(min, name, &xname); 1014 if (maj != GSS_S_COMPLETE) 1015 return (maj); 1016 1017 ret = mbr_identifier_to_uuid(ID_TYPE_GSS_EXPORT_NAME, xname.value, xname.length, uu); 1018 (void) gss_release_buffer(&ms, &xname); 1019 1020 if (ret) { 1021 DEBUG(2, "mbr_identifier_to_uid: failed to map export name to uuid: reason %d\n", ret); 1022 return (gss_name_to_ucred_1(min, name, uid, gids, ngroups)); 1023 } 1024 1025 ret = mbr_uuid_to_id(uu, uid, &type); 1026 if (ret || type != ID_TYPE_UID) { 1027 Info("gssapi: failed to turn uuid into uid: %d", ret); 1028 return (GSS_S_FAILURE); 1029 } 1030 1031 ret = getpwuid_r(*uid, &pwent, pwdbuf, sizeof(pwdbuf), &pwd); 1032 if (ret) { 1033 Info("Look up of uid %d failed. Reason %d: %s\n", *uid, errno, 1034 strerror(errno)); 1035 return (GSS_S_FAILURE); 1036 } 1037 1038 if (pwd) { 1039 *ngroups = NGROUPS_MAX; 1040 if (getgrouplist(pwd->pw_name, pwd->pw_gid, 1041 (int *)gids, (int *)ngroups) == -1) { 1042 /* Best we can do is just return the principal gid */ 1043 *gids = pwd->pw_gid; 1044 *ngroups = 1; 1045 } else { 1046 DEBUG(2, "getgrouplist failed.\n"); 1047 } 1048 } else { 1049 Log("Directory Service could not find uid %d.\n", *uid); 1050 return (GSS_S_FAILURE); 1051 } 1052 1053 return (GSS_S_COMPLETE); 1054} 1055 1056 1057static char * 1058lowercase(char *s) 1059{ 1060 char *t; 1061 1062 for (t = s; t && *t; t++) 1063 *t = tolower(*t); 1064 1065 return (s); 1066} 1067 1068/* 1069 * Turn a hostname into a FQDN if we can. Optionally do the reverse lookup 1070 * and return it as well in the rfqdn parameter if it is different from the 1071 * forward lookup. If that parameter is NULL, don't try the reverse lookup. 1072 * at all. If the foward lookup fails we return NULL. 1073 * If we succeed it is the caller's responsibility to free the results. 1074 */ 1075static char * 1076canonicalize_host(const char *host, char **rfqdn) 1077{ 1078 struct hostent *hp, *rhp; 1079 int h_err; 1080 char *fqdn; 1081 1082 if (rfqdn) 1083 *rfqdn = NULL; 1084 1085 hp = getipnodebyname(host, AF_INET6, AI_DEFAULT, &h_err); 1086 if (hp == NULL) { 1087 DEBUG(2, "host look up for %s returned %d\n", host, h_err); 1088 return (NULL); 1089 } 1090 fqdn = strdup(lowercase(hp->h_name)); 1091 if (fqdn == NULL) { 1092 Log("Could not allocat hostname in canonicalize_host\n"); 1093 return (NULL); 1094 } 1095 1096 if (rfqdn) { 1097 DEBUG(2, "Trying reverse lookup\n"); 1098 rhp = getipnodebyaddr(hp->h_addr_list[0], hp->h_length, AF_INET6, &h_err); 1099 if (rhp) { 1100 if (strncmp(fqdn, lowercase(rhp->h_name), MAXHOSTNAMELEN) != 0) { 1101 *rfqdn = strdup(rhp->h_name); 1102 if (*rfqdn == NULL) 1103 Log("Could not allocat hostname in canonicalize_host\n"); 1104 } 1105 freehostent(rhp); 1106 } 1107 else { 1108 DEBUG(2, "reversed host look up for %s returned %d\n", host, h_err); 1109 } 1110 } 1111 1112 freehostent(hp); 1113 1114 return (fqdn); 1115} 1116 1117/* 1118 * Given the service name, host name and realm, construct the kerberos gss 1119 * service name. 1120 */ 1121static uint32_t 1122construct_service_name(uint32_t *minor, const char *service, char *host, 1123 const char *realm, bool lcase, gss_name_t *svcname) 1124{ 1125 size_t len; 1126 char *s; 1127 gss_buffer_desc name_buf; 1128 uint32_t major; 1129 1130 if (lcase) 1131 lowercase(host); 1132 len = strlen(service) + strlen(host) + strlen(realm) + 3; 1133 s = malloc(len); 1134 if (s == NULL) { 1135 Log("Out of memory"); 1136 return (GSS_S_FAILURE); 1137 } 1138 strlcpy(s, service, len); 1139 strlcat(s, "/", len); 1140 strlcat(s, host, len); 1141 strlcat(s, "@", len); 1142 strlcat(s, realm, len); 1143 1144 str_to_buf(s, &name_buf); 1145 1146 Info("Importing kerberos principal service name %s\n", s); 1147 1148 major = gss_import_name(minor, &name_buf, 1149 GSS_KRB5_NT_PRINCIPAL_NAME, svcname); 1150 free(s); 1151 return (major); 1152} 1153 1154static uint32_t 1155construct_hostbased_service_name(uint32_t *minor, const char *service, const char *host, gss_name_t *svcname) 1156{ 1157 size_t len; 1158 char *s; 1159 gss_buffer_desc name_buf; 1160 uint32_t major; 1161 1162 len = strlen(service) + strlen(host) + 2; 1163 s = malloc(len); 1164 if (s == NULL) { 1165 Log("Out of memory"); 1166 return (GSS_S_FAILURE); 1167 } 1168 strlcpy(s, service, len); 1169 strlcat(s, "@", len); 1170 strlcat(s, host, len); 1171 1172 str_to_buf(s, &name_buf); 1173 1174 Info("Importing host based service name %s\n", s); 1175 1176 major = gss_import_name(minor, &name_buf, GSS_C_NT_HOSTBASED_SERVICE, svcname); 1177 1178 DEBUG(2, "gss_import_name returned %#K", major); 1179 1180 free(s); 1181 return (major); 1182} 1183 1184/* 1185 * str_to_svc_name: Given a string representation of a service name, convert it 1186 * into a set of gss service names of name type GSS_KRB5_NT_PRINCIPAL_NAME. 1187 * 1188 * We get up to three names, lowercase of the forward canonicalization of the 1189 * host name, lowercase of the host name itself, and the lowercase of the reverse 1190 * canonicalization of the host name. 1191 * 1192 * name_count is an in/out parameter that says what the size is of the svcname 1193 * array coming in and the number of gss names found coming out. 1194 * if name_count is one, no canonicalization is done 1195 * if name_count is two, return the lowercase of the forward canonicalization 1196 * followed by the non canonicalized host name 1197 * if name_count is three, the two elements above followed by the lowercase of 1198 * the reverse lookup. 1199 * 1200 * We return GSS_S_COMPLETE if we can produce at least one service name. 1201 */ 1202 1203#define LKDCPREFIX "LKDC:" 1204 1205static uint32_t 1206str_to_svc_names(uint32_t *minor, const char *svcstr, 1207 gss_name_t *svcname, uint32_t *name_count) 1208{ 1209 uint32_t major __unused /* To make the static analyser happy */, first_major; 1210 char *realm = NULL /* default_realm */, *host; 1211 char *s, *p, *service; 1212 char *fqdn = NULL, *rfqdn = NULL; 1213 uint32_t count = *name_count; 1214 int is_lkdc; 1215 krb5_realm *realms = NULL; 1216 1217 *minor = 0; 1218 major = GSS_S_FAILURE; 1219 *name_count = 0; 1220 1221 if (svcstr == NULL) { 1222 Log("Null service name string\n"); 1223 return (GSS_S_FAILURE); 1224 } 1225 DEBUG(3, "%s count = %d\n", svcstr, count); 1226 service = strdup(svcstr); 1227 if (service == NULL) { 1228 Log("Out of memory\n"); 1229 return (GSS_S_FAILURE); 1230 } 1231 1232 p = get_next_kerb_component(service); 1233 1234 /*set host part */ 1235 host = p + 1; 1236 1237 if (p == NULL || *p == '\0') { 1238 /* 1239 * We only have the service name so we (this host) 1240 * must be our instance. 1241 */ 1242 host = local_host; 1243 1244 } else if (*p == '@') { 1245 /* Have a host based service name */ 1246 /* Terminate service part of name */ 1247 *p = '\0'; 1248 1249 s = get_next_kerb_component(host); 1250 if (s != NULL) { 1251 Info("Invalid host name part %s\n", host); 1252 free(service); 1253 return (GSS_S_BAD_NAME); 1254 } 1255 major = construct_hostbased_service_name(minor, service, host, svcname); 1256 if (major == GSS_S_COMPLETE) 1257 *name_count = 1; 1258 return (major); 1259 } else if (*p == '/') { 1260 /* We have a kerberos instance thus a kerberos principal type */ 1261 /* Terminate service part of name */ 1262 *p = '\0'; 1263 1264 /* See if we have a realm */ 1265 s = host; 1266 do { 1267 s = get_next_kerb_component(s+1); 1268 if (s && (*s == '@')) { 1269 realm = s + 1; 1270 *s = '\0'; /* terminate host instance */ 1271 break; 1272 } 1273 } while (s); 1274 } else { 1275 /* Should never happen */ 1276 free(service); 1277 return (GSS_S_BAD_NAME); 1278 } 1279 1280 if (realm == NULL) { 1281 /* 1282 * Try this as a host based service name first, since 1283 * host base service name will get canonicalized, looked up in the domain realms 1284 * section and then tried for referrals 1285 */ 1286 major = construct_hostbased_service_name(minor, service, host, svcname); 1287 if (major == GSS_S_COMPLETE) { 1288 *name_count = 1; 1289 free(service); 1290 return (major); 1291 } 1292 /* Nope so set the realm to be the default and fall through */ 1293 if (get_local_realms(&realms)) 1294 realm = *realms; 1295 } 1296 if (realm == NULL) { 1297 free(service); 1298 /* 1299 * Force exit in SHUTDOWN_TIMEOUT. Perhaps 1300 * we'll pickup a default on next start up. 1301 */ 1302 kill(getpid(), SIGTERM); 1303 return (GSS_S_BAD_NAME); 1304 } 1305 1306 1307 is_lkdc = (strncmp(realm, LKDCPREFIX, strlen(LKDCPREFIX)) == 0); 1308 /* Don't lowercase an LKDC instance */ 1309 major = construct_service_name(minor, service, host, realm, !is_lkdc, &svcname[*name_count]); 1310 if (major == GSS_S_COMPLETE) 1311 *name_count += 1; 1312 first_major = major; 1313 1314 /* Don't waste time trying to canonicalize local KDCs */ 1315 if (count == 1 || is_lkdc) 1316 goto done; 1317 1318 fqdn = canonicalize_host(host, (count == 3) ? &rfqdn : NULL); 1319 if (fqdn) { 1320 if (strncmp(fqdn, host, MAXHOSTNAMELEN) != 0) { 1321 major = construct_service_name(minor, service, fqdn, realm, true, &svcname[*name_count]); 1322 if (major == GSS_S_COMPLETE) 1323 *name_count += 1; 1324 } else { 1325 free(fqdn); 1326 } 1327 } 1328 1329 if (rfqdn) { 1330 if (*name_count < count) { 1331 major = construct_service_name(minor, service, rfqdn, realm, true, &svcname[*name_count]); 1332 if (major == GSS_S_COMPLETE) 1333 *name_count += 1; 1334 } else { 1335 free(rfqdn); 1336 } 1337 } 1338 1339done: 1340 free(service); 1341 free_local_realms(realms); 1342 1343 return (*name_count ? GSS_S_COMPLETE : first_major); 1344} 1345 1346/* 1347 * Given the name and name type, convert the name to a gss_name_t. If the name type 1348 * is a mechanism specific (currently one of the kerberos or NTLM name types), we will set the mechtype 1349 * passed in to be that mechanism type. We do this so that we will acquire that mechanism specific 1350 * credential in do_acquire_cred. This is important when the mechanism being used is SPNEGO and 1351 * we end up trying to use the wrong credential. 1352 */ 1353static uint32_t 1354blob_to_name(uint32_t *min, gssd_nametype nt, gssd_byte_buffer name, uint32_t size, gssd_mechtype *mech, char **strrep, char **oidnt, gss_name_t *gname) 1355{ 1356 uint32_t maj; 1357 gss_buffer_desc name_buf = { size, name }; 1358 gss_OID name_type; 1359 *min = GSS_S_COMPLETE; 1360 1361 switch (nt) { 1362 case GSSD_EXPORT: 1363 name_type = GSS_C_NT_EXPORT_NAME; 1364 break; 1365 case GSSD_ANONYMOUS: 1366 name_type = GSS_C_NT_ANONYMOUS; 1367 if (*mech == GSSD_SPNEGO_MECH) 1368 *mech = GSSD_NTLM_MECH; 1369 break; 1370 case GSSD_HOSTBASED: 1371 name_type = GSS_C_NT_HOSTBASED_SERVICE; 1372 break; 1373 case GSSD_USER: 1374 name_type = GSS_C_NT_USER_NAME; 1375 break; 1376 case GSSD_MACHINE_UID: 1377 name_type = GSS_C_NT_MACHINE_UID_NAME; 1378 break; 1379 case GSSD_STRING_UID: 1380 name_type = GSS_C_NT_STRING_UID_NAME; 1381 break; 1382 case GSSD_KRB5_PRINCIPAL: 1383 name_type = GSS_KRB5_NT_PRINCIPAL_NAME; 1384 *mech = GSSD_KRB5_MECH; 1385 break; 1386 case GSSD_UUID: 1387 name_type = GSS_C_NT_UUID; 1388 *mech = GSSD_IAKERB_MECH; 1389 break; 1390 case GSSD_KRB5_REFERRAL: 1391 name_type = GSS_KRB5_NT_PRINCIPAL_NAME_REFERRAL; 1392 *mech = GSSD_KRB5_MECH; 1393 break; 1394 case GSSD_NTLM_PRINCIPAL: 1395 name_type = GSS_C_NT_NTLM; 1396 *mech = GSSD_NTLM_MECH; 1397 break; 1398 case GSSD_NTLM_BLOB: 1399 default: 1400 return (GSS_S_BAD_NAMETYPE); 1401 } 1402 1403 maj = gss_import_name(min, &name_buf, name_type, gname); 1404 1405 if (maj != GSS_S_COMPLETE || get_debug_level() > 1) { 1406 char *ntstr = oid_name(name_type); 1407 Info("gss_import_name returned %#K; %#k for %.*s using %s name type", 1408 maj, mechtab[*mech], *min, size, name, ntstr); 1409 free(ntstr); 1410 } 1411 if (maj == GSS_S_COMPLETE && strrep) { 1412 uint32_t dmaj, dmin; 1413 gss_buffer_desc dbuf; 1414 gss_OID oid; 1415 1416 dmaj = gss_display_name(&dmin, *gname, &dbuf, &oid); 1417 DEBUG(3, "gss_display_name returned %#K", dmaj); 1418 *strrep = (dmaj == GSS_S_COMPLETE) ? buf_to_str(&dbuf) : strdup("unknown"); 1419 if (oidnt) 1420 *oidnt = oid_name(oid); 1421 } 1422 1423 return (maj); 1424} 1425 1426static uint32_t 1427blob_to_svcnames(uint32_t *min, gssd_nametype nt, gssd_byte_buffer svc_princ, uint32_t size, 1428 gssd_mechtype mech, gss_name_t *svcname, uint32_t *name_count) 1429{ 1430 *min = GSS_S_COMPLETE; 1431 1432 switch (nt) { 1433 case GSSD_STRING_NAME: 1434 return (str_to_svc_names(min, (char *)svc_princ, svcname, name_count)); 1435 default: 1436 *name_count = 1; 1437 return (blob_to_name(min, nt, svc_princ, size, &mech, NULL, NULL, svcname)); 1438 } 1439} 1440 1441static int 1442is_nfs_service(gss_name_t svcname) 1443{ 1444 uint32_t maj, min; 1445 gss_buffer_desc nbuf; 1446 gss_name_t canon; 1447 char *str = NULL; 1448 int is_nfs = 0; 1449 1450 maj = gss_canonicalize_name(&min, svcname, mechtab[GSSD_KRB5_MECH], &canon); 1451 if (maj != GSS_S_COMPLETE) 1452 return (0); 1453 1454 maj = gss_display_name(&min, canon, &nbuf, NULL); 1455 if (maj != GSS_S_COMPLETE) 1456 goto done; 1457 1458 str = buf_to_str(&nbuf); 1459 1460 DEBUG(3, "is_nfs_service principal is %s\n", str ? str : ""); 1461 1462 if (str) 1463 is_nfs = IS_NFS_SERVICE(str); 1464 1465done: 1466 free(str); 1467 1468 return (is_nfs); 1469} 1470 1471/* 1472 * Figure out who nobody is and how big a buffer we need to fetch password entries. 1473 * If we're logging at a debug level print out the default realm if we can. 1474 */ 1475static void 1476gssd_init(void) 1477{ 1478 struct passwd *pwent; 1479 struct group *grent; 1480 char hostbuf[MAXHOSTNAMELEN]; 1481 1482 /* Set up mech table */ 1483 mechtab[GSSD_KRB5_MECH] = GSS_KRB5_MECHANISM; 1484 mechtab[GSSD_SPNEGO_MECH] = GSS_SPNEGO_MECHANISM; 1485 mechtab[GSSD_NTLM_MECH] = GSS_NTLM_MECHANISM; 1486 mechtab[GSSD_IAKERB_MECH] = GSS_IAKERB_MECHANISM; 1487 1488 /* 1489 * Turn off home directory access during startup. 1490 * XXX Will need a more flexible policy to handle 1491 * apps that may want home dir access. 1492 */ 1493 krb5_set_home_dir_access(NULL, FALSE); 1494 1495 pwent = getpwnam("nobody"); 1496 NobodyUid = pwent ? pwent->pw_uid : NOBODY; 1497 grent = getgrnam("nobody"); 1498 NobodyGid = grent ? grent->gr_gid : NOBODY; 1499 1500 gethostname(hostbuf, MAXHOSTNAMELEN); 1501 local_host = canonicalize_host(hostbuf, NULL); 1502 if ( local_host == NULL) { 1503 Info("Could not canonicalize our host name in gssd_init\n"); 1504 local_host = strdup(lowercase(hostbuf)); 1505 } 1506 1507 /* Figure out how big a buffer we need for getting pwd entries */ 1508 GetPWMaxRSz = sysconf(_SC_GETPW_R_SIZE_MAX); 1509 GetPWMaxRSz = (GetPWMaxRSz == -1) ? 512 : GetPWMaxRSz; 1510 1511 DEBUG(2, "Starting with pid = %d\n\n\n", getpid()); 1512 if (get_debug_level()) { 1513 krb5_realm *realms = NULL; 1514 krb5_realm drealm = NULL; 1515 1516 if (get_local_realms(&realms)) 1517 drealm = *realms; 1518 Info("Kerberos default realm is %s for %s\n\n", 1519 drealm ? drealm : "No realm", local_host); 1520 free_local_realms(realms); 1521 } 1522} 1523 1524/* 1525 * Receive one message. Note that mach_msg_server_once will call 1526 * the appropriate dispatch routine, which in turn will call new_worker_thread() 1527 * and that will fire us up again to wait for the next message. 1528 */ 1529static void * 1530receive_message(void *arg __attribute__((unused))) 1531{ 1532 kern_return_t kr; 1533 1534 1535#ifdef VDEBUG 1536 DEBUG(3, "Enter receive_message %p with transaction count = %lu, " 1537 "standby count = %lu\n", pthread_self(), 1538 _vproc_transaction_count(), _vproc_standby_count()); 1539#endif 1540 pthread_setname_np("mach_msg_server thread"); 1541 kr = mach_msg_server_once(gssd_mach_server, MAX_GSSD_MSG_SIZE, 1542 gssd_receive_right, 1543 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | 1544 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)); 1545 1546 1547#ifdef VDEBUG 1548 DEBUG(3, "Leaving receive_message %p with transaction count = %lu, " 1549 "standby count = %lu\n", pthread_self(), 1550 _vproc_transaction_count(), _vproc_standby_count()); 1551#endif 1552 1553 if (kr != KERN_SUCCESS) { 1554 Info("mach_msg_server(mp): %s\n", mach_error_string(kr)); 1555 exit(1); 1556 } 1557 1558 return (NULL); 1559} 1560 1561 1562/* 1563 * Wait until we have fewer than the maximum number of worker threads, 1564 * and then create one running receive_message() thread. 1565 * 1566 * Called by the dispatch routines just before processing a message, 1567 * so we're listening for messages even while processing a message, 1568 * as long as we aren't out of threads. 1569 */ 1570#define MAXTHREADNAME 24 1571 1572static void 1573new_worker_thread(void) 1574{ 1575 pthread_t thread; 1576 char thread_name[MAXTHREADNAME]; 1577 int error; 1578 1579 (void) pthread_mutex_lock(numthreads_lock); 1580 1581 while (bye == 0 && numthreads >= maxthreads) { 1582 (void) pthread_cond_wait(numthreads_cv, numthreads_lock); 1583 } 1584 if (bye) 1585 goto out; 1586 numthreads++; 1587 error = pthread_create(&thread, attr, receive_message, NULL); 1588 if (error) { 1589 Info("unable to create worker thread: %s", strerror(error)); 1590 numthreads--; 1591 } 1592 1593out: 1594 1595 snprintf(thread_name, sizeof (thread_name), "worker thread %d", numthreads); 1596 thread_name[MAXTHREADNAME - 1] = '\0'; 1597 pthread_setname_np(thread_name); 1598 DEBUG(3, "Starting %s\n", thread_name); 1599 1600 (void) pthread_mutex_unlock(numthreads_lock); 1601} 1602 1603/* 1604 * This worker thread is terminating; reduce the count of worker threads, 1605 * and, if it's dropped below the maximum, wake up anybody waiting for 1606 * it to drop below the maximum. 1607 * 1608 * Called by the dispatch routines just before returning. 1609 */ 1610static void 1611end_worker_thread(void) 1612{ 1613 (void) pthread_mutex_lock(numthreads_lock); 1614 numthreads--; 1615 if (numthreads < maxthreads) 1616 pthread_cond_signal(numthreads_cv); 1617 1618 if (get_debug_level() > 2) { 1619 char thread_name[MAXTHREADNAME]; 1620 pthread_getname_np(pthread_self(), thread_name, sizeof thread_name); 1621 DEBUG(3, "Ending %s. Number of worker threads running is %d\n", thread_name, numthreads); 1622 } 1623 1624 (void) pthread_mutex_unlock(numthreads_lock); 1625} 1626 1627 1628/* 1629 * Thread that handles signals for us and will tell the timeout thread to 1630 * shut us down if we get a signal that we don't continue for. We set a global 1631 * variable bye and the timeout value to SHUTDOWN_TIMEOUT and wake every 1632 * body up. Threads block in new_worker_thread will see bye is set and exit. 1633 * We set timeout to SHUTDOWN_TIMEOUT for the timeout thread, so that threads 1634 * executing dispatch routines have an opportunity to finish. 1635 */ 1636 1637static void* 1638shutdown_thread(void *arg __attribute__((unused))) 1639{ 1640 int sig; 1641 int status; 1642 int remote_token; 1643 int master_token; 1644 sigset_t quitset[1]; 1645 1646 pthread_setname_np("Signal thread"); 1647 1648 sigemptyset(quitset); 1649 sigaddset(quitset, SIGQUIT); 1650 1651 status = notify_register_signal(asl_remote_notify_name(), SIGUSR2, &remote_token); 1652 if (status != NOTIFY_STATUS_OK) 1653 Log("Could not register for asl notifications: %s\n", asl_remote_notify_name()); 1654 status = notify_register_signal(NOTIFY_SYSTEM_MASTER, SIGUSR2, &master_token); 1655 if (status != NOTIFY_STATUS_OK) 1656 Log("Could not register for asl notifications: %s\n", NOTIFY_SYSTEM_MASTER); 1657 1658 /* 1659 * N.B. From the man page: "A true indication is returned the first time notify_check 1660 * is called for a token. Subsequent calls give a true indication when notifications have 1661 * been posted for the name associated with the notification token." 1662 * 1663 * So we do a notify_check here for the above tokens to get the true status when processing 1664 * SIGUSR2 below. 1665 */ 1666 (void)notify_check(remote_token, &status); 1667 (void)notify_check(master_token, &status); 1668 1669 do { 1670 int asl_notification = 0; 1671 int debug_level = get_debug_level(); 1672 1673 if (sigwait(waitset, &sig)) 1674 Log("sigwait failed %s", strerror(errno)); 1675 1676 DEBUG(2, "Received signal %d\n", sig); 1677 switch (sig) { 1678 case SIGQUIT: 1679 if (get_debug_level() > 1) 1680 die = 1; 1681 else { 1682 pthread_sigmask(SIG_UNBLOCK, quitset, NULL); 1683 raise(SIGQUIT); 1684 } 1685 break; 1686 case SIGUSR1: 1687 debug_level++; 1688 break; 1689 case SIGUSR2: 1690 status = notify_check(master_token, &asl_notification); 1691 if (status != NOTIFY_STATUS_OK) 1692 Log("Could not retreive notification for %s", NOTIFY_SYSTEM_MASTER); 1693 if (asl_notification == 0) { 1694 status = notify_check(remote_token, &asl_notification); 1695 if (status != NOTIFY_STATUS_OK ) 1696 Log("Could not retreive notification for %s", asl_remote_notify_name()); 1697 if (asl_notification == 0) { 1698 if (debug_level) 1699 debug_level--; 1700 } 1701 } 1702 break; 1703 case SIGHUP: 1704 debug_level = !debug_level; 1705 break; 1706 } 1707 if (asl_notification) { 1708 set_debug_level(-1); 1709 Info("Debug set to %d by syslog\n", get_debug_level()); 1710 } else { 1711 set_debug_level(debug_level); 1712 Info("Debug level set to %d", get_debug_level()); 1713 } 1714 } while (sigismember(contset, sig) || sig == 0); 1715 1716 pthread_mutex_lock(numthreads_lock); 1717 bye = 1; 1718 /* 1719 * Wait a little bit for dispatch threads to complete. 1720 */ 1721 timeout = SHUTDOWN_TIMEOUT; 1722 /* 1723 * Force the timeout_thread and all the rest to to wake up and exit. 1724 */ 1725 pthread_cond_broadcast(numthreads_cv); 1726 pthread_mutex_unlock(numthreads_lock); 1727 1728 return (NULL); 1729} 1730 1731static void 1732compute_new_timeout(struct timespec *new) 1733{ 1734 struct timeval current; 1735 1736 gettimeofday(¤t, NULL); 1737 new->tv_sec = current.tv_sec + timeout; 1738 new->tv_nsec = 1000 * current.tv_usec; 1739} 1740 1741static int no_timeout; 1742 1743static void 1744disable_timeout(int disable) 1745{ 1746 pthread_mutex_lock(numthreads_lock); 1747 no_timeout = disable; 1748 pthread_mutex_unlock(numthreads_lock); 1749} 1750 1751static void* 1752timeout_thread(void *arg __attribute__((unused))) 1753{ 1754 int rv = 0; 1755 struct timespec exittime; 1756 1757 pthread_setname_np("Timeout thread"); 1758 (void) pthread_mutex_lock(numthreads_lock); 1759 1760 /* 1761 * Note that we have an extra thread running waiting for a mach message, 1762 * the first of which was started in main. Hence we have the test below for 1763 * greater than one instead of zero. 1764 */ 1765 while (bye ? (rv == 0 && numthreads > 1) : (rv == 0 || no_timeout || numthreads > 1)) { 1766 if (bye < 2) 1767 compute_new_timeout(&exittime); 1768 /* 1769 * If the shutdown thread has told us to exit (bye == 1), 1770 * then increment bye so that we will exit after at most 1771 * SHUTDOWN_TIMEOUT from the time we were signaled. When 1772 * we come back around the loop bye will be greater or 1773 * equal to two and we will not update our absolute exit time. 1774 */ 1775 if (bye) 1776 bye++; 1777 rv = pthread_cond_timedwait(numthreads_cv, 1778 numthreads_lock, &exittime); 1779 1780 DEBUG(4, "timeout_thread: rv = %s %d\n", 1781 rv ? strerror(rv) : "signaled", numthreads); 1782 } 1783 1784 (void) pthread_mutex_unlock(numthreads_lock); 1785 1786 1787 return (NULL); 1788} 1789 1790/* 1791 * vm_alloc_buffer: Copy the contents of the gss_buf_t to vm_allocated 1792 * memory at *value. The mig routines will automatically deallocate this 1793 * memory. 1794 */ 1795 1796static void 1797vm_alloc_buffer(gss_buffer_t buf, uint8_t **value, uint32_t *len) 1798{ 1799 kern_return_t kr; 1800 1801 *value = NULL; 1802 *len = 0; 1803 1804 if (buf->length == 0) 1805 return; 1806 kr = vm_allocate(mach_task_self(), 1807 (vm_address_t *)value, buf->length, VM_FLAGS_ANYWHERE); 1808 if (kr != KERN_SUCCESS) { 1809 Log("Could not allocate vm in vm_alloc_buffer\n"); 1810 return; 1811 } 1812 *len = (uint32_t) buf->length; 1813 memcpy(*value, buf->value, *len); 1814} 1815 1816/* 1817 * Extract the session key from a completed gss context. Currently the only 1818 * supported mechanism is kerberos and NTLM. Note the extracted key has been vm_allocated 1819 * and will be released by mig. (See gssd_mach.defs) 1820 * XXX this is extraordinarily yuckie. 1821 */ 1822 1823 1824static gss_OID kerb_mechs[] = { 1825 GSS_KRB5_MECHANISM, 1826 GSS_IAKERB_MECHANISM, 1827 GSS_PKU2U_MECHANISM, 1828 NULL 1829}; 1830 1831static bool 1832is_kerberos_key_mech(gss_const_OID mech) 1833{ 1834 gss_OID *p; 1835 1836 for (p = kerb_mechs; p; p++) { 1837 if (gss_oid_equal(mech, *p)) 1838 return (true); 1839 } 1840 1841 return (false); 1842} 1843 1844static uint32_t 1845GetSessionKey(uint32_t *minor, gss_OID mech, gss_ctx_id_t *ctx, 1846 gssd_byte_buffer *skey, mach_msg_type_number_t *skeyCnt) 1847{ 1848 gss_krb5_lucid_context_v1_t *lucid_ctx = NULL; 1849 gss_krb5_lucid_key_t *key; 1850 void *some_lucid_ctx; 1851 uint32_t maj_stat, min_stat; 1852 uint32_t vers; 1853 gss_buffer_desc buf; 1854 1855 *skey = NULL; 1856 *skeyCnt = 0; 1857 *minor = 0; 1858 1859 if (gss_oid_equal(mech, GSS_NTLM_MECHANISM)) { 1860 gss_buffer_set_t keys; 1861 maj_stat = gss_inquire_sec_context_by_oid(minor, *ctx, GSS_NTLM_GET_SESSION_KEY_X, &keys); 1862 if (maj_stat != GSS_S_COMPLETE) 1863 return (maj_stat); 1864 1865 if (keys->count) { 1866 if (keys->count > 1) 1867 Info("GetSessionKey received multiple keys. Using first key of %d keys\n", (uint32_t)keys->count); 1868 vm_alloc_buffer(&keys->elements[0], skey, skeyCnt); 1869 if (skey == NULL) { 1870 Log("Out of memory in GetSessionKey\n"); 1871 return (GSS_S_FAILURE); 1872 } 1873 } 1874 (void)gss_release_buffer_set(&min_stat, &keys); 1875 return (GSS_S_COMPLETE); 1876 1877 } else if (is_kerberos_key_mech(mech)) { 1878 DEBUG(4, "Calling gss_krb5_export_lucid_sec_context\n"); 1879 maj_stat = gss_krb5_export_lucid_sec_context(minor, ctx, 1880 1, &some_lucid_ctx); 1881 DEBUG(3, "gss_krb5_export_lucid_sec_context returned %#K; %#k", maj_stat, mech, *minor); 1882 1883 if (maj_stat != GSS_S_COMPLETE) { 1884 return (maj_stat); 1885 } 1886 *ctx = GSS_C_NO_CONTEXT; 1887 1888 vers = ((gss_krb5_lucid_context_version_t *)some_lucid_ctx)->version; 1889 switch (vers) { 1890 case 1: 1891 lucid_ctx = (gss_krb5_lucid_context_v1_t *)some_lucid_ctx; 1892 break; 1893 default: 1894 Log("Lucid version %d is unsupported\n", vers); 1895 (void) gss_krb5_free_lucid_sec_context(&min_stat, lucid_ctx); 1896 return (GSS_S_UNAVAILABLE); 1897 } 1898 1899 DEBUG(4, "vers = %d, protocol = %d\n", vers, lucid_ctx->protocol); 1900 1901 switch (lucid_ctx->protocol) { 1902 case 0: 1903 DEBUG(4, "Got rfc1964\n"); 1904 key = &lucid_ctx->rfc1964_kd.ctx_key; 1905 break; 1906 case 1: 1907 key = lucid_ctx->cfx_kd.have_acceptor_subkey ? 1908 &lucid_ctx->cfx_kd.acceptor_subkey : 1909 &lucid_ctx->cfx_kd.ctx_key; 1910 break; 1911 default: 1912 (void) gss_krb5_free_lucid_sec_context(&min_stat, lucid_ctx); 1913 return (GSS_S_CALL_BAD_STRUCTURE); /* should never happen. */ 1914 } 1915 1916 DEBUG(4, "lucid key type = %d\n", key->type); 1917 buf.length = key->length; 1918 buf.value = key->data; 1919 1920 vm_alloc_buffer(&buf, skey, skeyCnt); 1921 if (skey == NULL) { 1922 Log("Out of memory in GetSessionKey\n"); 1923 return (GSS_S_FAILURE); 1924 } 1925 1926 (void) gss_krb5_free_lucid_sec_context(&min_stat, lucid_ctx); 1927 return (GSS_S_COMPLETE); 1928 } 1929 1930 maj_stat = gss_oid_to_str(&min_stat, mech, &buf); 1931 if (maj_stat == GSS_S_COMPLETE) { 1932 char *oidstr = buf_to_str(&buf); 1933 Info("Unsupported mechanism for key extraction: %s\n", oidstr); 1934 free(oidstr); 1935 } else { 1936 Info("Unsupported mechanism for key extraction.\n"); 1937 } 1938 1939 return (GSS_S_COMPLETE); 1940} 1941 1942/* 1943 * If we get a call and the verifier does not match, clear out the args for 1944 * the client. 1945 */ 1946static uint32_t 1947badcall(char *rtn, uint32_t *minor_stat, 1948 gssd_ctx *gss_context, gssd_cred *cred_handle, uint32_t *gssd_flags, 1949 gssd_byte_buffer *skey, mach_msg_type_number_t *skeyCnt, 1950 gssd_byte_buffer *otoken, mach_msg_type_number_t *otokenCnt) 1951{ 1952 1953 if (!gssd_check(CAST(void *, *gss_context))) 1954 Info("Bad context found %p\n", (void *)(uintptr_t)*gss_context); 1955 if (!gssd_check(CAST(void *, *cred_handle))) 1956 Info("Bad cred handle found %p\n", (void *)(uintptr_t)*cred_handle); 1957 Log("%s request not addressed to us\n", rtn); 1958 *minor_stat = 0; 1959 *gss_context = CAST(gssd_ctx, GSS_C_NO_CONTEXT); 1960 *cred_handle = CAST(gssd_cred, GSS_C_NO_CREDENTIAL); 1961 *gssd_flags = 0; 1962 *skey = NULL; 1963 *skeyCnt = 0; 1964 *otoken = NULL; 1965 *otokenCnt = 0; 1966 1967 return (GSS_S_CALL_BAD_STRUCTURE); 1968} 1969 1970/* 1971 * Convert a gss_name_t to a krb5_principal 1972 */ 1973static uint32_t 1974gss_name_to_kprinc(uint32_t *minor, gss_name_t name, krb5_principal *princ, krb5_context kctx) 1975{ 1976 uint32_t major, m; 1977 gss_name_t kname = GSS_C_NO_NAME; 1978 gss_buffer_desc dname; 1979 char *strname = NULL; 1980 1981 *minor = 0; 1982 major = gss_canonicalize_name(minor, name, GSS_KRB5_MECHANISM, &kname); 1983 if (major != GSS_S_COMPLETE) 1984 return (major); 1985 1986 major = gss_display_name(minor, kname, &dname, NULL); 1987 (void) gss_release_name(&m, &kname); 1988 if (major != GSS_S_COMPLETE) 1989 return (major); 1990 1991 strname = buf_to_str(&dname); 1992 if (strname == NULL) { 1993 return (GSS_S_FAILURE); 1994 } 1995 1996 DEBUG(3, "parsing %s\n", strname); 1997 *minor = krb5_parse_name(kctx, strname, princ); 1998 1999 major = (uint32_t) (*minor ? GSS_S_FAILURE : GSS_S_COMPLETE); 2000 free(strname); 2001 2002 return (major); 2003} 2004 2005/* 2006 * krb5_find_cache_name(krb5_principal princ) 2007 * 2008 * Given a kerberos principal find the best cache name to use. 2009 */ 2010 2011static int cred_logged = 0; /* Only complain about missing creds once per gssd session */ 2012 2013static char* 2014krb5_find_cache_name(krb5_context kcontext, krb5_principal sprinc, int *expired) 2015{ 2016 krb5_error_code error, err; 2017 krb5_cc_cache_cursor cursor; 2018 krb5_ccache ccache; 2019 krb5_principal ccache_princ; 2020 char *cname = NULL; 2021 char *kname = NULL; 2022 time_t ltime; 2023 const char *msg = NULL; 2024 int cnt = 0; 2025 *expired = 0; 2026 2027 err = krb5_cc_cache_get_first(kcontext, NULL, &cursor); 2028 if (err) { 2029 if (!cred_logged) { 2030 Log("No credentials found, using default (need to kinit?)\n"); 2031 cred_logged = 1; 2032 msg = krb5_get_error_message(kcontext, err); 2033 Info("Could not get cache collection cursor %s\n", msg); 2034 krb5_free_error_message(kcontext, msg); 2035 } 2036 return (NULL); 2037 } 2038 while (!(error = krb5_cc_cache_next(kcontext, cursor, &ccache))) { 2039 cnt += 1; 2040 err = krb5_cc_get_full_name(kcontext, ccache, &cname); 2041 if (err) { 2042 msg = krb5_get_error_message(kcontext, err); 2043 Info("krb5_cc_get_full_name error: %s\n", msg); 2044 krb5_free_error_message(kcontext, msg); 2045 krb5_cc_close(kcontext, ccache); 2046 if (cname) /* Shouldn't happen */ 2047 free(cname); 2048 cname = NULL; 2049 continue; 2050 } 2051 err = krb5_cc_get_principal(kcontext, ccache, &ccache_princ); 2052 if (err) { 2053 krb5_cc_close(kcontext, ccache); 2054 msg = krb5_get_error_message(kcontext, err); 2055 Info("krb5_cc_get_principal error: %s\n", msg); 2056 krb5_free_error_message(kcontext, msg); 2057 free(cname); 2058 cname = NULL; 2059 continue; 2060 } 2061 if (krb5_realm_compare(kcontext, sprinc, ccache_princ)) { 2062 (void) krb5_unparse_name(kcontext, ccache_princ, &kname); 2063 krb5_free_principal(kcontext, ccache_princ); 2064 2065 ltime = 0; 2066 *expired = 0; 2067 err = krb5_cc_get_lifetime(kcontext, ccache, <ime); 2068 Info("Found cache %d: %s for %s lifetime %ld\n", 2069 cnt, cname, kname ? kname : "could not get principal name", ltime); 2070 if (kname) { 2071 free(kname); 2072 kname = NULL; 2073 } 2074 2075 if (ltime <= 0) { 2076 if (err && err != KRB5_CC_END) { 2077 msg = krb5_get_error_message(kcontext, err); 2078 Info("krb5_cc_get_lifetime error: %s\n", msg); 2079 krb5_free_error_message(kcontext, msg); 2080 } 2081 *expired = 1; 2082 } else { 2083 krb5_cc_close(kcontext, ccache); 2084 break; 2085 } 2086 } 2087 krb5_cc_close(kcontext, ccache); 2088 free(cname); 2089 cname = NULL; 2090 } 2091 if (error == KRB5_CC_END) { 2092 if (!cred_logged) { 2093 Notice("No credentials found for %s, using default (need to kinit?)\n", krb5_principal_get_realm(kcontext, sprinc)); 2094 cred_logged = 1; 2095 } 2096 } else if (error) { 2097 msg = krb5_get_error_message(kcontext, error); 2098 Log("Could not iterate through cache collections: %s\n", msg); 2099 krb5_free_error_message(kcontext, msg); 2100 } 2101 2102 return (cname); 2103} 2104 2105/* 2106 * set_principal_identity: 2107 * Given a service principal try and set the default identity so that 2108 * calls to gss_init_sec_context will work. 2109 * Currently this only groks kerberos. 2110 */ 2111static uint32_t 2112set_principal_identity(gss_name_t sname, uint32_t *minor) 2113{ 2114 krb5_principal sprinc; 2115 uint32_t major; 2116 char *cname; 2117 krb5_context kctx; 2118 int error, expired; 2119 2120 *minor = 0; 2121 error = krb5_init_context(&kctx); 2122 if (error) { 2123 Log("Can't get kerberos context"); 2124 return (GSS_S_FAILURE); 2125 } 2126 2127 major = gss_name_to_kprinc(minor, sname, &sprinc, kctx); 2128 if (major != GSS_S_COMPLETE) { 2129 krb5_free_context(kctx); 2130 DEBUG(2, "Could not convert gss name to kerberos principal %#K %#k\n", major, GSS_KRB5_MECHANISM, *minor); 2131 return (major); 2132 } 2133 2134 cname = krb5_find_cache_name(kctx, sprinc, &expired); 2135 krb5_free_principal(kctx, sprinc); 2136 krb5_free_context(kctx); 2137 Debug("Using ccache <%s> expired = %d\n", cname ? cname : "Default", expired); 2138 if (expired) 2139 return (GSS_S_CREDENTIALS_EXPIRED); 2140 if (cname) { 2141 major = gss_krb5_ccache_name(minor, cname, NULL); 2142 DEBUG(3, "gss_krb5_ccache_name returned %#K; %#k\n", major, GSS_KRB5_MECHANISM, minor); 2143 free(cname); 2144 } 2145 2146 return (GSS_S_COMPLETE); 2147} 2148 2149 2150static uint32_t 2151do_acquire_cred_v1(uint32_t *minor, char *principal, gssd_mechtype mech, gss_name_t sname, uint32_t uid, 2152 gssd_cred *cred_handle, uint32_t flags) 2153{ 2154 uint32_t major = GSS_S_FAILURE, mstat; 2155 gss_buffer_desc buf_name; 2156 gss_name_t clnt_gss_name; 2157 gss_OID_set mechset = GSS_C_NULL_OID_SET; 2158 gss_OID name_type = GSS_KRB5_NT_PRINCIPAL_NAME; 2159 2160 major = set_principal_identity(sname, minor); 2161 if (major) 2162 return (major); 2163 major = gss_create_empty_oid_set(minor, &mechset); 2164 if (major != GSS_S_COMPLETE) 2165 goto done; 2166 major = gss_add_oid_set_member(minor, mechtab[mech], &mechset); 2167 if (major != GSS_S_COMPLETE) 2168 goto done; 2169 2170 /* 2171 * If we've been passed a principal name then try that first with Kerberos. 2172 * Since using GSS_C_NT_USER_NAME might work, but throw away instance and realm 2173 * info. It seems easier just to try and not call gss_inquire_names_for_mech 2174 */ 2175 if (principal && *principal) { 2176 str_to_buf(principal, &buf_name); 2177 2178 Info("importing name %s with Kerberos\n", principal); 2179 2180 retry: 2181 major = gss_import_name(minor, &buf_name, name_type, &clnt_gss_name); 2182 if (major == GSS_S_COMPLETE) { 2183 char *nt_oid; 2184 major = gss_acquire_cred( 2185 minor, 2186 clnt_gss_name, 2187 GSS_C_INDEFINITE, 2188 mechset, 2189 GSS_C_INITIATE, 2190 (gss_cred_id_t *) cred_handle, 2191 NULL, NULL); 2192 nt_oid = oid_name(name_type); 2193 Info("gss_acuire_cred for %s using %s, returned: %K; %#k", principal, nt_oid, major, mechtab[mech], *minor); 2194 free(nt_oid); 2195 if (major == GSS_S_COMPLETE) { 2196 /* Done with the name */ 2197 (void) gss_release_name(&mstat, &clnt_gss_name); 2198 goto done; 2199 } 2200 } 2201 2202 /* 2203 * We could call gss_inquire_names_for_mech and try all supported name types 2204 * but it seems likely the only name type of interest would be GSS_C_NT_USER_NAME. 2205 */ 2206 if (name_type == GSS_KRB5_NT_PRINCIPAL_NAME) { 2207 name_type = GSS_C_NT_USER_NAME; 2208 goto retry; 2209 } 2210 } 2211 2212 if (!(flags & GSSD_NO_DEFAULT)) { 2213 /* Try default */ 2214 major = gss_acquire_cred( 2215 minor, 2216 GSS_C_NO_NAME, 2217 GSS_C_INDEFINITE, 2218 mechset, 2219 GSS_C_INITIATE, 2220 (gss_cred_id_t *) cred_handle, 2221 NULL, NULL); 2222 2223 if (major == GSS_S_COMPLETE) { 2224 Info("Using default credential %p\n", *(gss_cred_id_t *)cred_handle); 2225 goto done; 2226 } 2227 } 2228 2229 /* See if uid will work */ 2230 major = uid_to_gss_name(minor, (uid_t) uid, 2231 GSS_C_NT_USER_NAME, &clnt_gss_name); 2232 if (major != GSS_S_COMPLETE) 2233 return (major); 2234 2235 major = gss_acquire_cred( 2236 minor, 2237 clnt_gss_name, 2238 GSS_C_INDEFINITE, 2239 mechset, 2240 GSS_C_INITIATE, 2241 (gss_cred_id_t *) cred_handle, 2242 NULL, NULL); 2243 Info("Trying to aquire cred with uid %d. Returned %#K; %#k", uid, major, mechtab[mech], *minor); 2244 2245 /* Done with the name */ 2246 (void) gss_release_name(&mstat, &clnt_gss_name); 2247done: 2248 if (mechset != GSS_C_NULL_OID_SET) 2249 gss_release_oid_set(&mstat, &mechset); 2250 2251 return (major); 2252} 2253 2254static uint32_t 2255do_acquire_cred(uint32_t *minor_stat, gssd_nametype nt, gssd_byte_buffer name, uint32_t size, 2256 gssd_mechtype mech, gss_cred_id_t *handle) 2257{ 2258 uint32_t maj, min, nmaj; 2259 gss_OID_set mechset = GSS_C_NULL_OID_SET; 2260 gss_name_t gname = GSS_C_NO_NAME; 2261 char *mech_name= NULL; 2262 char *princ_name = NULL; 2263 char *oid_nt = NULL; 2264 2265 *minor_stat = GSS_S_COMPLETE; 2266 2267 if (handle == NULL) 2268 return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_CALL_INACCESSIBLE_WRITE); 2269 2270 maj = gss_create_empty_oid_set(minor_stat, &mechset); 2271 if (maj != GSS_S_COMPLETE) 2272 return (maj); 2273 2274 /* 2275 * Convert the name blob to a gss_name_t, giving back the string representation for 2276 * the name and the name type oid passed in. In addition if the name type was a 2277 * mech specific name type adjust the mech to reflect that. That mechanism will 2278 * then be added as the only member to the mech set below, and thus we will only 2279 * acquire credentials for that mech. This is important for SPNEGO, if we don't do 2280 * that, then SPNEGO may try mechanism we are not interested in. 2281 */ 2282 nmaj = blob_to_name(minor_stat, nt, name, size, &mech, &princ_name, &oid_nt, &gname); 2283 2284 maj = gss_add_oid_set_member(minor_stat, mechtab[mech], &mechset); 2285 if (maj != GSS_S_COMPLETE) 2286 goto done; 2287 2288 /* If we can't convert to a gss_name_t try the default with the possibly adjusted mech type */ 2289 if (nmaj != GSS_S_COMPLETE) 2290 goto do_default; 2291 2292 mech_name = oid_name(mechtab[mech]); 2293 Info("Acquiring credentials for %s with %s name type using %s mechanism", 2294 princ_name, oid_nt, mech_name ? mech_name : "Unknown"); 2295 free(mech_name); 2296 2297 maj = gss_acquire_cred(minor_stat, 2298 gname, 2299 GSS_C_INDEFINITE, 2300 mechset, 2301 GSS_C_INITIATE, 2302 handle, 2303 NULL, NULL); 2304 2305 (void)gss_release_name(&min, &gname); 2306 Info("Acquiring passed in credentials %K; %#k", maj, mechtab[mech], *minor_stat); 2307 if (maj == GSS_S_COMPLETE) 2308 goto done; 2309 2310do_default: 2311 if (!acquire_default) 2312 goto done; 2313 2314 /* Use the default in gss_init_sec_context */ 2315 maj = gss_acquire_cred( 2316 minor_stat, 2317 GSS_C_NO_NAME, 2318 GSS_C_INDEFINITE, 2319 mechset, 2320 GSS_C_INITIATE, 2321 handle, 2322 NULL, NULL); 2323 2324 if (maj == GSS_S_COMPLETE) { 2325 Info("Using default credential %p\n", (void *) *handle); 2326 } else { 2327 Info("Using null credential\n"); 2328 *handle = GSS_C_NO_CREDENTIAL; 2329 maj = GSS_S_COMPLETE; 2330 } 2331done: 2332 if (mechset != GSS_C_NULL_OID_SET) 2333 (void) gss_release_oid_set(&min, &mechset); 2334 if (gname != GSS_C_NO_NAME) 2335 (void) gss_release_name(&min, &gname); 2336 free(princ_name); 2337 free(oid_nt); 2338 2339 return (maj); 2340} 2341 2342/* 2343 * gssd_context type and routines to hold the underlying gss context as well 2344 * as the service name 2345 * 2346 * The reason we do this is on the initial call to gss_init_sec_context is that the 2347 * service name can generate up to two extra service names to try. 2348 * See str_to_svc_names above. Now we need to store the found name 2349 * where we can retrieve it on the next call if we return CONTINUE_NEEDED and 2350 * an easy way to do that is to construct our own context data structure to wrap 2351 * the real gss context and the service name used. 2352 * 2353 * You might be wondering why not just call str_to_svc_names again and not 2354 * worry about another level of context wrapping. Apart from the added work 2355 * of generating the candidate names and finding the "right" name again when we go 2356 * through the loop calling gss_init_sec_context, it won't work unless the first 2357 * name is the chosen name. When we pass in the address of the context to 2358 * gss_init_sec_context, on error gss will happily delete the context and set 2359 * our context now to be GSS_C_NO_CONTEXT. 2360 * 2361 * So let us say we generate 3 candidate service names and the second one will actually 2362 * work. The first time around gss_init_sec_context will fail and set our passed 2363 * in context to GSS_C_NO_CONTEXT and on the second call succeed, but 2364 * gss_init_sec_context will think this is an initial context (since the context 2365 * is NULL) and create a new one and return to the caller CONTINUE_NEEDED. Oops 2366 * we're in an infinite loop at this point, since the server will receive a valid 2367 * initial token and around we go. 2368 */ 2369typedef struct { 2370 gss_ctx_id_t gss_cntx; 2371 gss_name_t svc_name; 2372 vproc_transaction_t trans_handle; 2373} gssd_context, *gssd_context_t; 2374 2375static gssd_ctx 2376gssd_set_context(gss_ctx_id_t ctx, gss_name_t svc_name) 2377{ 2378 gssd_context_t g; 2379 2380 g = malloc(sizeof (gssd_context)); 2381 if (g == NULL) 2382 return (CAST(gssd_ctx, GSS_C_NO_CONTEXT)); 2383 gssd_enter(g); 2384 2385 g->gss_cntx = ctx; 2386 g->svc_name = svc_name; 2387 g->trans_handle = vproc_transaction_begin(NULL); 2388 2389 return (CAST(gssd_ctx, g)); 2390} 2391 2392static gss_ctx_id_t 2393gssd_get_context(gssd_ctx ctx, gss_name_t *svc_name) 2394{ 2395 gssd_context_t g; 2396 gss_ctx_id_t gss_context; 2397 2398 if (!ctx) { 2399 if (svc_name) 2400 *svc_name = GSS_C_NO_NAME; 2401 return (GSS_C_NO_CONTEXT); 2402 } 2403 g = CAST(gssd_context_t, ctx); 2404 if (svc_name) 2405 *svc_name = g->svc_name; 2406 gss_context = g->gss_cntx; 2407 vproc_transaction_end(NULL, g->trans_handle); 2408 gssd_remove(g); 2409 free(g); 2410 2411 return (gss_context); 2412} 2413 2414#define MAX_SVC_NAMES 3 2415 2416static uint32_t 2417svc_mach_gss_init_sec_context_common( 2418 gssd_mechtype mech, 2419 gssd_byte_buffer itoken, mach_msg_type_number_t itokenCnt, 2420 gss_name_t svcid, 2421 uint32_t flags, 2422 uint32_t *gssd_flags, 2423 gss_ctx_id_t *context, 2424 gss_cred_id_t cred_handle, 2425 uint32_t *ret_flags, 2426 gssd_byte_buffer *skey, mach_msg_type_number_t *skeyCnt, 2427 gssd_byte_buffer *otoken, mach_msg_type_number_t *otokenCnt, 2428 gssd_dstring displayname, 2429 uint32_t *minor_stat) 2430{ 2431 gss_buffer_desc intoken = {itokenCnt, itoken}; 2432 gss_buffer_desc outtoken = {0, NULL}; 2433 gss_buffer_desc name_buf; 2434 gss_name_t source; 2435 gss_OID mech_oid; 2436 uint32_t major_stat; 2437 uint32_t major, minor; 2438 uint32_t __unused in_gssd_flags = *gssd_flags; 2439 2440 DEBUG(2, "Using mech = %d\n", mech); 2441 DEBUG(3, "\tcred_handle = %p\n", cred_handle); 2442 DEBUG(3, "\tgss_context = %p\n", context); 2443 DEBUG(2, "itokenCnt = %d\n", itokenCnt); 2444 HEXDUMP(2, (char *)itoken, (itokenCnt > 80) ? 80 : itokenCnt); 2445 if (die) { 2446 DEBUG(2, "Forced server death\n"); 2447 _exit(0); 2448 } 2449 2450 *gssd_flags = 0; 2451 2452#ifdef WIN2K_HACK 2453 if ((in_gssd_flags & GSSD_WIN2K_HACK) && itokenCnt > 0) 2454 spnego_win2k_hack(&intoken); 2455#endif 2456 2457 major_stat = gss_init_sec_context( 2458 minor_stat, 2459 cred_handle, /* User's credential handle */ 2460 context, /* Context handle */ 2461 svcid, /* Target name */ 2462 mechtab[mech], /* Use the requested mech */ 2463 flags, /* Request flag bits */ 2464 0, /* Time requirement */ 2465 NULL, /* Channel bindings */ 2466 &intoken, /* Token from context acceptor */ 2467 &mech_oid, /* Actual mech types */ 2468 &outtoken, /* Token for the context acceptor */ 2469 ret_flags, /* Returned flag bits */ 2470 NULL); /* Time valid */ 2471 2472 vm_alloc_buffer(&outtoken, otoken, otokenCnt); 2473 gss_release_buffer(&minor, &outtoken); 2474 2475 if (major_stat == GSS_S_COMPLETE) { 2476 /* 2477 * If requeseted return a display representation to the caller. 2478 */ 2479 if (displayname) { 2480 major = gss_inquire_context(&minor, *context, &source, 2481 NULL, NULL, NULL, NULL, NULL, NULL); 2482 if (major == GSS_S_COMPLETE) { 2483 major = gss_display_name(&minor, source, &name_buf, NULL); 2484 if (major == GSS_S_COMPLETE) { 2485 char *s = buf_to_str(&name_buf); 2486 strlcpy(displayname, s, MAX_DISPLAY_STR); 2487 free(s); 2488 } 2489 } 2490 } 2491 2492 if (gss_oid_equal(mech_oid, GSS_NTLM_MECHANISM)) { 2493 gss_buffer_set_t data; 2494 2495 major = gss_inquire_sec_context_by_oid(&minor, *context, GSS_C_NTLM_GUEST, &data); 2496 if (major == GSS_S_COMPLETE) { 2497 uint32_t guest_flag = *(uint32_t *)data->elements->value; 2498 if (guest_flag) { 2499 *gssd_flags |= GSSD_GUEST_ONLY; 2500 DEBUG(3, "\tContext is NTLM simple file sharing %x\n", guest_flag); 2501 } else { 2502 DEBUG(3, "\tContext is NOT NTLM simple file sharing\n"); 2503 } 2504 (void) gss_release_buffer_set(&minor, &data); 2505 } else { 2506 Info("gss_inquire_sec_context_by_oid returned %K; %#k", major, mechtab[mech], minor); 2507 } 2508 } 2509 2510 /* 2511 * Fetch the (sub)session key from the context 2512 */ 2513 major_stat = GetSessionKey(minor_stat, mech_oid, context, 2514 skey, skeyCnt); 2515 2516 DEBUG(2, "Client key: length = %d\n", *skeyCnt); 2517 HEXDUMP(2, (char *) *skey, *skeyCnt); 2518 } 2519 2520 2521 OSAtomicIncrement32(&initCnt); 2522 if (major_stat != GSS_S_CONTINUE_NEEDED && major_stat != GSS_S_COMPLETE) 2523 OSAtomicIncrement32(&initErr); 2524 2525 DEBUG(3, "cred = %p\n", cred_handle); 2526 DEBUG(3, "\tgss_context = %p\n", *context); 2527 DEBUG(2, "%sotokenCnt = %d\n", get_debug_level() > 2 ? "\t" : "", *otokenCnt); 2528 HEXDUMP(2, (char *)*otoken, (*otokenCnt > 80) ? 80 : *otokenCnt); 2529 DEBUG(3, "Returning from init %d errors out of a total %d calls\n", initErr, initCnt); 2530 2531 2532 2533 return (major_stat); 2534} 2535 2536/* 2537 * Mig dispatch routine for gss_init_sec_context. 2538 */ 2539kern_return_t 2540svc_mach_gss_init_sec_context( 2541 mach_port_t server, 2542 gssd_mechtype mech, 2543 gssd_byte_buffer itoken, mach_msg_type_number_t itokenCnt, 2544 uint32_t uid, 2545 gssd_string princ_namestr, 2546 gssd_string svc_namestr, 2547 uint32_t flags, 2548 uint32_t gssd_flags, 2549 gssd_ctx *gss_context, 2550 gssd_cred *cred_handle, 2551 audit_token_t atok, 2552 uint32_t *ret_flags, 2553 gssd_byte_buffer *skey, mach_msg_type_number_t *skeyCnt, 2554 gssd_byte_buffer *otoken, mach_msg_type_number_t *otokenCnt, 2555 uint32_t *major_stat, 2556 uint32_t *minor_stat) 2557{ 2558 kern_return_t kstat; 2559 2560 kstat = svc_mach_gss_init_sec_context_v2(server, 2561 mech, 2562 itoken, 2563 itokenCnt, 2564 uid, 2565 GSSD_STRING_NAME, 2566 (gssd_byte_buffer) princ_namestr, 2567 (uint32_t) strlen(princ_namestr) + 1, 2568 GSSD_STRING_NAME, 2569 (gssd_byte_buffer) svc_namestr, 2570 (uint32_t) strlen(svc_namestr) + 1, 2571 flags, 2572 &gssd_flags, 2573 gss_context, 2574 cred_handle, 2575 atok, 2576 ret_flags, 2577 skey, 2578 skeyCnt, 2579 otoken, 2580 otokenCnt, 2581 NULL, 2582 major_stat, 2583 minor_stat); 2584 return (kstat); 2585} 2586 2587kern_return_t 2588svc_mach_gss_init_sec_context_v2( 2589 mach_port_t server __attribute__((unused)), 2590 gssd_mechtype mech, 2591 gssd_byte_buffer itoken, 2592 mach_msg_type_number_t itokenCnt, 2593 uint32_t uid, 2594 gssd_nametype clnt_nt, 2595 gssd_byte_buffer clnt_princ, 2596 mach_msg_type_number_t clnt_princCnt, 2597 gssd_nametype svc_nt, 2598 gssd_byte_buffer svc_princ, 2599 mach_msg_type_number_t svc_princCnt, 2600 uint32_t flags, 2601 uint32_t *gssd_flags, 2602 gssd_ctx *gss_context, 2603 gssd_cred *cred_handle, 2604 audit_token_t atok, 2605 uint32_t *ret_flags, 2606 gssd_byte_buffer *skey, 2607 mach_msg_type_number_t *skeyCnt, 2608 gssd_byte_buffer *otoken, 2609 mach_msg_type_number_t *otokenCnt, 2610 gssd_dstring displayname, 2611 uint32_t *major_stat, 2612 uint32_t *minor_stat) 2613{ 2614 gss_name_t svc_gss_name[MAX_SVC_NAMES]; 2615 gss_ctx_id_t g_cntx = GSS_C_NO_CONTEXT; 2616 uint32_t i, gnames = MAX_SVC_NAMES, name_index = MAX_SVC_NAMES; 2617 uint32_t mstat; /* Minor status for cleaning up. */ 2618 vproc_transaction_t gssd_vproc_handle; 2619 uint32_t only_1des = ((*gssd_flags & GSSD_NFS_1DES) != 0); 2620 kern_return_t kr = KERN_SUCCESS; 2621 2622 DEBUG(2, "Enter"); 2623 2624 gssd_vproc_handle = vproc_transaction_begin(NULL); 2625 new_worker_thread(); 2626 2627 if (!check_audit(atok, FALSE)) { 2628 kr = KERN_NO_ACCESS; 2629 goto out; 2630 } 2631 2632 krb5_set_home_dir_access(NULL, (*gssd_flags & GSSD_HOME_ACCESS_OK) ? 1 : 0); 2633 2634 if (displayname) 2635 *displayname = '\0'; 2636 2637 if (!gssd_check(CAST(void *, *gss_context)) || !gssd_check(CAST(void *, *cred_handle))) { 2638 *major_stat = badcall("svc_mach_gss_init_context", 2639 minor_stat, gss_context, cred_handle, 2640 gssd_flags, 2641 skey, skeyCnt, 2642 otoken, otokenCnt); 2643 2644 kr = KERN_SUCCESS; 2645 goto out; 2646 } 2647 2648 if (*gss_context == CAST(gssd_ctx, GSS_C_NO_CONTEXT)) { 2649 2650 if (no_canon || (*gssd_flags & GSSD_NO_CANON)) 2651 gnames = 1; 2652 *major_stat = blob_to_svcnames(minor_stat, svc_nt, svc_princ, svc_princCnt, 2653 mech, svc_gss_name, &gnames); 2654 2655 if (*major_stat != GSS_S_COMPLETE) { 2656 Info("Could not determine service principal name: %#K", *major_stat); 2657 goto done; 2658 } 2659 2660 if (gnames > 1) 2661 Info("Trying the following server principal names:"); 2662 for (i = 0; i < gnames; i++) { 2663 char *dname; 2664 gss_buffer_desc bufname; 2665 uint32_t maj, min; 2666 gss_OID oid; 2667 char *oname; 2668 2669 maj = gss_display_name(&min, svc_gss_name[i], &bufname, &oid); 2670 if (maj != GSS_S_COMPLETE) 2671 Info("Cannot determine target name: %K", maj); 2672 else { 2673 dname = buf_to_str(&bufname); 2674 oname = oid_name(oid); 2675 Info("%s %s as %s", (gnames > 1)? "\t" : "Server principal name", dname, oname); 2676 free(dname); 2677 free(oname); 2678 } 2679 } 2680 2681 } 2682 else { 2683 gnames = 1; 2684 g_cntx = gssd_get_context(*gss_context, svc_gss_name); 2685 if ((*gssd_flags & GSSD_RESTART) && g_cntx != GSS_C_NO_CONTEXT) 2686 (void) gss_delete_sec_context(&mstat, &g_cntx, GSS_C_NO_BUFFER); 2687 } 2688 if (*cred_handle && (*gssd_flags & GSSD_RESTART)) { 2689 gssd_remove(CAST(void *, *cred_handle)); 2690 (void) gss_release_cred(&mstat, (gss_cred_id_t *) cred_handle); 2691 } 2692 if (CAST(gss_cred_id_t, *cred_handle) == GSS_C_NO_CREDENTIAL || (*gssd_flags & GSSD_RESTART)) { 2693 if (clnt_nt == GSSD_STRING_NAME) 2694 *major_stat = do_acquire_cred_v1(minor_stat, (char *)clnt_princ, mech, 2695 *svc_gss_name, uid, cred_handle, *gssd_flags); 2696 else { 2697 *major_stat = do_acquire_cred(minor_stat, clnt_nt, 2698 clnt_princ, clnt_princCnt, 2699 mech, (gss_cred_id_t *) cred_handle); 2700 } 2701 if (*major_stat != GSS_S_COMPLETE) 2702 goto done; 2703 /* ??? 2704 * Currently NFS only supports a subset of the Kerberos enctypes 2705 * and only suports the kerberos mech. If using a non kerberos 2706 * credential, gss_krb5_set_allowable_enctypes will fail. 2707 */ 2708 if (is_nfs_service(*svc_gss_name)) { 2709 *major_stat = gss_krb5_set_allowable_enctypes 2710 (minor_stat, *(gss_cred_id_t *)cred_handle, 2711 NUM_NFS_ENCTYPES - only_1des, NFS_ENCTYPES); 2712 if (*major_stat != GSS_S_COMPLETE) { 2713 Log("Could not set enctypes for NFS\n"); 2714 goto done; 2715 } 2716 } 2717 gssd_enter(CAST(void *, *cred_handle)); 2718 } 2719 2720 *major_stat = GSS_S_BAD_NAME; 2721 for (i = 0; i < gnames; i++) { 2722 2723 *major_stat = svc_mach_gss_init_sec_context_common( 2724 mech, 2725 itoken, 2726 itokenCnt, 2727 svc_gss_name[i], 2728 flags, 2729 gssd_flags, 2730 &g_cntx, 2731 CAST(gss_cred_id_t, *cred_handle), 2732 ret_flags, 2733 skey, 2734 skeyCnt, 2735 otoken, 2736 otokenCnt, 2737 displayname, 2738 minor_stat); 2739 2740 2741 if (*major_stat == GSS_S_COMPLETE || 2742 *major_stat == GSS_S_CONTINUE_NEEDED) 2743 break; 2744 } 2745 name_index = i; 2746 2747 /* Done with the names */ 2748 for (i = 0; i < gnames; i++) 2749 if (i != name_index) 2750 (void)gss_release_name(&mstat, &svc_gss_name[i]); 2751 2752 if (*major_stat == GSS_S_CONTINUE_NEEDED) { 2753 *gss_context = gssd_set_context(g_cntx, svc_gss_name[name_index]); 2754 if (*gss_context == 0) 2755 *major_stat = GSS_S_FAILURE; 2756 } 2757 2758done: 2759 Info("svc_mach_gss_init_sec_context_common %K; %#k", *major_stat, mechtab[mech], *minor_stat); 2760 if (*major_stat != GSS_S_CONTINUE_NEEDED) { 2761 /* We're done so free what we allocated */ 2762 gssd_remove(CAST(void *, *cred_handle)); 2763 (void) gss_release_cred(&mstat, (gss_cred_id_t *) cred_handle); 2764 if (g_cntx != GSS_C_NO_CONTEXT) 2765 (void) gss_delete_sec_context(&mstat, &g_cntx, GSS_C_NO_BUFFER); 2766 2767 if (name_index < gnames) 2768 (void)gss_release_name(&mstat, &svc_gss_name[name_index]); 2769 } 2770 2771out: 2772 end_worker_thread(); 2773 vproc_transaction_end(NULL, gssd_vproc_handle); 2774 2775 DEBUG(2, "Exit"); 2776 2777 return (kr); 2778 2779} 2780 2781/* 2782 * Mig dispatch routine for gss_accept_sec_context. 2783 */ 2784kern_return_t 2785svc_mach_gss_accept_sec_context( 2786 mach_port_t test_port, 2787 gssd_byte_buffer itoken, mach_msg_type_number_t itokenCnt, 2788 gssd_string svc_namestr, 2789 uint32_t gssd_flags, 2790 gssd_ctx *gss_context, 2791 gssd_cred *cred_handle, 2792 audit_token_t atok, 2793 uint32_t *ret_flags, 2794 uint32_t *uid, 2795 gssd_gid_list gids, mach_msg_type_number_t *gidsCnt, 2796 gssd_byte_buffer *skey, mach_msg_type_number_t *skeyCnt, 2797 gssd_byte_buffer *otoken, mach_msg_type_number_t *otokenCnt, 2798 uint32_t *major_stat, 2799 uint32_t *minor_stat) 2800{ 2801 kern_return_t kr; 2802 2803 kr = svc_mach_gss_accept_sec_context_v2(test_port, 2804 itoken, 2805 itokenCnt, 2806 GSSD_STRING_NAME, 2807 (gssd_byte_buffer)svc_namestr, 2808 (uint32_t) strlen(svc_namestr) + 1, 2809 &gssd_flags, 2810 gss_context, 2811 cred_handle, 2812 atok, 2813 ret_flags, 2814 uid, 2815 gids, 2816 gidsCnt, 2817 skey, 2818 skeyCnt, 2819 otoken, 2820 otokenCnt, 2821 major_stat, 2822 minor_stat); 2823 return (kr); 2824} 2825 2826kern_return_t 2827svc_mach_gss_accept_sec_context_v2( 2828 mach_port_t server __attribute__((unused)), 2829 gssd_byte_buffer itoken, 2830 mach_msg_type_number_t itokenCnt, 2831 gssd_nametype svc_nt __attribute__((unused)), 2832 gssd_byte_buffer svc_princ __attribute__((unused)), 2833 mach_msg_type_number_t svc_princCnt __attribute__((unused)), 2834 uint32_t *inout_gssd_flags __attribute__((unused)), 2835 gssd_ctx *gss_context, 2836 gssd_cred *cred_handle, 2837 audit_token_t atok, 2838 uint32_t *ret_flags, 2839 uint32_t *uid, 2840 gssd_gid_list gids, 2841 mach_msg_type_number_t *gidsCnt, 2842 gssd_byte_buffer *skey, 2843 mach_msg_type_number_t *skeyCnt, 2844 gssd_byte_buffer *otoken, 2845 mach_msg_type_number_t *otokenCnt, 2846 uint32_t *major_stat, 2847 uint32_t *minor_stat) 2848{ 2849 gss_ctx_id_t g_cntx = GSS_C_NO_CONTEXT; 2850 gss_name_t princ; 2851 gss_OID oid; 2852 uint32_t mstat; /* Minor status to clean up with. */ 2853 kern_return_t kr = KERN_SUCCESS; 2854 vproc_transaction_t gssd_vproc_handle; 2855 2856 DEBUG(2, "Enter"); 2857 gssd_vproc_handle = vproc_transaction_begin(NULL); 2858 new_worker_thread(); 2859 2860 if (!check_audit(atok, FALSE)) { 2861 kr = KERN_NO_ACCESS; 2862 goto out; 2863 } 2864 2865 krb5_set_home_dir_access(NULL, ((*inout_gssd_flags) & GSSD_HOME_ACCESS_OK) ? 1 : 0); 2866 2867 *inout_gssd_flags = 0; 2868 2869 /* Set the uid to nobody to be safe */ 2870 *uid = NobodyUid; 2871 2872 if (die) { 2873 DEBUG(2, "Forced server death\n"); 2874 _exit(0); 2875 } 2876 2877 if (!gssd_check(CAST(void *, *gss_context)) || !gssd_check(CAST(void *, *cred_handle))) { 2878 *major_stat = badcall("svc_mach_gss_accept_sec_context", 2879 minor_stat, gss_context, cred_handle, 2880 inout_gssd_flags, 2881 skey, skeyCnt, otoken, otokenCnt); 2882 2883 end_worker_thread(); 2884 vproc_transaction_end(NULL, gssd_vproc_handle); 2885 2886 return (KERN_SUCCESS); 2887 } 2888 2889 g_cntx = gssd_get_context(*gss_context, NULL); 2890 gss_buffer_desc intoken = {itokenCnt, itoken}; 2891 gss_buffer_desc outtoken = {0, NULL};; 2892 *major_stat = 0; 2893 *minor_stat = 0; 2894 2895 DEBUG(4, "minor_stat = %d\n", (int) *minor_stat); 2896 DEBUG(4, "\tcred = %p\n", (void *)(uintptr_t)*cred_handle); 2897 DEBUG(4, "\tgss_context = %p\n", g_cntx); 2898 DEBUG(3, "itokenCnt = %d\n", itokenCnt); 2899 HEXDUMP(3, (char *)itoken, (itokenCnt > 80) ? 80 : itokenCnt); 2900 2901 *major_stat = gss_accept_sec_context( 2902 minor_stat, 2903 &g_cntx, // Context handle 2904 CAST(gss_cred_id_t, *cred_handle), // Acceptor's credential handle 2905 &intoken, // Token from context initiator 2906 GSS_C_NO_CHANNEL_BINDINGS, // Channel bindings 2907 &princ, // Context initiator's name 2908 &oid, // Mech types 2909 &outtoken, // Token for context initiator 2910 ret_flags, // Flags out 2911 NULL, // Time requirement 2912 NULL); // Delegated creds 2913 2914 vm_alloc_buffer(&outtoken, otoken, otokenCnt); 2915 gss_release_buffer(&mstat, &outtoken); 2916 2917 if (*major_stat == GSS_S_COMPLETE ) { 2918 /* 2919 * Turn the principal name into UNIX creds 2920 */ 2921 *major_stat = gss_name_to_ucred(minor_stat, princ, 2922 uid, gids, gidsCnt); 2923 if (*major_stat != GSS_S_COMPLETE) { 2924 kr = KERN_FAILURE; 2925 goto done; 2926 } 2927 /* 2928 * Fetch the (sub)session key from the context 2929 */ 2930 *major_stat = GetSessionKey(minor_stat, oid, &g_cntx, 2931 skey, skeyCnt); 2932 2933 DEBUG(2, "Server key length = %d\n", *skeyCnt); 2934 HEXDUMP(2, (char *) *skey, *skeyCnt); 2935 } else if (*major_stat == GSS_S_CONTINUE_NEEDED) { 2936 *gss_context = gssd_set_context(g_cntx, NULL); 2937 if (*gss_context == 0) 2938 *major_stat = GSS_S_FAILURE; 2939 2940 /* 2941 * Register our context handle 2942 */ 2943 gssd_enter(CAST(void *, *gss_context)); 2944 } 2945 if (*major_stat == GSS_S_COMPLETE || *major_stat == GSS_S_CONTINUE_NEEDED) { 2946 DEBUG(3, "otokenCnt = %d", *otokenCnt); 2947 HEXDUMP(3, (char *)*otoken, (*otokenCnt > 80) ? 80 : *otokenCnt); 2948 } 2949done: 2950 gss_release_name(&mstat, &princ); 2951 if (*major_stat != GSS_S_CONTINUE_NEEDED) { 2952 gssd_remove(CAST(void *, *cred_handle)); 2953 (void)gss_release_cred(&mstat, (gss_cred_id_t *) cred_handle); 2954 if (g_cntx != GSS_C_NO_CONTEXT) 2955 (void) gss_delete_sec_context(&mstat, &g_cntx, GSS_C_NO_BUFFER); 2956 } 2957 2958 OSAtomicIncrement32(&acceptCnt); 2959 if (*major_stat != GSS_S_CONTINUE_NEEDED && *major_stat != GSS_S_COMPLETE) 2960 OSAtomicIncrement32(&acceptErr); 2961 DEBUG(3, "Returning from accept %d erros of of %d total calls\n", acceptErr, acceptCnt); 2962 2963 Info("gss_accept_sec_context %K; %#k", *major_stat, oid, *minor_stat); 2964out: 2965 end_worker_thread(); 2966 vproc_transaction_end(NULL, gssd_vproc_handle); 2967 2968 DEBUG(2, "Exit"); 2969 2970 return (kr); 2971} 2972 2973 2974#define MSG(f, ...) do {\ 2975 if (f) { \ 2976 Debug(__VA_ARGS__); \ 2977 } else { \ 2978 Log(__VA_ARGS__); \ 2979 } \ 2980} while (0) 2981 2982 2983 2984/* 2985 * Mig dispatch routine to log GSS-API errors 2986 */ 2987kern_return_t 2988svc_mach_gss_log_error( 2989 mach_port_t test_port __attribute__((unused)), 2990 gssd_string mnt, 2991 uint32_t uid, 2992 gssd_string source, 2993 uint32_t major, 2994 uint32_t minor, 2995 audit_token_t atok) 2996{ 2997 OM_uint32 msg_context = 0; 2998 OM_uint32 min_stat = 0; 2999 OM_uint32 maj_stat = 0; 3000 gss_buffer_desc errBuf; 3001 char msgbuf[1024]; 3002 char *errStr; 3003 int full = 0; 3004 vproc_transaction_t gssd_vproc_handle; 3005 kern_return_t kr = KERN_SUCCESS; 3006 3007 DEBUG(2, "Enter"); 3008 gssd_vproc_handle = vproc_transaction_begin(NULL); 3009 new_worker_thread(); 3010 3011 if (!check_audit(atok, FALSE)) { 3012 kr = KERN_NO_ACCESS; 3013 goto out; 3014 } 3015 3016 (void) snprintf(msgbuf, sizeof(msgbuf), "nfs %s Kerberos: %s, uid=%d", 3017 source, mnt, uid); 3018 3019 /* 3020 * Start with the major error string(s) 3021 * The strings are concatenated into a fixed size log 3022 * message buffer. If the messages exceed the buffer 3023 * size then we truncate. 3024 */ 3025 do { 3026 if (major == GSS_S_FAILURE) // more info in minor msg 3027 break; 3028 maj_stat = gss_display_status(&min_stat, major, GSS_C_GSS_CODE, 3029 GSS_C_NULL_OID, &msg_context, &errBuf); 3030 errStr = buf_to_str(&errBuf); 3031 if (maj_stat != GSS_S_COMPLETE) 3032 goto done; 3033 full = strlcat(msgbuf, " - ", sizeof(msgbuf)) >= sizeof(msgbuf) || 3034 strlcat(msgbuf, errStr, sizeof(msgbuf)) >= sizeof(msgbuf); 3035 free(errStr); 3036 if (full) 3037 goto done; 3038 } while (msg_context != 0); 3039 3040 /* 3041 * Append any minor error string(s) 3042 */ 3043 msg_context = 0; 3044 do { 3045 maj_stat = gss_display_status (&min_stat, minor, GSS_C_MECH_CODE, 3046 GSS_C_NULL_OID, &msg_context, &errBuf); 3047 errStr = buf_to_str(&errBuf); 3048 if (maj_stat != GSS_S_COMPLETE) 3049 goto done; 3050 full = strlcat(msgbuf, " - ", sizeof(msgbuf)) >= sizeof(msgbuf) || 3051 strlcat(msgbuf, errStr, sizeof(msgbuf)) >= sizeof(msgbuf); 3052 free(errStr); 3053 if (full) 3054 goto done; 3055 } while (msg_context != 0); 3056 3057done: 3058 MSG((major == GSS_S_NO_CRED), "%s", msgbuf); 3059 3060out: 3061 end_worker_thread(); 3062 vproc_transaction_end(NULL, gssd_vproc_handle); 3063 3064 return (kr); 3065} 3066 3067kern_return_t 3068svc_mach_gss_hold_cred(mach_port_t server __unused, 3069 gssd_mechtype mech, 3070 gssd_nametype nt, 3071 gssd_byte_buffer princ, 3072 mach_msg_type_number_t princCnt, 3073 audit_token_t atok, 3074 uint32_t *major_stat, 3075 uint32_t *minor_stat) 3076{ 3077 gss_cred_id_t cred = NULL; 3078 uint32_t m; 3079 vproc_transaction_t gssd_vproc_handle; 3080 kern_return_t kr = KERN_SUCCESS; 3081 3082 DEBUG(2, "Enter"); 3083 gssd_vproc_handle = vproc_transaction_begin(NULL); 3084 new_worker_thread(); 3085 3086 if (!check_audit(atok, FALSE)) { 3087 kr = KERN_NO_ACCESS; 3088 goto out; 3089 } 3090 3091 *major_stat = do_acquire_cred(minor_stat, nt, princ, princCnt, mech, &cred); 3092 if (*major_stat != GSS_S_COMPLETE) 3093 goto out; 3094 *major_stat = gss_cred_hold(minor_stat, cred); 3095 (void) gss_release_cred(&m, &cred); 3096 3097out: 3098 end_worker_thread(); 3099 vproc_transaction_end(NULL, gssd_vproc_handle); 3100 3101 return (kr); 3102} 3103 3104kern_return_t 3105svc_mach_gss_unhold_cred(mach_port_t server __unused, 3106 gssd_mechtype mech, 3107 gssd_nametype nt, 3108 gssd_byte_buffer princ, 3109 mach_msg_type_number_t princCnt, 3110 audit_token_t atok, 3111 uint32_t *major_stat, 3112 uint32_t *minor_stat) 3113{ 3114 gss_cred_id_t cred = NULL; 3115 uint32_t m; 3116 vproc_transaction_t gssd_vproc_handle; 3117 kern_return_t kr = KERN_SUCCESS; 3118 3119 DEBUG(2, "Enter"); 3120 gssd_vproc_handle = vproc_transaction_begin(NULL); 3121 new_worker_thread(); 3122 3123 if (!check_audit(atok, FALSE)) { 3124 kr = KERN_NO_ACCESS; 3125 goto out; 3126 } 3127 3128 *major_stat = do_acquire_cred(minor_stat, nt, princ, princCnt, mech, &cred); 3129 if (*major_stat != GSS_S_COMPLETE) 3130 goto out; 3131 *major_stat = gss_cred_unhold(minor_stat, cred); 3132 (void) gss_release_cred(&m, &cred); 3133 3134out: 3135 end_worker_thread(); 3136 vproc_transaction_end(NULL, gssd_vproc_handle); 3137 return (kr); 3138} 3139 3140kern_return_t 3141svc_mach_gss_lookup(mach_port_t server, 3142 uint32_t uid, 3143 int32_t asid, 3144 audit_token_t atok, 3145 mach_port_t *gssd_port) 3146{ 3147 kern_return_t kr = KERN_SUCCESS; 3148 uuid_t uuid; 3149 uuid_string_t uuidstr; 3150 vproc_transaction_t gssd_vproc_handle; 3151 3152 DEBUG(2, "Enter"); 3153 gssd_vproc_handle = vproc_transaction_begin(NULL); 3154 new_worker_thread(); 3155 3156 if (!check_audit(atok, kernel_only)) { 3157 kr = KERN_NO_ACCESS; 3158 goto out; 3159 } 3160 3161 *gssd_port = MACH_PORT_NULL; 3162 if (!check_session(asid)) { 3163 *gssd_port = server; 3164 } else { 3165 sessioninfo2uuid((uid_t)uid, (au_asid_t)asid, uuid); 3166 uuid_unparse(uuid, uuidstr); 3167 DEBUG(2, "Looking up %s for %d %d as instance %s", bname, uid, asid, uuidstr); 3168 3169 kr = bootstrap_look_up3(bootstrap_port, bname, gssd_port, 0, uuid, BOOTSTRAP_SPECIFIC_INSTANCE); 3170 if (kr != KERN_SUCCESS) 3171 Log("Could not lookup per instance port %d: %s", kr, bootstrap_strerror(kr)); 3172 3173 DEBUG(2, "bootstap_look_up3 = %d port = %d, server port = %d", kr, *gssd_port, server); 3174 } 3175out: 3176 end_worker_thread(); 3177 vproc_transaction_end(NULL, gssd_vproc_handle); 3178 return (kr); 3179} 3180