1/*
2 * Copyright (c) 2006-2014 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)))
125extern int ctx_counter;
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	DEBUG(2, "Total entries left = %d\n", ctx_counter);
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
740	return (0);
741}
742
743static int
744get_local_realms(krb5_realm **realms)
745{
746	int error;
747	krb5_context kctx;
748
749	if (realms == NULL)
750		return (FALSE);
751	*realms = NULL;
752	error = krb5_init_context(&kctx);
753	if (error) {
754		Log("Could not get kerberos context");
755		krb5_free_context(kctx);
756		return (FALSE);
757	}
758	error = krb5_get_default_realms(kctx, realms);
759	krb5_free_context(kctx);
760	if (error) {
761		Log("Could not get kerbose default realms");
762		return (FALSE);
763	}
764	return (TRUE);
765}
766
767static void
768free_local_realms(krb5_realm *realms)
769{
770	int error;
771	krb5_context kctx;
772
773	if (realms == NULL)
774		return;
775
776	error = krb5_init_context(&kctx);
777	if (error) {
778		Log("Could not get kerberos context");
779		return;
780	}
781	(void )krb5_free_host_realm(kctx, realms);
782	krb5_free_context(kctx);
783}
784
785/*
786 * Given a uid and name type convert it to a gss_name_t
787 */
788static uint32_t
789uid_to_gss_name(uint32_t *minor, uid_t uid, gss_OID oid, gss_name_t *name)
790{
791	char pwbuf[GetPWMaxRSz];
792	struct passwd *pwd, pwent;
793	char *princ_str;
794	gss_buffer_desc buf_name;
795	uint32_t major;
796	size_t len;
797	size_t realmlen;
798	krb5_realm *realms = NULL;
799	krb5_realm default_realm = NULL;
800	int rc;
801
802	*minor = 0;
803
804	rc  = getpwuid_r(uid, &pwent, pwbuf, sizeof(pwbuf), &pwd);
805	if (rc != 0 || pwd == NULL)
806		return (GSS_S_UNAUTHORIZED);
807
808	if (get_local_realms(&realms))
809		default_realm = *realms;
810
811	realmlen = default_realm ? strlen(default_realm)  : 0;
812	len = strlen(pwd->pw_name) + 1 + realmlen + 1;
813	len = maximum(len, 10);  /* max string rep for uids */
814	len = maximum(len, 5 + strlen(local_host) + 1 + realmlen + 1);
815	if ((princ_str = malloc(len)) == NULL) {
816		free_local_realms(realms);
817		return (GSS_S_FAILURE);
818	}
819	if (gss_oid_equal(oid, GSS_KRB5_NT_PRINCIPAL_NAME)) {
820		if (pwd->pw_uid == 0) {
821			/* use the host principal */
822			if (default_realm)
823				snprintf(princ_str, len,
824					 "host/%s@%s", local_host, default_realm);
825			else
826				snprintf(princ_str, len, "host/%s", local_host);
827		} else {
828			if (default_realm)
829				snprintf(princ_str, len,
830					 "%s@%s", pwd->pw_name, default_realm);
831			else
832				snprintf(princ_str, len, "%s", pwd->pw_name);
833		}
834	}
835	else if (gss_oid_equal(oid, GSS_C_NT_USER_NAME))
836		snprintf(princ_str, len, "%s", pwd->pw_name);
837	else if (gss_oid_equal(oid, GSS_C_NT_STRING_UID_NAME))
838		snprintf(princ_str, len, "%d", pwd->pw_uid);
839	else if (gss_oid_equal(oid, GSS_C_NT_MACHINE_UID_NAME))
840		memcpy(princ_str, &pwd->pw_uid, sizeof(pwd->pw_uid));
841	else if (gss_oid_equal(oid, GSS_C_NT_HOSTBASED_SERVICE) && pwd->pw_uid == 0)
842		snprintf(princ_str, len, "host@%s", local_host);
843	else {
844		free(princ_str);
845		free_local_realms(realms);
846		return (GSS_S_FAILURE);
847	}
848
849	str_to_buf(princ_str, &buf_name);
850
851	DEBUG(2, "importing name %s\n", princ_str);
852
853	major = gss_import_name(minor, &buf_name, oid, name);
854
855	free(princ_str);
856	free_local_realms(realms);
857
858	return (major);
859}
860
861/*
862 * get_next_kerb_component. Get the next kerberos component from string.
863 */
864static char *
865get_next_kerb_component(char *str)
866{
867	char *s, *p;
868
869	/*
870	 * Its possible to include "/" and "@" in the leading
871	 * components of a kerberos principal name if they
872	 * are back slashed escaped, as in, fo\/o\@@realm.
873	 */
874
875	s = str;
876	do {
877		p = strpbrk(s, "/@\\");
878		s = (p && *p == '\\' && *(p+1)) ? p + 2 : NULL;
879	} while (s);
880
881	return (p);
882}
883
884
885/*
886 * getucred: Given a user name return the corresponding uid and gid list.
887 * Note the first gid in the list is the principal (passwd entry) gid.
888 *
889 * Return: True on success of False on failure. Note on failure, *uid and *gid
890 * are set to nobody and *ngroups is set to 1.
891 */
892static bool
893getucred(const char *uname, uid_t *uid, gid_t *gids, uint32_t *ngroups)
894{
895	struct passwd *pwd, pwent;
896	char pwdbuf[GetPWMaxRSz];
897	*uid = NobodyUid;
898	*gids = NobodyGid;
899	*ngroups = 1;
900
901	(void) getpwnam_r(uname, &pwent, pwdbuf, sizeof(pwdbuf), &pwd);
902	if (pwd) {
903		*uid = pwd->pw_uid;
904		*ngroups = NGROUPS_MAX;
905		if (getgrouplist(uname, pwd->pw_gid,
906			(int *)gids, (int *)ngroups) == -1) {
907			/* Best we can do is just return the principal gid */
908			*gids = pwd->pw_gid;
909			*ngroups = 1;
910		}
911		return (true);
912	}
913	return (false);
914}
915
916/*
917 * Given a gss_name_t convert it to a local uid. We use an optional list
918 * of kerberos realm names to try if name can't be resolve to a passwd
919 * entry directly after converting it to a display name.
920 */
921static uint32_t
922gss_name_to_ucred_1(uint32_t *minor, gss_name_t name,
923		    uid_t *uid, gid_t *gids, uint32_t *ngroups)
924{
925	uint32_t major;
926	char *name_str = NULL;
927	gss_buffer_desc buf;
928	gss_OID oid = GSS_C_NO_OID;
929	char **rlm, *this_realm, *uname;
930	bool gotname;
931	krb5_realm *realms = NULL;
932
933	*minor = 0;
934
935	/*
936	 * Convert name to text string and fetch the name type.
937	 */
938	major = gss_display_name(minor, name, &buf, &oid);
939	if (major != GSS_S_COMPLETE)
940		return (major);
941
942	name_str = buf_to_str(&buf);
943	if (name_str == NULL)
944		return (GSS_S_FAILURE);
945
946	uname = name_str;
947
948	/*
949	 * See if we get lucky and the string version of the name
950	 * can be found.
951	 */
952
953	if ((gotname = getucred(uname, uid, gids, ngroups)))
954		goto out;
955
956	if (gss_oid_equal(oid, GSS_KRB5_NT_PRINCIPAL_NAME)) {
957		/*
958		 * If we failed the above lookup and we're a kerberos name
959		 * and if the realm of the name is one of our local realms,
960		 * try looking up the first component and see if its a user we
961		 * know. We ignore any instance part here, i.e., we assume
962		 * user@realm and user/instance@realm are the same for all
963		 * instances.
964		 */
965		this_realm = strrchr(name_str, '@');
966		if (this_realm == NULL)
967			goto out;
968		this_realm++;
969		if (!get_local_realms(&realms))
970			goto out;
971		for(rlm = realms; rlm && *rlm; rlm++) {
972			if (strncmp(this_realm, *rlm, buf.length) == 0) {
973				char *p;
974
975				p = get_next_kerb_component(name_str);
976				if (p)
977					*p = '\0';
978
979				gotname = getucred(uname, uid, gids, ngroups);
980				goto out;
981			}
982		}
983	}
984out:
985	if (!gotname)
986		Log("Directory Service could not map %s to unix credentials. Directory Service problem?\n", uname);
987	else
988		Info("Directory Service mapped %s to uid %d", uname, *uid);
989
990	free(uname);
991	free_local_realms(realms);
992
993	return (uint32_t)(gotname ? GSS_S_COMPLETE : GSS_S_FAILURE);
994}
995
996/*
997 * Given a gss_name_t convert it to a local uid.
998 */
999static uint32_t
1000gss_name_to_ucred(uint32_t *min, gss_name_t name,
1001		  uid_t *uid, gid_t *gids, uint32_t *ngroups)
1002{
1003	uint32_t maj, ms;
1004	gss_buffer_desc xname;
1005	uuid_t uu;
1006	int ret;
1007	int type;
1008	struct passwd *pwd, pwent;
1009	char pwdbuf[GetPWMaxRSz];
1010	*uid = NobodyUid;
1011	*gids = NobodyGid;
1012	*ngroups = 1;
1013
1014	maj = gss_export_name(min, name, &xname);
1015	if (maj != GSS_S_COMPLETE)
1016		return (maj);
1017
1018	ret = mbr_identifier_to_uuid(ID_TYPE_GSS_EXPORT_NAME, xname.value, xname.length, uu);
1019	(void) gss_release_buffer(&ms, &xname);
1020
1021	if (ret) {
1022		DEBUG(2, "mbr_identifier_to_uid: failed to map export name to uuid: reason %d\n", ret);
1023		return (gss_name_to_ucred_1(min, name, uid, gids, ngroups));
1024	}
1025
1026	ret = mbr_uuid_to_id(uu, uid, &type);
1027	if (ret || type != ID_TYPE_UID) {
1028		Info("gssapi: failed to turn uuid into uid: %d", ret);
1029		return (GSS_S_FAILURE);
1030	}
1031
1032	ret = getpwuid_r(*uid, &pwent, pwdbuf, sizeof(pwdbuf), &pwd);
1033	if (ret) {
1034		Info("Look up of uid %d failed. Reason %d: %s\n", *uid, errno,
1035		     strerror(errno));
1036		return (GSS_S_FAILURE);
1037	}
1038
1039	if (pwd) {
1040		*ngroups = NGROUPS_MAX;
1041		if (getgrouplist(pwd->pw_name, pwd->pw_gid,
1042				 (int *)gids, (int *)ngroups) == -1) {
1043			/* Best we can do is just return the principal gid */
1044			*gids = pwd->pw_gid;
1045			*ngroups = 1;
1046		} else {
1047			DEBUG(2, "getgrouplist failed.\n");
1048		}
1049	} else {
1050		Log("Directory Service could not find uid %d.\n", *uid);
1051		return (GSS_S_FAILURE);
1052	}
1053
1054	return (GSS_S_COMPLETE);
1055}
1056
1057
1058static char *
1059lowercase(char *s)
1060{
1061	char *t;
1062
1063	for (t = s; t && *t; t++)
1064		*t = tolower(*t);
1065
1066	return (s);
1067}
1068
1069/*
1070 * Turn a hostname into a FQDN if we can. Optionally do the reverse lookup
1071 * and return it as well in the rfqdn parameter if it is different from the
1072 * forward  lookup. If that parameter is NULL,  don't try the reverse lookup.
1073 * at all. If the foward lookup fails we return NULL.
1074 * If we succeed it is the caller's responsibility to free the results.
1075 */
1076static char *
1077canonicalize_host(const char *host, char **rfqdn)
1078{
1079	struct hostent *hp, *rhp;
1080	int h_err;
1081	char *fqdn;
1082
1083	if (rfqdn)
1084		*rfqdn = NULL;
1085
1086	hp = getipnodebyname(host, AF_INET6, AI_DEFAULT, &h_err);
1087	if (hp == NULL) {
1088		DEBUG(2, "host look up for %s returned %d\n", host, h_err);
1089		return (NULL);
1090	}
1091	fqdn = strdup(lowercase(hp->h_name));
1092	if (fqdn == NULL) {
1093		Log("Could not allocat hostname in canonicalize_host\n");
1094		return (NULL);
1095	}
1096
1097	if (rfqdn) {
1098		DEBUG(2, "Trying reverse lookup\n");
1099		rhp = getipnodebyaddr(hp->h_addr_list[0], hp->h_length, AF_INET6, &h_err);
1100		if (rhp) {
1101			if (strncmp(fqdn, lowercase(rhp->h_name), MAXHOSTNAMELEN) != 0) {
1102				*rfqdn = strdup(rhp->h_name);
1103				if (*rfqdn == NULL)
1104					Log("Could not allocat hostname in canonicalize_host\n");
1105			}
1106			freehostent(rhp);
1107		}
1108		else {
1109			DEBUG(2, "reversed host look up for %s returned %d\n", host, h_err);
1110		}
1111	}
1112
1113	freehostent(hp);
1114
1115	return (fqdn);
1116}
1117
1118/*
1119 * Given the service name, host name and realm, construct the kerberos gss
1120 * service name.
1121 */
1122static uint32_t
1123construct_service_name(uint32_t *minor, const char *service, char *host,
1124		       const char *realm, bool lcase, gss_name_t *svcname)
1125{
1126	size_t len;
1127	char *s;
1128	gss_buffer_desc name_buf;
1129	uint32_t major;
1130
1131	if (lcase)
1132		lowercase(host);
1133	len = strlen(service) + strlen(host) + strlen(realm) + 3;
1134	s = malloc(len);
1135	if (s == NULL) {
1136		Log("Out of memory");
1137		return (GSS_S_FAILURE);
1138	}
1139	strlcpy(s, service, len);
1140	strlcat(s, "/", len);
1141	strlcat(s, host, len);
1142	strlcat(s, "@", len);
1143	strlcat(s, realm, len);
1144
1145	str_to_buf(s, &name_buf);
1146
1147	Info("Importing kerberos principal service name %s\n", s);
1148
1149	major = gss_import_name(minor, &name_buf,
1150				GSS_KRB5_NT_PRINCIPAL_NAME, svcname);
1151	free(s);
1152	return (major);
1153}
1154
1155static uint32_t
1156construct_hostbased_service_name(uint32_t *minor, const char *service, const char *host, gss_name_t *svcname)
1157{
1158	size_t len;
1159	char *s;
1160	gss_buffer_desc name_buf;
1161	uint32_t major;
1162
1163	len = strlen(service) + strlen(host) + 2;
1164	s = malloc(len);
1165	if (s == NULL) {
1166		Log("Out of memory");
1167		return (GSS_S_FAILURE);
1168	}
1169	strlcpy(s, service, len);
1170	strlcat(s, "@", len);
1171	strlcat(s, host, len);
1172
1173	str_to_buf(s, &name_buf);
1174
1175	Info("Importing host based service name %s\n", s);
1176
1177	major = gss_import_name(minor, &name_buf, GSS_C_NT_HOSTBASED_SERVICE, svcname);
1178
1179	DEBUG(2, "gss_import_name returned %#K", major);
1180
1181	free(s);
1182	return (major);
1183}
1184
1185/*
1186 * str_to_svc_name: Given a string representation of a service name, convert it
1187 * into a set of  gss service names of name type GSS_KRB5_NT_PRINCIPAL_NAME.
1188 *
1189 * We get up to three names, lowercase of the forward canonicalization of the
1190 * host name, lowercase of the host name itself, and the lowercase of the reverse
1191 * canonicalization of the host name.
1192 *
1193 * name_count is an in/out parameter that says what the size is of the svcname
1194 * array coming in and the number of gss names found coming out.
1195 * if name_count is one, no canonicalization is done
1196 * if name_count is two, return the lowercase of the forward canonicalization
1197 *	followed by the non canonicalized host name
1198 * if name_count is three, the two elements above followed by the lowercase of
1199 *	the reverse lookup.
1200 *
1201 * We return GSS_S_COMPLETE if we can produce at least one service name.
1202 */
1203
1204#define LKDCPREFIX "LKDC:"
1205
1206static uint32_t
1207str_to_svc_names(uint32_t *minor, const char *svcstr,
1208	gss_name_t *svcname, uint32_t *name_count)
1209{
1210	uint32_t major __unused /* To make the static analyser happy */, first_major;
1211	char *realm = NULL /* default_realm */, *host;
1212	char *s, *p, *service;
1213	char *fqdn = NULL, *rfqdn = NULL;
1214	uint32_t count = *name_count;
1215	int is_lkdc;
1216	krb5_realm *realms = NULL;
1217
1218	*minor = 0;
1219	major = GSS_S_FAILURE;
1220	*name_count = 0;
1221
1222	if (svcstr == NULL) {
1223		Log("Null service name string\n");
1224		return (GSS_S_FAILURE);
1225	}
1226	DEBUG(3, "%s count = %d\n", svcstr, count);
1227	service = strdup(svcstr);
1228	if (service == NULL) {
1229		Log("Out of memory\n");
1230		return (GSS_S_FAILURE);
1231	}
1232
1233	p = get_next_kerb_component(service);
1234
1235	/*set host part */
1236	host = p + 1;
1237
1238	if (p == NULL || *p == '\0') {
1239		/*
1240		 * We only have the service name so we (this host)
1241		 * must be our instance.
1242		 */
1243		host = local_host;
1244
1245	} else if (*p == '@') {
1246		/* Have a host based service name */
1247		/* Terminate service part of name */
1248		*p = '\0';
1249
1250		s = get_next_kerb_component(host);
1251		if (s != NULL) {
1252			Info("Invalid host name part %s\n", host);
1253			free(service);
1254			return (GSS_S_BAD_NAME);
1255		}
1256		major = construct_hostbased_service_name(minor, service, host, svcname);
1257		if (major == GSS_S_COMPLETE)
1258			*name_count = 1;
1259		return (major);
1260	} else if (*p == '/') {
1261		/* We have a kerberos instance thus a kerberos principal type */
1262		/* Terminate service part of name */
1263		*p = '\0';
1264
1265		/* See if we have a realm */
1266		s = host;
1267		do {
1268			s = get_next_kerb_component(s+1);
1269			if (s && (*s == '@')) {
1270				realm = s + 1;
1271				*s = '\0';	/* terminate host instance */
1272				break;
1273			}
1274		} while (s);
1275	} else {
1276		/* Should never happen */
1277		free(service);
1278		return (GSS_S_BAD_NAME);
1279	}
1280
1281	if (realm == NULL) {
1282		/*
1283		 * Try this as a host based service name first, since
1284		 * host base service name will get canonicalized, looked up in the domain realms
1285		 * section and then tried for referrals
1286		 */
1287		major = construct_hostbased_service_name(minor, service, host, svcname);
1288		if (major == GSS_S_COMPLETE) {
1289			*name_count = 1;
1290			free(service);
1291			return (major);
1292		}
1293		/* Nope so set the realm to be the default and fall through */
1294		if (get_local_realms(&realms))
1295			realm = *realms;
1296	}
1297	if (realm == NULL) {
1298		free(service);
1299		/*
1300		 * Force exit in SHUTDOWN_TIMEOUT. Perhaps
1301		 * we'll pickup a default on next start up.
1302		 */
1303		kill(getpid(), SIGTERM);
1304		return (GSS_S_BAD_NAME);
1305	}
1306
1307
1308	is_lkdc = (strncmp(realm, LKDCPREFIX, strlen(LKDCPREFIX)) == 0);
1309	/* Don't lowercase an LKDC instance */
1310	major = construct_service_name(minor, service, host, realm, !is_lkdc, &svcname[*name_count]);
1311	if (major == GSS_S_COMPLETE)
1312		*name_count += 1;
1313	first_major = major;
1314
1315	/* Don't waste time trying to canonicalize local KDCs */
1316	if (count == 1 || is_lkdc)
1317		goto done;
1318
1319	fqdn = canonicalize_host(host, (count == 3) ? &rfqdn : NULL);
1320	if (fqdn) {
1321		if (strncmp(fqdn, host, MAXHOSTNAMELEN) != 0) {
1322			major = construct_service_name(minor, service, fqdn, realm, true, &svcname[*name_count]);
1323			if (major == GSS_S_COMPLETE)
1324				*name_count += 1;
1325		} else {
1326			free(fqdn);
1327		}
1328	}
1329
1330	if (rfqdn) {
1331		if (*name_count < count) {
1332			major = construct_service_name(minor, service, rfqdn, realm, true, &svcname[*name_count]);
1333			if (major == GSS_S_COMPLETE)
1334				*name_count += 1;
1335		} else {
1336			free(rfqdn);
1337		}
1338	}
1339
1340done:
1341	free(service);
1342	free_local_realms(realms);
1343
1344	return (*name_count ? GSS_S_COMPLETE : first_major);
1345}
1346
1347/*
1348 * Given the name and name type, convert the name to a gss_name_t. If the name type
1349 * is a mechanism specific (currently one of the kerberos or NTLM name types), we will set the mechtype
1350 * passed in to be that mechanism type. We do this so that we will acquire that mechanism specific
1351 * credential in do_acquire_cred. This is important when the mechanism being used is SPNEGO and
1352 * we end up trying to use the wrong credential.
1353 */
1354static uint32_t
1355blob_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)
1356{
1357	uint32_t maj;
1358	gss_buffer_desc name_buf = { size, name };
1359	gss_OID name_type;
1360	*min = GSS_S_COMPLETE;
1361
1362	switch (nt) {
1363		case GSSD_EXPORT:
1364			name_type = GSS_C_NT_EXPORT_NAME;
1365			break;
1366		case GSSD_ANONYMOUS:
1367			name_type = GSS_C_NT_ANONYMOUS;
1368			if (*mech == GSSD_SPNEGO_MECH)
1369				*mech = GSSD_NTLM_MECH;
1370			break;
1371		case GSSD_HOSTBASED:
1372			name_type = GSS_C_NT_HOSTBASED_SERVICE;
1373			break;
1374		case GSSD_USER:
1375			name_type = GSS_C_NT_USER_NAME;
1376			break;
1377		case GSSD_MACHINE_UID:
1378			name_type = GSS_C_NT_MACHINE_UID_NAME;
1379			break;
1380		case GSSD_STRING_UID:
1381			name_type = GSS_C_NT_STRING_UID_NAME;
1382			break;
1383		case GSSD_KRB5_PRINCIPAL:
1384			name_type = GSS_KRB5_NT_PRINCIPAL_NAME;
1385			*mech = GSSD_KRB5_MECH;
1386			break;
1387		case GSSD_UUID:
1388			name_type = GSS_C_NT_UUID;
1389			*mech = GSSD_IAKERB_MECH;
1390			break;
1391		case GSSD_KRB5_REFERRAL:
1392			name_type = GSS_KRB5_NT_PRINCIPAL_NAME_REFERRAL;
1393			*mech = GSSD_KRB5_MECH;
1394			break;
1395		case GSSD_NTLM_PRINCIPAL:
1396			name_type = GSS_C_NT_NTLM;
1397			*mech = GSSD_NTLM_MECH;
1398			break;
1399		case GSSD_NTLM_BLOB:
1400		default:
1401			return (GSS_S_BAD_NAMETYPE);
1402	}
1403
1404	maj = gss_import_name(min, &name_buf, name_type, gname);
1405
1406	if (maj != GSS_S_COMPLETE || get_debug_level() > 1) {
1407		char *ntstr = oid_name(name_type);
1408		Info("gss_import_name returned %#K; %#k for %.*s using %s name type",
1409		     maj, mechtab[*mech], *min, size, name, ntstr);
1410		free(ntstr);
1411	}
1412	if (maj == GSS_S_COMPLETE && strrep) {
1413		uint32_t dmaj, dmin;
1414		gss_buffer_desc dbuf;
1415		gss_OID oid;
1416
1417		dmaj = gss_display_name(&dmin, *gname, &dbuf, &oid);
1418		DEBUG(3, "gss_display_name returned %#K", dmaj);
1419		*strrep  = (dmaj == GSS_S_COMPLETE) ? buf_to_str(&dbuf) : strdup("unknown");
1420		if (oidnt)
1421			*oidnt = oid_name(oid);
1422	}
1423
1424	return (maj);
1425}
1426
1427static uint32_t
1428blob_to_svcnames(uint32_t *min, gssd_nametype nt, gssd_byte_buffer svc_princ, uint32_t size,
1429	gssd_mechtype mech, gss_name_t *svcname, uint32_t *name_count)
1430{
1431	*min = GSS_S_COMPLETE;
1432
1433	switch (nt) {
1434	case GSSD_STRING_NAME:
1435		return (str_to_svc_names(min, (char *)svc_princ, svcname, name_count));
1436	default:
1437		*name_count = 1;
1438		return (blob_to_name(min, nt, svc_princ, size, &mech, NULL, NULL, svcname));
1439	}
1440}
1441
1442static int
1443is_nfs_service(gss_name_t svcname)
1444{
1445	uint32_t maj, min;
1446	gss_buffer_desc nbuf;
1447	gss_name_t canon;
1448	char *str = NULL;
1449	int is_nfs = 0;
1450
1451	maj = gss_canonicalize_name(&min, svcname, mechtab[GSSD_KRB5_MECH], &canon);
1452	if (maj != GSS_S_COMPLETE)
1453		return (0);
1454
1455	maj = gss_display_name(&min, canon, &nbuf, NULL);
1456	if (maj != GSS_S_COMPLETE)
1457		goto done;
1458
1459	str = buf_to_str(&nbuf);
1460
1461	DEBUG(3, "is_nfs_service principal is %s\n", str ? str : "");
1462
1463	if (str)
1464		is_nfs = IS_NFS_SERVICE(str);
1465
1466done:
1467	gss_release_name(&min, &canon);
1468	free(str);
1469
1470	return (is_nfs);
1471}
1472
1473/*
1474 * Figure out who nobody is and how big a buffer we need to fetch password entries.
1475 * If we're logging at a debug level print out the default realm if we can.
1476 */
1477static void
1478gssd_init(void)
1479{
1480	struct passwd *pwent;
1481	struct group *grent;
1482	char hostbuf[MAXHOSTNAMELEN];
1483
1484	/* Set up mech table */
1485	mechtab[GSSD_KRB5_MECH] = GSS_KRB5_MECHANISM;
1486	mechtab[GSSD_SPNEGO_MECH] = GSS_SPNEGO_MECHANISM;
1487	mechtab[GSSD_NTLM_MECH] = GSS_NTLM_MECHANISM;
1488	mechtab[GSSD_IAKERB_MECH] = GSS_IAKERB_MECHANISM;
1489
1490	/*
1491	 * Turn off home directory access during startup.
1492	 * XXX Will need a more flexible policy to handle
1493	 * apps that may want home dir access.
1494	 */
1495	krb5_set_home_dir_access(NULL, FALSE);
1496
1497	pwent = getpwnam("nobody");
1498	NobodyUid = pwent ? pwent->pw_uid : NOBODY;
1499	grent = getgrnam("nobody");
1500	NobodyGid = grent ? grent->gr_gid : NOBODY;
1501
1502	gethostname(hostbuf, MAXHOSTNAMELEN);
1503	local_host = canonicalize_host(hostbuf, NULL);
1504	if ( local_host == NULL) {
1505		Info("Could not canonicalize our host name in gssd_init\n");
1506		local_host = strdup(lowercase(hostbuf));
1507	}
1508
1509	/* Figure out how big a buffer we need for getting pwd entries */
1510	GetPWMaxRSz = sysconf(_SC_GETPW_R_SIZE_MAX);
1511	GetPWMaxRSz = (GetPWMaxRSz == -1) ? 512 : GetPWMaxRSz;
1512
1513	DEBUG(2, "Starting with pid = %d\n\n\n", getpid());
1514	if (get_debug_level()) {
1515		krb5_realm *realms = NULL;
1516		krb5_realm drealm = NULL;
1517
1518		if (get_local_realms(&realms))
1519			drealm = *realms;
1520		Info("Kerberos default realm is %s for %s\n\n",
1521			     drealm ? drealm : "No realm", local_host);
1522		free_local_realms(realms);
1523	}
1524}
1525
1526/*
1527 * Receive one message. Note that mach_msg_server_once will call
1528 * the appropriate dispatch routine, which in turn will call new_worker_thread()
1529 * and that will fire us up again to wait for the next message.
1530 */
1531static void *
1532receive_message(void *arg __attribute__((unused)))
1533{
1534	kern_return_t kr;
1535
1536
1537#ifdef VDEBUG
1538		DEBUG(3, "Enter receive_message %p with transaction count = %lu, "
1539			"standby count = %lu\n", pthread_self(),
1540			_vproc_transaction_count(), _vproc_standby_count());
1541#endif
1542	pthread_setname_np("mach_msg_server thread");
1543	kr = mach_msg_server_once(gssd_mach_server, MAX_GSSD_MSG_SIZE,
1544			gssd_receive_right,
1545			MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) |
1546			MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0));
1547
1548
1549#ifdef VDEBUG
1550		DEBUG(3, "Leaving receive_message %p with transaction count = %lu, "
1551			"standby count = %lu\n", pthread_self(),
1552			_vproc_transaction_count(), _vproc_standby_count());
1553#endif
1554
1555	if (kr != KERN_SUCCESS)  {
1556		Info("mach_msg_server(mp): %s\n", mach_error_string(kr));
1557		exit(1);
1558	}
1559
1560	return (NULL);
1561}
1562
1563
1564/*
1565 * Wait until we have fewer than the maximum number of worker threads,
1566 * and then create one running receive_message() thread.
1567 *
1568 * Called by the dispatch routines just before processing a message,
1569 * so we're listening for messages even while processing a message,
1570 * as long as we aren't out of threads.
1571 */
1572#define MAXTHREADNAME 24
1573
1574static void
1575new_worker_thread(void)
1576{
1577	pthread_t thread;
1578	char thread_name[MAXTHREADNAME];
1579	int error;
1580
1581	(void) pthread_mutex_lock(numthreads_lock);
1582
1583	while (bye == 0 && numthreads >= maxthreads) {
1584		(void) pthread_cond_wait(numthreads_cv, numthreads_lock);
1585	}
1586	if (bye)
1587		goto out;
1588	numthreads++;
1589	error = pthread_create(&thread, attr, receive_message, NULL);
1590	if (error) {
1591		Info("unable to create worker thread: %s", strerror(error));
1592		numthreads--;
1593	}
1594
1595out:
1596
1597	snprintf(thread_name, sizeof (thread_name), "worker thread %d", numthreads);
1598	thread_name[MAXTHREADNAME - 1] = '\0';
1599	pthread_setname_np(thread_name);
1600	DEBUG(3, "Starting %s\n", thread_name);
1601
1602	(void) pthread_mutex_unlock(numthreads_lock);
1603}
1604
1605/*
1606 * This worker thread is terminating; reduce the count of worker threads,
1607 * and, if it's dropped below the maximum, wake up anybody waiting for
1608 * it to drop below the maximum.
1609 *
1610 * Called by the dispatch routines just before returning.
1611 */
1612static void
1613end_worker_thread(void)
1614{
1615	(void) pthread_mutex_lock(numthreads_lock);
1616	numthreads--;
1617	if (numthreads < maxthreads)
1618		pthread_cond_signal(numthreads_cv);
1619
1620	if (get_debug_level() > 2) {
1621		char thread_name[MAXTHREADNAME];
1622		pthread_getname_np(pthread_self(), thread_name, sizeof thread_name);
1623		DEBUG(3, "Ending %s. Number of worker threads running is %d\n", thread_name, numthreads);
1624	}
1625
1626	(void) pthread_mutex_unlock(numthreads_lock);
1627}
1628
1629
1630/*
1631 * Thread that handles signals for us and will tell the timeout thread to
1632 * shut us down if we get a signal that we don't continue for. We set a global
1633 * variable bye and the timeout value to SHUTDOWN_TIMEOUT and wake every
1634 * body up. Threads block in new_worker_thread will see bye is set and exit.
1635 * We set timeout to SHUTDOWN_TIMEOUT for the timeout thread, so that threads
1636 * executing dispatch routines have an opportunity to finish.
1637 */
1638
1639static void*
1640shutdown_thread(void *arg __attribute__((unused)))
1641{
1642	int sig;
1643	int status;
1644	int remote_token;
1645	int master_token;
1646	sigset_t quitset[1];
1647	char *notify_name = asl_remote_notify_name();
1648
1649	pthread_setname_np("Signal thread");
1650
1651	sigemptyset(quitset);
1652	sigaddset(quitset, SIGQUIT);
1653
1654	status = notify_register_signal(notify_name, SIGUSR2, &remote_token);
1655	if (status != NOTIFY_STATUS_OK)
1656		Log("Could not register for asl notifications: %s\n", asl_remote_notify_name());
1657	status = notify_register_signal(NOTIFY_SYSTEM_MASTER, SIGUSR2, &master_token);
1658	if (status != NOTIFY_STATUS_OK)
1659		Log("Could not register for asl notifications: %s\n", NOTIFY_SYSTEM_MASTER);
1660
1661	/*
1662	 * N.B.  From the man page: "A true indication is returned the first time notify_check
1663	 * is called for a token.  Subsequent calls give a true indication when notifications have
1664	 * been posted for the name associated with the notification token."
1665	 *
1666	 * So we do a notify_check here for the above tokens to get the true status when processing
1667	 * SIGUSR2 below.
1668	 */
1669	(void)notify_check(remote_token, &status);
1670	(void)notify_check(master_token, &status);
1671
1672	do {
1673		int asl_notification = 0;
1674		int debug_level = get_debug_level();
1675
1676		if (sigwait(waitset, &sig))
1677			Log("sigwait failed %s", strerror(errno));
1678
1679		DEBUG(2, "Received signal %d\n", sig);
1680		switch (sig) {
1681		case SIGQUIT:
1682			if (get_debug_level() > 1)
1683				die = 1;
1684			else {
1685				pthread_sigmask(SIG_UNBLOCK, quitset, NULL);
1686				raise(SIGQUIT);
1687			}
1688			break;
1689		case SIGUSR1:
1690			debug_level++;
1691			break;
1692		case SIGUSR2:
1693			status = notify_check(master_token, &asl_notification);
1694			if (status != NOTIFY_STATUS_OK)
1695				Log("Could not retreive notification for %s", NOTIFY_SYSTEM_MASTER);
1696			if (asl_notification == 0) {
1697				status = notify_check(remote_token, &asl_notification);
1698				if (status != NOTIFY_STATUS_OK )
1699					Log("Could not retreive notification for %s", asl_remote_notify_name());
1700				if (asl_notification == 0) {
1701					if (debug_level)
1702						debug_level--;
1703				}
1704			}
1705			break;
1706		case SIGHUP:
1707			debug_level = !debug_level;
1708			break;
1709		}
1710		if (asl_notification) {
1711			set_debug_level(-1);
1712			Info("Debug set to %d by syslog\n", get_debug_level());
1713		} else {
1714			set_debug_level(debug_level);
1715			Info("Debug level set to %d", get_debug_level());
1716		}
1717	} while (sigismember(contset, sig) || sig == 0);
1718
1719	pthread_mutex_lock(numthreads_lock);
1720	bye = 1;
1721	/*
1722	 * Wait a little bit for dispatch threads to complete.
1723	 */
1724	timeout = SHUTDOWN_TIMEOUT;
1725	/*
1726	 * Force the timeout_thread and all the rest to to wake up and exit.
1727	 */
1728	pthread_cond_broadcast(numthreads_cv);
1729	pthread_mutex_unlock(numthreads_lock);
1730	free(notify_name);
1731
1732	return (NULL);
1733}
1734
1735static void
1736compute_new_timeout(struct timespec *new)
1737{
1738	struct timeval current;
1739
1740	gettimeofday(&current, NULL);
1741	new->tv_sec = current.tv_sec + timeout;
1742	new->tv_nsec = 1000 * current.tv_usec;
1743}
1744
1745static int no_timeout;
1746
1747static void
1748disable_timeout(int disable)
1749{
1750	pthread_mutex_lock(numthreads_lock);
1751	no_timeout = disable;
1752	pthread_mutex_unlock(numthreads_lock);
1753}
1754
1755static void*
1756timeout_thread(void *arg __attribute__((unused)))
1757{
1758	int rv = 0;
1759	struct timespec exittime;
1760
1761	pthread_setname_np("Timeout thread");
1762	(void) pthread_mutex_lock(numthreads_lock);
1763
1764	/*
1765	 * Note that we have an extra thread running waiting for a mach message,
1766	 * the first of which was started in main. Hence we have the test below for
1767	 * greater than one instead of zero.
1768	 */
1769	while (bye ? (rv == 0 && numthreads > 1) : (rv == 0 || no_timeout || numthreads > 1)) {
1770		if (bye < 2)
1771			compute_new_timeout(&exittime);
1772		/*
1773		 * If the shutdown thread has told us to exit (bye == 1),
1774		 * then increment bye so that we will exit after at most
1775		 * SHUTDOWN_TIMEOUT from the time we were signaled. When
1776		 * we come back around the loop bye will be greater or
1777		 * equal to two and we will not update our absolute exit time.
1778		 */
1779		if (bye)
1780			bye++;
1781		rv = pthread_cond_timedwait(numthreads_cv,
1782					numthreads_lock, &exittime);
1783
1784		DEBUG(4, "timeout_thread: rv = %s %d\n",
1785			rv ? strerror(rv) : "signaled", numthreads);
1786	}
1787
1788	(void) pthread_mutex_unlock(numthreads_lock);
1789
1790
1791	return (NULL);
1792}
1793
1794/*
1795 * vm_alloc_buffer: Copy the contents of the gss_buf_t to vm_allocated
1796 * memory at *value. The mig routines will automatically deallocate this
1797 * memory.
1798 */
1799
1800static void
1801vm_alloc_buffer(gss_buffer_t buf, uint8_t **value, uint32_t *len)
1802{
1803	kern_return_t kr;
1804
1805	*value = NULL;
1806	*len = 0;
1807
1808	if (buf->length == 0)
1809		return;
1810	kr = vm_allocate(mach_task_self(),
1811			(vm_address_t *)value, buf->length, VM_FLAGS_ANYWHERE);
1812	if (kr != KERN_SUCCESS) {
1813		Log("Could not allocate vm in vm_alloc_buffer\n");
1814		return;
1815	}
1816	*len = (uint32_t) buf->length;
1817	memcpy(*value, buf->value, *len);
1818}
1819
1820/*
1821 * Extract the session key from a completed gss context. Currently the only
1822 * supported mechanism is kerberos and NTLM. Note the extracted key has been vm_allocated
1823 * and will be released by mig. (See gssd_mach.defs)
1824 * XXX this is extraordinarily yuckie.
1825 */
1826
1827
1828static gss_OID kerb_mechs[] = {
1829	GSS_KRB5_MECHANISM,
1830	GSS_IAKERB_MECHANISM,
1831	GSS_PKU2U_MECHANISM,
1832	NULL
1833};
1834
1835static bool
1836is_kerberos_key_mech(gss_const_OID mech)
1837{
1838	gss_OID *p;
1839
1840	for (p = kerb_mechs; p; p++) {
1841		if (gss_oid_equal(mech, *p))
1842			return (true);
1843	}
1844
1845	return (false);
1846}
1847
1848static uint32_t
1849GetSessionKey(uint32_t *minor, gss_OID mech, gss_ctx_id_t ctx,
1850		gssd_byte_buffer *skey, mach_msg_type_number_t *skeyCnt)
1851{
1852	gss_krb5_lucid_context_v1_t *lucid_ctx = NULL;
1853	gss_krb5_lucid_key_t *key;
1854	void  *some_lucid_ctx;
1855	uint32_t maj_stat, min_stat;
1856	uint32_t vers;
1857	gss_buffer_desc buf;
1858
1859	*skey = NULL;
1860	*skeyCnt = 0;
1861	*minor = 0;
1862
1863	if (gss_oid_equal(mech, GSS_NTLM_MECHANISM)) {
1864		gss_buffer_set_t keys;
1865		maj_stat = gss_inquire_sec_context_by_oid(minor, ctx, GSS_NTLM_GET_SESSION_KEY_X, &keys);
1866		if (maj_stat != GSS_S_COMPLETE)
1867			return (maj_stat);
1868
1869		if (keys->count) {
1870			if (keys->count > 1)
1871				Info("GetSessionKey received multiple keys. Using first key of %d keys\n", (uint32_t)keys->count);
1872			vm_alloc_buffer(&keys->elements[0], skey, skeyCnt);
1873			if (skey == NULL) {
1874				Log("Out of memory in GetSessionKey\n");
1875				return (GSS_S_FAILURE);
1876			}
1877		}
1878		(void)gss_release_buffer_set(&min_stat, &keys);
1879		return (GSS_S_COMPLETE);
1880
1881	} else if (is_kerberos_key_mech(mech)) {
1882		DEBUG(4, "Calling  gss_krb5_export_lucid_sec_context\n");
1883		maj_stat = gss_krb5_export_lucid_sec_context(minor, &ctx,
1884							     1, &some_lucid_ctx);
1885		DEBUG(3, "gss_krb5_export_lucid_sec_context returned %#K; %#k", maj_stat, mech, *minor);
1886
1887		if (maj_stat != GSS_S_COMPLETE) {
1888			return (maj_stat);
1889		}
1890
1891		vers = ((gss_krb5_lucid_context_version_t *)some_lucid_ctx)->version;
1892		switch (vers) {
1893			case 1:
1894				lucid_ctx = (gss_krb5_lucid_context_v1_t *)some_lucid_ctx;
1895				break;
1896			default:
1897				Log("Lucid version %d is unsupported\n", vers);
1898				(void) gss_krb5_free_lucid_sec_context(&min_stat, lucid_ctx);
1899				return (GSS_S_UNAVAILABLE);
1900		}
1901
1902		DEBUG(4, "vers = %d, protocol = %d\n",  vers, lucid_ctx->protocol);
1903
1904		switch (lucid_ctx->protocol) {
1905			case 0:
1906				DEBUG(4, "Got rfc1964\n");
1907				key = &lucid_ctx->rfc1964_kd.ctx_key;
1908				break;
1909			case 1:
1910				key = lucid_ctx->cfx_kd.have_acceptor_subkey ?
1911				&lucid_ctx->cfx_kd.acceptor_subkey :
1912				&lucid_ctx->cfx_kd.ctx_key;
1913				break;
1914			default:
1915				(void) gss_krb5_free_lucid_sec_context(&min_stat, lucid_ctx);
1916				return (GSS_S_CALL_BAD_STRUCTURE);  /* should never happen. */
1917		}
1918
1919		DEBUG(4, "lucid key type = %d\n", key->type);
1920		buf.length = key->length;
1921		buf.value  = key->data;
1922
1923		vm_alloc_buffer(&buf, skey, skeyCnt);
1924		if (skey == NULL) {
1925			Log("Out of memory in GetSessionKey\n");
1926			return (GSS_S_FAILURE);
1927		}
1928
1929		(void) gss_krb5_free_lucid_sec_context(&min_stat, lucid_ctx);
1930		return (GSS_S_COMPLETE);
1931	}
1932
1933	maj_stat = gss_oid_to_str(&min_stat, mech, &buf);
1934	if (maj_stat == GSS_S_COMPLETE) {
1935		char *oidstr = buf_to_str(&buf);
1936		Info("Unsupported mechanism for key extraction: %s\n", oidstr);
1937		free(oidstr);
1938	} else {
1939		Info("Unsupported mechanism for key extraction.\n");
1940	}
1941
1942	return (GSS_S_COMPLETE);
1943}
1944
1945/*
1946 * If we get a call and the verifier does not match, clear out the args for
1947 * the client.
1948 */
1949static uint32_t
1950badcall(char *rtn, uint32_t *minor_stat,
1951	gssd_ctx *gss_context, gssd_cred *cred_handle, uint32_t *gssd_flags,
1952	gssd_byte_buffer *skey, mach_msg_type_number_t *skeyCnt,
1953	gssd_byte_buffer *otoken, mach_msg_type_number_t *otokenCnt)
1954{
1955
1956	if (!gssd_check(CAST(void *, *gss_context)))
1957	    Info("Bad context found %p\n", (void *)(uintptr_t)*gss_context);
1958	if (!gssd_check(CAST(void *, *cred_handle)))
1959	    Info("Bad cred handle found %p\n", (void *)(uintptr_t)*cred_handle);
1960	Log("%s request not addressed to us\n", rtn);
1961	*minor_stat = 0;
1962	*gss_context = CAST(gssd_ctx, GSS_C_NO_CONTEXT);
1963	*cred_handle = CAST(gssd_cred, GSS_C_NO_CREDENTIAL);
1964	*gssd_flags = 0;
1965	*skey = NULL;
1966	*skeyCnt = 0;
1967	*otoken = NULL;
1968	*otokenCnt = 0;
1969
1970	return (GSS_S_CALL_BAD_STRUCTURE);
1971}
1972
1973/*
1974 * Convert a gss_name_t to a krb5_principal
1975 */
1976static uint32_t
1977gss_name_to_kprinc(uint32_t *minor, gss_name_t name, krb5_principal *princ, krb5_context kctx)
1978{
1979	uint32_t major, m;
1980	gss_name_t kname = GSS_C_NO_NAME;
1981	gss_buffer_desc dname;
1982	char *strname = NULL;
1983
1984	*minor = 0;
1985	major = gss_canonicalize_name(minor, name, GSS_KRB5_MECHANISM, &kname);
1986	if (major != GSS_S_COMPLETE)
1987		return (major);
1988
1989	major = gss_display_name(minor, kname, &dname, NULL);
1990	(void) gss_release_name(&m, &kname);
1991	if (major != GSS_S_COMPLETE)
1992		return (major);
1993
1994	strname = buf_to_str(&dname);
1995	if (strname == NULL) {
1996		return (GSS_S_FAILURE);
1997	}
1998
1999	DEBUG(3, "parsing %s\n", strname);
2000	*minor = krb5_parse_name(kctx, strname, princ);
2001
2002	major = (uint32_t) (*minor ? GSS_S_FAILURE : GSS_S_COMPLETE);
2003	free(strname);
2004
2005	return (major);
2006}
2007
2008/*
2009 * krb5_find_cache_name(krb5_principal princ)
2010 *
2011 * Given a kerberos principal find the best cache name to use.
2012 */
2013
2014#define KFCN_ALIVE 1
2015#define KFCN_EXPIRED 2
2016
2017static char*
2018krb5_find_cache_name(krb5_context kcontext, krb5_principal sprinc, int *flags)
2019{
2020	krb5_error_code error, err;
2021	krb5_cc_cache_cursor cursor;
2022	krb5_ccache ccache;
2023	krb5_principal ccache_princ;
2024	char *cname = NULL;
2025	char *kname = NULL;
2026	time_t ltime;
2027	const char *msg = NULL;
2028	int cnt = 0;
2029	*flags = 0;
2030
2031	err = krb5_cc_cache_get_first(kcontext, NULL, &cursor);
2032	if (err) {
2033		msg = krb5_get_error_message(kcontext, err);
2034		Info("Could not get cache collection cursor %s\n", msg);
2035		krb5_free_error_message(kcontext, msg);
2036		return (NULL);
2037	}
2038	while (!(error = krb5_cc_cache_next(kcontext, cursor, &ccache))) {
2039		int isdead = 0;
2040		cnt += 1;
2041		err = krb5_cc_get_full_name(kcontext, ccache, &cname);
2042		if (err) {
2043			msg = krb5_get_error_message(kcontext, err);
2044			Info("krb5_cc_get_full_name error: %s\n", msg);
2045			krb5_free_error_message(kcontext, msg);
2046			krb5_cc_close(kcontext, ccache);
2047			if (cname)   /* Shouldn't happen */
2048				free(cname);
2049			cname = NULL;
2050			continue;
2051		}
2052		err = krb5_cc_get_principal(kcontext, ccache, &ccache_princ);
2053		if (err) {
2054			krb5_cc_close(kcontext, ccache);
2055			msg = krb5_get_error_message(kcontext, err);
2056			Info("krb5_cc_get_principal error: %s\n", msg);
2057			krb5_free_error_message(kcontext, msg);
2058			free(cname);
2059			cname = NULL;
2060			continue;
2061		}
2062
2063		err = krb5_cc_get_lifetime(kcontext, ccache, &ltime);
2064
2065		if (ltime <= 0) {
2066			if (err && err != KRB5_CC_END) {
2067				msg = krb5_get_error_message(kcontext, err);
2068				Info("krb5_cc_get_lifetime error: %s\n", msg);
2069				krb5_free_error_message(kcontext, msg);
2070			}
2071			isdead = 1;
2072		} else {
2073			*flags |= KFCN_ALIVE;
2074		}
2075
2076		if (krb5_realm_compare(kcontext, sprinc, ccache_princ)) {
2077			(void) krb5_unparse_name(kcontext, ccache_princ, &kname);
2078			krb5_free_principal(kcontext, ccache_princ);
2079			Info("Found cache %d: %s for %s lifetime %ld\n",
2080			     cnt, cname, kname ? kname : "could not get principal name", ltime);
2081			free(kname);
2082
2083			if (!isdead) {
2084				krb5_cc_close(kcontext, ccache);
2085				*flags &= ~KFCN_EXPIRED;
2086				break;
2087			} else {
2088				*flags |= KFCN_EXPIRED;
2089			}
2090		} else {
2091			(void) krb5_free_principal(kcontext, ccache_princ);
2092		}
2093
2094		krb5_cc_close(kcontext, ccache);
2095		free(cname);
2096		cname = NULL;
2097	}
2098	if (error != KRB5_CC_END) {
2099		msg = krb5_get_error_message(kcontext, error);
2100		Log("Could not iterate through cache collections: %s\n", msg);
2101		krb5_free_error_message(kcontext, msg);
2102	}
2103	(void) krb5_cc_cache_end_seq_get(kcontext, cursor);
2104
2105	return (cname);
2106}
2107
2108/*
2109 * set_principal_identity:
2110 * Given a service principal try and set the default identity so that
2111 * calls to gss_init_sec_context will work.
2112 * Currently this only groks kerberos.
2113 */
2114static uint32_t
2115set_principal_identity(gss_name_t sname, uint32_t *minor)
2116{
2117	krb5_principal sprinc;
2118	uint32_t major;
2119	char *cname;
2120	krb5_context kctx;
2121	int error, flags;
2122
2123	*minor = 0;
2124	error = krb5_init_context(&kctx);
2125	if (error) {
2126		Log("Can't get kerberos context");
2127		return (GSS_S_FAILURE);
2128	}
2129
2130	major = gss_name_to_kprinc(minor, sname, &sprinc, kctx);
2131	if (major != GSS_S_COMPLETE) {
2132		krb5_free_context(kctx);
2133		DEBUG(2, "Could not convert gss name to kerberos principal %#K %#k\n", major, GSS_KRB5_MECHANISM, *minor);
2134		return (major);
2135	}
2136
2137	cname = krb5_find_cache_name(kctx, sprinc, &flags);
2138	krb5_free_principal(kctx, sprinc);
2139	krb5_free_context(kctx);
2140	Debug("Using ccache <%s> flags = %d\n", cname ? cname : "Default", flags);
2141	if (flags == KFCN_EXPIRED)
2142		return (GSS_S_CREDENTIALS_EXPIRED);
2143	if (cname) {
2144		major = gss_krb5_ccache_name(minor, cname, NULL);
2145		DEBUG(3, "gss_krb5_ccache_name returned %#K; %#k\n", major, GSS_KRB5_MECHANISM,  minor);
2146		free(cname);
2147	}
2148
2149	return (GSS_S_COMPLETE);
2150}
2151
2152
2153static uint32_t
2154do_acquire_cred_v1(uint32_t *minor, char *principal, gssd_mechtype mech, gss_name_t sname, uint32_t uid,
2155		   gssd_cred *cred_handle, uint32_t flags)
2156{
2157	uint32_t major = GSS_S_FAILURE, mstat;
2158	gss_buffer_desc buf_name;
2159	gss_name_t clnt_gss_name;
2160	gss_OID_set mechset = GSS_C_NULL_OID_SET;
2161	gss_OID name_type = GSS_KRB5_NT_PRINCIPAL_NAME;
2162
2163	major = set_principal_identity(sname, minor);
2164	if (major)
2165		return (major);
2166	major = gss_create_empty_oid_set(minor, &mechset);
2167	if (major != GSS_S_COMPLETE)
2168		goto done;
2169	major = gss_add_oid_set_member(minor, mechtab[mech], &mechset);
2170	if (major != GSS_S_COMPLETE)
2171		goto done;
2172
2173	/*
2174	 * If we've been passed a principal name then try that first with Kerberos.
2175	 * Since using GSS_C_NT_USER_NAME might work, but throw away instance and realm
2176	 * info. It seems easier just to try and not call gss_inquire_names_for_mech
2177	 */
2178	if (principal && *principal) {
2179		str_to_buf(principal, &buf_name);
2180
2181		Info("importing name %s with Kerberos\n", principal);
2182
2183	retry:
2184		major = gss_import_name(minor, &buf_name, name_type, &clnt_gss_name);
2185		if (major == GSS_S_COMPLETE) {
2186			char  *nt_oid;
2187			major = gss_acquire_cred(
2188						 minor,
2189						 clnt_gss_name,
2190						 GSS_C_INDEFINITE,
2191						 mechset,
2192						 GSS_C_INITIATE,
2193						 (gss_cred_id_t *) cred_handle,
2194						 NULL, NULL);
2195			nt_oid = oid_name(name_type);
2196			Info("gss_acuire_cred for %s using %s, returned: %K; %#k", principal, nt_oid, major, mechtab[mech], *minor);
2197			free(nt_oid);
2198			if (major == GSS_S_COMPLETE) {
2199				/* Done with the name */
2200				(void) gss_release_name(&mstat, &clnt_gss_name);
2201				goto done;
2202			}
2203		}
2204
2205		/*
2206		 * We could call gss_inquire_names_for_mech and try all supported name types
2207		 * but it seems likely the only name type of interest would be GSS_C_NT_USER_NAME.
2208		 */
2209		if (name_type == GSS_KRB5_NT_PRINCIPAL_NAME) {
2210			name_type = GSS_C_NT_USER_NAME;
2211			goto retry;
2212		}
2213	}
2214
2215	if (!(flags & GSSD_NO_DEFAULT)) {
2216		/* Try default */
2217		major = gss_acquire_cred(
2218					 minor,
2219					 GSS_C_NO_NAME,
2220					 GSS_C_INDEFINITE,
2221					 mechset,
2222					 GSS_C_INITIATE,
2223					 (gss_cred_id_t *) cred_handle,
2224					 NULL, NULL);
2225
2226		if (major == GSS_S_COMPLETE) {
2227			Info("Using default credential %p\n", *(gss_cred_id_t *)cred_handle);
2228			goto done;
2229		}
2230	}
2231
2232	/* See if uid will work */
2233	major = uid_to_gss_name(minor, (uid_t) uid,
2234				GSS_C_NT_USER_NAME, &clnt_gss_name);
2235	if (major != GSS_S_COMPLETE)
2236		return (major);
2237
2238	major = gss_acquire_cred(
2239				 minor,
2240				 clnt_gss_name,
2241				 GSS_C_INDEFINITE,
2242				 mechset,
2243				 GSS_C_INITIATE,
2244				 (gss_cred_id_t *) cred_handle,
2245				 NULL, NULL);
2246	Info("Trying to aquire cred with uid %d. Returned %#K; %#k", uid, major, mechtab[mech], *minor);
2247
2248	/* Done with the name */
2249	(void) gss_release_name(&mstat, &clnt_gss_name);
2250done:
2251	if (mechset != GSS_C_NULL_OID_SET)
2252		gss_release_oid_set(&mstat, &mechset);
2253
2254	return (major);
2255}
2256
2257static uint32_t
2258do_acquire_cred(uint32_t *minor_stat, gssd_nametype nt, gssd_byte_buffer name, uint32_t size,
2259		gssd_mechtype mech, gss_cred_id_t *handle)
2260{
2261	uint32_t maj, min, nmaj;
2262	gss_OID_set mechset = GSS_C_NULL_OID_SET;
2263	gss_name_t gname = GSS_C_NO_NAME;
2264	char *mech_name= NULL;
2265	char *princ_name = NULL;
2266	char *oid_nt = NULL;
2267
2268	*minor_stat = GSS_S_COMPLETE;
2269
2270	if (handle == NULL)
2271		return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_CALL_INACCESSIBLE_WRITE);
2272
2273	maj = gss_create_empty_oid_set(minor_stat, &mechset);
2274	if (maj != GSS_S_COMPLETE)
2275		return (maj);
2276
2277	/*
2278	 * Convert the name blob to a gss_name_t, giving back the string representation for
2279	 * the name and the name type oid passed in. In addition if the name type was a
2280	 * mech specific name type adjust the mech to reflect that. That mechanism will
2281	 * then be added as the only member to the mech set below, and thus we will only
2282	 * acquire credentials for that mech. This is important for SPNEGO, if we don't do
2283	 * that, then SPNEGO may try mechanism we are not interested in.
2284	 */
2285	nmaj = blob_to_name(minor_stat, nt, name, size, &mech, &princ_name, &oid_nt, &gname);
2286
2287	maj = gss_add_oid_set_member(minor_stat, mechtab[mech], &mechset);
2288	if (maj != GSS_S_COMPLETE)
2289		goto done;
2290
2291	/* If we can't convert to a gss_name_t try the default with the possibly adjusted mech type */
2292	if (nmaj != GSS_S_COMPLETE)
2293		goto do_default;
2294
2295	mech_name = oid_name(mechtab[mech]);
2296	Info("Acquiring credentials for %s with %s name type using %s mechanism",
2297	     princ_name, oid_nt, mech_name ? mech_name : "Unknown");
2298	free(mech_name);
2299
2300	maj = gss_acquire_cred(minor_stat,
2301			       gname,
2302			       GSS_C_INDEFINITE,
2303			       mechset,
2304			       GSS_C_INITIATE,
2305			       handle,
2306			       NULL, NULL);
2307
2308	(void)gss_release_name(&min, &gname);
2309	Info("Acquiring passed in credentials %K; %#k", maj, mechtab[mech], *minor_stat);
2310	if (maj == GSS_S_COMPLETE)
2311		goto done;
2312
2313do_default:
2314	if (!acquire_default)
2315		goto done;
2316
2317	/* Use the default in gss_init_sec_context */
2318	maj = gss_acquire_cred(
2319			       minor_stat,
2320			       GSS_C_NO_NAME,
2321			       GSS_C_INDEFINITE,
2322			       mechset,
2323			       GSS_C_INITIATE,
2324			       handle,
2325			       NULL, NULL);
2326
2327	if (maj == GSS_S_COMPLETE) {
2328		Info("Using default credential %p\n", (void *) *handle);
2329	} else {
2330		Info("Using null credential\n");
2331		*handle = GSS_C_NO_CREDENTIAL;
2332		maj = GSS_S_COMPLETE;
2333	}
2334done:
2335	if (mechset != GSS_C_NULL_OID_SET)
2336		(void) gss_release_oid_set(&min, &mechset);
2337	if (gname != GSS_C_NO_NAME)
2338		(void) gss_release_name(&min, &gname);
2339	free(princ_name);
2340	free(oid_nt);
2341
2342	return (maj);
2343}
2344
2345/*
2346 * gssd_context type and routines to hold the underlying gss context as well
2347 * as the service name
2348 *
2349 * The reason we do this is on the initial call to gss_init_sec_context is that the
2350 * service name can generate up to two extra service names to try.
2351 * See str_to_svc_names above. Now we need to store the found name
2352 * where we can retrieve it on the next call if we return CONTINUE_NEEDED and
2353 * an easy way to do that is to construct our own context data structure to wrap
2354 * the real gss context and the service name used.
2355 *
2356 * You might be wondering why not just call str_to_svc_names again and not
2357 * worry about another level of context wrapping. Apart from the added work
2358 * of generating the candidate names and finding the "right" name again when we go
2359 * through the loop calling gss_init_sec_context, it won't work unless the first
2360 * name is the chosen name. When we pass in the address of the context to
2361 * gss_init_sec_context, on error gss will happily delete the context and set
2362 * our context now to be GSS_C_NO_CONTEXT.
2363 *
2364 * So let us say we generate 3 candidate service names and the second one will actually
2365 * work. The first time around gss_init_sec_context will fail and set our passed
2366 * in context to GSS_C_NO_CONTEXT  and on the second call succeed, but
2367 * gss_init_sec_context will think this is an initial context (since the context
2368 * is NULL) and create a new one and return to the caller CONTINUE_NEEDED. Oops
2369 * we're in an infinite loop at this point, since the server will receive a valid
2370 * initial token and around we go.
2371 */
2372typedef struct {
2373	gss_ctx_id_t gss_cntx;
2374	gss_name_t   svc_name;
2375	vproc_transaction_t trans_handle;
2376} gssd_context, *gssd_context_t;
2377
2378static gssd_ctx
2379gssd_set_context(gss_ctx_id_t ctx, gss_name_t svc_name)
2380{
2381	gssd_context_t g;
2382
2383	g = malloc(sizeof (gssd_context));
2384	if (g == NULL)
2385		return (CAST(gssd_ctx, GSS_C_NO_CONTEXT));
2386	gssd_enter(g);
2387
2388	g->gss_cntx = ctx;
2389	g->svc_name = svc_name;
2390	g->trans_handle = vproc_transaction_begin(NULL);
2391
2392	return (CAST(gssd_ctx, g));
2393}
2394
2395static gss_ctx_id_t
2396gssd_get_context(gssd_ctx ctx, gss_name_t *svc_name)
2397{
2398	gssd_context_t g;
2399	gss_ctx_id_t gss_context;
2400
2401	if (!ctx) {
2402		if (svc_name)
2403			*svc_name = GSS_C_NO_NAME;
2404		return (GSS_C_NO_CONTEXT);
2405	}
2406	g = CAST(gssd_context_t, ctx);
2407	if (svc_name)
2408		*svc_name = g->svc_name;
2409	gss_context = g->gss_cntx;
2410	vproc_transaction_end(NULL, g->trans_handle);
2411	gssd_remove(g);
2412	free(g);
2413
2414	return (gss_context);
2415}
2416
2417#define MAX_SVC_NAMES 3
2418
2419static uint32_t
2420svc_mach_gss_init_sec_context_common(
2421				     gssd_mechtype mech,
2422				     gssd_byte_buffer itoken, mach_msg_type_number_t itokenCnt,
2423				     gss_name_t svcid,
2424				     uint32_t flags,
2425				     uint32_t *gssd_flags,
2426				     gss_ctx_id_t  *context,
2427				     gss_cred_id_t cred_handle,
2428				     uint32_t *ret_flags,
2429				     gssd_byte_buffer *skey, mach_msg_type_number_t *skeyCnt,
2430				     gssd_byte_buffer *otoken, mach_msg_type_number_t *otokenCnt,
2431				     gssd_dstring  displayname,
2432				     uint32_t *minor_stat)
2433{
2434	gss_buffer_desc intoken = {itokenCnt, itoken};
2435	gss_buffer_desc outtoken = {0, NULL};
2436	gss_buffer_desc name_buf;
2437	gss_name_t source;
2438	gss_OID mech_oid;
2439	uint32_t major_stat;
2440	uint32_t major, minor;
2441	uint32_t __unused in_gssd_flags = *gssd_flags;
2442
2443	DEBUG(2, "Using mech = %d\n", mech);
2444	DEBUG(3, "\tcred_handle = %p\n", cred_handle);
2445	DEBUG(3, "\tgss_context = %p\n", context);
2446	DEBUG(2, "itokenCnt = %d\n", itokenCnt);
2447	HEXDUMP(2, (char *)itoken, (itokenCnt > 80) ? 80 : itokenCnt);
2448	if (die) {
2449		DEBUG(2, "Forced server death\n");
2450		_exit(0);
2451	}
2452
2453	*gssd_flags = 0;
2454
2455#ifdef WIN2K_HACK
2456	if ((in_gssd_flags & GSSD_WIN2K_HACK) && itokenCnt > 0)
2457		spnego_win2k_hack(&intoken);
2458#endif
2459
2460	major_stat = gss_init_sec_context(
2461					  minor_stat,
2462					  cred_handle,		/* User's credential handle */
2463					  context,		/* Context handle */
2464					  svcid,		/* Target name */
2465					  mechtab[mech],	/* Use the requested mech */
2466					  flags,		/* Request flag bits */
2467					  0,			/* Time requirement */
2468					  NULL,		/* Channel bindings */
2469					  &intoken,		/* Token from context acceptor */
2470					  &mech_oid,		/* Actual mech types */
2471					  &outtoken,		/* Token for the context acceptor */
2472					  ret_flags,		/* Returned flag bits */
2473					  NULL);		/* Time valid */
2474
2475	vm_alloc_buffer(&outtoken, otoken, otokenCnt);
2476	gss_release_buffer(&minor, &outtoken);
2477
2478	if (major_stat == GSS_S_COMPLETE) {
2479		/*
2480		 * If requeseted return a display representation to the caller.
2481		 */
2482		if (displayname) {
2483			major = gss_inquire_context(&minor, *context, &source,
2484						    NULL, NULL, NULL, NULL, NULL, NULL);
2485			if (major == GSS_S_COMPLETE) {
2486				major = gss_display_name(&minor, source, &name_buf, NULL);
2487				if (major == GSS_S_COMPLETE) {
2488					char *s = buf_to_str(&name_buf);
2489					strlcpy(displayname, s, MAX_DISPLAY_STR);
2490					free(s);
2491				}
2492				gss_release_name(&minor, &source);
2493			}
2494		}
2495
2496		if (gss_oid_equal(mech_oid, GSS_NTLM_MECHANISM)) {
2497			gss_buffer_set_t data;
2498
2499			major = gss_inquire_sec_context_by_oid(&minor, *context, GSS_C_NTLM_GUEST, &data);
2500			if (major == GSS_S_COMPLETE) {
2501				uint32_t guest_flag = *(uint32_t *)data->elements->value;
2502				if (guest_flag) {
2503					*gssd_flags |= GSSD_GUEST_ONLY;
2504					DEBUG(3, "\tContext is NTLM simple file sharing %x\n", guest_flag);
2505				} else {
2506					DEBUG(3, "\tContext is NOT NTLM simple file sharing\n");
2507				}
2508				(void) gss_release_buffer_set(&minor, &data);
2509			} else {
2510				Info("gss_inquire_sec_context_by_oid returned %K; %#k", major, mechtab[mech], minor);
2511			}
2512		}
2513
2514		/*
2515		 * Fetch the (sub)session key from the context
2516		 */
2517		major_stat = GetSessionKey(minor_stat, mech_oid, *context,
2518					   skey, skeyCnt);
2519
2520		DEBUG(2, "Client key: length = %d\n", *skeyCnt);
2521		HEXDUMP(2, (char *) *skey, *skeyCnt);
2522	}
2523
2524
2525	OSAtomicIncrement32(&initCnt);
2526	if (major_stat != GSS_S_CONTINUE_NEEDED && major_stat != GSS_S_COMPLETE)
2527		OSAtomicIncrement32(&initErr);
2528
2529	DEBUG(3, "cred = %p\n", cred_handle);
2530	DEBUG(3, "\tgss_context = %p\n", *context);
2531	DEBUG(2, "%sotokenCnt = %d\n", get_debug_level() > 2 ? "\t" : "", *otokenCnt);
2532	HEXDUMP(2, (char *)*otoken, (*otokenCnt > 80) ? 80 : *otokenCnt);
2533	DEBUG(3, "Returning from init %d errors out of a total %d calls\n", initErr, initCnt);
2534
2535
2536
2537	return (major_stat);
2538}
2539
2540/*
2541 * Mig dispatch routine for gss_init_sec_context.
2542 */
2543kern_return_t
2544svc_mach_gss_init_sec_context(
2545	mach_port_t server,
2546	gssd_mechtype mech,
2547	gssd_byte_buffer itoken, mach_msg_type_number_t itokenCnt,
2548	uint32_t uid,
2549	gssd_string princ_namestr,
2550	gssd_string svc_namestr,
2551	uint32_t flags,
2552	uint32_t gssd_flags,
2553	gssd_ctx *gss_context,
2554	gssd_cred *cred_handle,
2555	audit_token_t atok,
2556	uint32_t *ret_flags,
2557	gssd_byte_buffer *skey, mach_msg_type_number_t *skeyCnt,
2558	gssd_byte_buffer *otoken, mach_msg_type_number_t *otokenCnt,
2559	uint32_t *major_stat,
2560	uint32_t *minor_stat)
2561{
2562	kern_return_t kstat;
2563
2564	kstat = svc_mach_gss_init_sec_context_v2(server,
2565						 mech,
2566						 itoken,
2567						 itokenCnt,
2568						 uid,
2569						 GSSD_STRING_NAME,
2570						 (gssd_byte_buffer) princ_namestr,
2571						 (uint32_t) strlen(princ_namestr) + 1,
2572						 GSSD_STRING_NAME,
2573						 (gssd_byte_buffer) svc_namestr,
2574						 (uint32_t) strlen(svc_namestr) + 1,
2575						 flags,
2576						 &gssd_flags,
2577						 gss_context,
2578						 cred_handle,
2579						 atok,
2580						 ret_flags,
2581						 skey,
2582						 skeyCnt,
2583						 otoken,
2584						 otokenCnt,
2585						 NULL,
2586						 major_stat,
2587						 minor_stat);
2588	return (kstat);
2589}
2590
2591kern_return_t
2592svc_mach_gss_init_sec_context_v2(
2593	mach_port_t server __attribute__((unused)),
2594	gssd_mechtype mech,
2595	gssd_byte_buffer itoken,
2596	mach_msg_type_number_t itokenCnt,
2597	uint32_t uid,
2598	gssd_nametype clnt_nt,
2599	gssd_byte_buffer clnt_princ,
2600	mach_msg_type_number_t clnt_princCnt,
2601	gssd_nametype svc_nt,
2602	gssd_byte_buffer svc_princ,
2603	mach_msg_type_number_t svc_princCnt,
2604	uint32_t flags,
2605	uint32_t *gssd_flags,
2606	gssd_ctx *gss_context,
2607	gssd_cred *cred_handle,
2608	audit_token_t atok,
2609	uint32_t *ret_flags,
2610	gssd_byte_buffer *skey,
2611	mach_msg_type_number_t *skeyCnt,
2612	gssd_byte_buffer *otoken,
2613	mach_msg_type_number_t *otokenCnt,
2614	 gssd_dstring displayname,
2615	uint32_t *major_stat,
2616	uint32_t *minor_stat)
2617{
2618	gss_name_t svc_gss_name[MAX_SVC_NAMES];
2619	gss_ctx_id_t g_cntx = GSS_C_NO_CONTEXT;
2620	uint32_t i, gnames = MAX_SVC_NAMES, name_index = MAX_SVC_NAMES;
2621	uint32_t mstat;   /* Minor status for cleaning up. */
2622	vproc_transaction_t gssd_vproc_handle;
2623	uint32_t only_1des = ((*gssd_flags & GSSD_NFS_1DES) != 0);
2624	kern_return_t kr = KERN_SUCCESS;
2625
2626	DEBUG(2, "Enter");
2627
2628	gssd_vproc_handle = vproc_transaction_begin(NULL);
2629	new_worker_thread();
2630
2631	if (!check_audit(atok, FALSE)) {
2632		kr = KERN_NO_ACCESS;
2633		goto out;
2634	}
2635
2636	krb5_set_home_dir_access(NULL, (*gssd_flags & GSSD_HOME_ACCESS_OK) ? 1 : 0);
2637
2638	if (displayname)
2639		*displayname = '\0';
2640
2641	if (!gssd_check(CAST(void *, *gss_context)) || !gssd_check(CAST(void *, *cred_handle))) {
2642		*major_stat = badcall("svc_mach_gss_init_context",
2643				      minor_stat, gss_context, cred_handle,
2644				      gssd_flags,
2645				      skey, skeyCnt,
2646				      otoken, otokenCnt);
2647
2648		kr = KERN_SUCCESS;
2649		goto out;
2650	}
2651
2652	/*
2653	 * Below currently doesn't do anything since the mach defs file has
2654	 * the major_stat as an out parameter, so *major_stat is always going
2655	 * to be 0 (GSS_S_COMPLETE). If we ever rev the protocol we should change
2656	 * that. It's not so bad since gss_init_sec_context will note that the
2657	 * context is invalid and we will destroy the context on returning.
2658	 */
2659	if (*major_stat != GSS_S_CONTINUE_NEEDED && *major_stat != GSS_S_COMPLETE) {
2660		kr = KERN_SUCCESS;
2661		g_cntx = gssd_get_context(*gss_context, svc_gss_name);
2662		goto done;
2663	}
2664
2665	if (*gss_context == CAST(gssd_ctx, GSS_C_NO_CONTEXT)) {
2666
2667		if (no_canon || (*gssd_flags & GSSD_NO_CANON))
2668			gnames = 1;
2669		*major_stat = blob_to_svcnames(minor_stat, svc_nt, svc_princ, svc_princCnt,
2670			mech, svc_gss_name, &gnames);
2671
2672		if (*major_stat != GSS_S_COMPLETE) {
2673			Info("Could not determine service principal name: %#K", *major_stat);
2674			goto done;
2675		}
2676
2677		if (gnames > 1)
2678			Info("Trying the following server principal names:");
2679		for (i = 0; i < gnames; i++) {
2680			char *dname;
2681			gss_buffer_desc bufname;
2682			uint32_t maj, min;
2683			gss_OID oid;
2684			char *oname;
2685
2686			maj = gss_display_name(&min, svc_gss_name[i], &bufname, &oid);
2687			if (maj != GSS_S_COMPLETE)
2688				Info("Cannot determine target name: %K", maj);
2689			else {
2690				dname = buf_to_str(&bufname);
2691				oname = oid_name(oid);
2692				Info("%s %s as %s", (gnames > 1)? "\t" : "Server principal name", dname, oname);
2693				free(dname);
2694				free(oname);
2695			}
2696		}
2697
2698	}
2699	else {
2700		gnames = 1;
2701		g_cntx = gssd_get_context(*gss_context, svc_gss_name);
2702		if ((*gssd_flags & GSSD_RESTART) && g_cntx != GSS_C_NO_CONTEXT)
2703			(void) gss_delete_sec_context(&mstat, &g_cntx, GSS_C_NO_BUFFER);
2704	}
2705	if (*cred_handle &&  (*gssd_flags & GSSD_RESTART)) {
2706		gssd_remove(CAST(void *, *cred_handle));
2707		(void) gss_release_cred(&mstat, (gss_cred_id_t *) cred_handle);
2708	}
2709	if (CAST(gss_cred_id_t, *cred_handle) == GSS_C_NO_CREDENTIAL || (*gssd_flags & GSSD_RESTART)) {
2710		if (clnt_nt == GSSD_STRING_NAME)
2711			*major_stat = do_acquire_cred_v1(minor_stat, (char *)clnt_princ, mech,
2712							 *svc_gss_name, uid, cred_handle, *gssd_flags);
2713		else {
2714			*major_stat = do_acquire_cred(minor_stat, clnt_nt,
2715						      clnt_princ, clnt_princCnt,
2716						      mech, (gss_cred_id_t *) cred_handle);
2717		}
2718		if (*major_stat != GSS_S_COMPLETE)
2719			goto done;
2720		/* ???
2721		 * Currently NFS only supports a subset of the Kerberos enctypes
2722		 * and only suports the kerberos mech. If using a non kerberos
2723		 * credential, gss_krb5_set_allowable_enctypes will fail.
2724		 */
2725		if (is_nfs_service(*svc_gss_name)) {
2726			*major_stat = gss_krb5_set_allowable_enctypes
2727				(minor_stat, *(gss_cred_id_t *)cred_handle,
2728				 NUM_NFS_ENCTYPES - only_1des, NFS_ENCTYPES);
2729			if (*major_stat != GSS_S_COMPLETE) {
2730				Log("Could not set enctypes for NFS\n");
2731				goto done;
2732			}
2733		}
2734		gssd_enter(CAST(void *, *cred_handle));
2735	}
2736
2737	*major_stat = GSS_S_BAD_NAME;
2738	for (i = 0; i < gnames; i++) {
2739
2740		*major_stat = svc_mach_gss_init_sec_context_common(
2741								   mech,
2742								   itoken,
2743								   itokenCnt,
2744								   svc_gss_name[i],
2745								   flags,
2746								   gssd_flags,
2747								   &g_cntx,
2748								   CAST(gss_cred_id_t, *cred_handle),
2749								   ret_flags,
2750								   skey,
2751								   skeyCnt,
2752								   otoken,
2753								   otokenCnt,
2754								   displayname,
2755								   minor_stat);
2756
2757		if (*major_stat == GSS_S_COMPLETE ||
2758		    *major_stat == GSS_S_CONTINUE_NEEDED)
2759			break;
2760	}
2761	name_index = i;
2762
2763	/* Done with the names */
2764	for (i = 0; i < gnames; i++)
2765		if (i != name_index)
2766			(void)gss_release_name(&mstat, &svc_gss_name[i]);
2767
2768	if (*major_stat == GSS_S_CONTINUE_NEEDED) {
2769		*gss_context = gssd_set_context(g_cntx, svc_gss_name[name_index]);
2770		if (*gss_context == 0)
2771			*major_stat = GSS_S_FAILURE;
2772	}
2773
2774done:
2775	Info("svc_mach_gss_init_sec_context_common %K; %#k", *major_stat, mechtab[mech], *minor_stat);
2776	if (*major_stat != GSS_S_CONTINUE_NEEDED) {
2777		/* We're done so free what we allocated */
2778		gssd_remove(CAST(void *, *cred_handle));
2779		(void) gss_release_cred(&mstat, (gss_cred_id_t *) cred_handle);
2780		if (g_cntx != GSS_C_NO_CONTEXT)
2781			(void) gss_delete_sec_context(&mstat, &g_cntx, GSS_C_NO_BUFFER);
2782
2783		if (name_index < gnames)
2784			(void)gss_release_name(&mstat, &svc_gss_name[name_index]);
2785	}
2786
2787out:
2788	end_worker_thread();
2789	vproc_transaction_end(NULL, gssd_vproc_handle);
2790
2791	DEBUG(2, "Exit");
2792
2793	return (kr);
2794
2795}
2796
2797/*
2798 * Mig dispatch routine for gss_accept_sec_context.
2799 */
2800kern_return_t
2801svc_mach_gss_accept_sec_context(
2802	mach_port_t test_port,
2803	gssd_byte_buffer itoken, mach_msg_type_number_t itokenCnt,
2804	gssd_string svc_namestr,
2805	uint32_t gssd_flags,
2806	gssd_ctx *gss_context,
2807	gssd_cred *cred_handle,
2808	audit_token_t atok,
2809	uint32_t *ret_flags,
2810	uint32_t *uid,
2811	gssd_gid_list gids, mach_msg_type_number_t *gidsCnt,
2812	gssd_byte_buffer *skey, mach_msg_type_number_t *skeyCnt,
2813	gssd_byte_buffer *otoken, mach_msg_type_number_t *otokenCnt,
2814	uint32_t *major_stat,
2815	uint32_t *minor_stat)
2816{
2817	kern_return_t kr;
2818
2819	kr = svc_mach_gss_accept_sec_context_v2(test_port,
2820						itoken,
2821						itokenCnt,
2822						GSSD_STRING_NAME,
2823						(gssd_byte_buffer)svc_namestr,
2824						(uint32_t) strlen(svc_namestr) + 1,
2825						&gssd_flags,
2826						gss_context,
2827						cred_handle,
2828						atok,
2829						ret_flags,
2830						uid,
2831						gids,
2832						gidsCnt,
2833						skey,
2834						skeyCnt,
2835						otoken,
2836						otokenCnt,
2837						major_stat,
2838						minor_stat);
2839	return (kr);
2840}
2841
2842kern_return_t
2843svc_mach_gss_accept_sec_context_v2(
2844	mach_port_t server __attribute__((unused)),
2845	gssd_byte_buffer itoken,
2846	mach_msg_type_number_t itokenCnt,
2847	gssd_nametype svc_nt __attribute__((unused)),
2848	gssd_byte_buffer svc_princ __attribute__((unused)),
2849	mach_msg_type_number_t svc_princCnt __attribute__((unused)),
2850	uint32_t *inout_gssd_flags __attribute__((unused)),
2851	gssd_ctx *gss_context,
2852	gssd_cred *cred_handle,
2853	audit_token_t atok,
2854	uint32_t *ret_flags,
2855	uint32_t *uid,
2856	gssd_gid_list gids,
2857	mach_msg_type_number_t *gidsCnt,
2858	gssd_byte_buffer *skey,
2859	mach_msg_type_number_t *skeyCnt,
2860	gssd_byte_buffer *otoken,
2861	mach_msg_type_number_t *otokenCnt,
2862	uint32_t *major_stat,
2863	uint32_t *minor_stat)
2864{
2865	gss_ctx_id_t g_cntx = GSS_C_NO_CONTEXT;
2866	gss_name_t princ;
2867	gss_OID oid;
2868	uint32_t mstat;    /* Minor status to clean up with. */
2869	kern_return_t kr = KERN_SUCCESS;
2870	vproc_transaction_t gssd_vproc_handle;
2871
2872	DEBUG(2, "Enter");
2873	gssd_vproc_handle = vproc_transaction_begin(NULL);
2874	new_worker_thread();
2875
2876	if (!check_audit(atok, FALSE)) {
2877		kr = KERN_NO_ACCESS;
2878		goto out;
2879	}
2880
2881	krb5_set_home_dir_access(NULL, ((*inout_gssd_flags) & GSSD_HOME_ACCESS_OK) ? 1 : 0);
2882
2883	*inout_gssd_flags = 0;
2884
2885	/* Set the uid to nobody to be safe */
2886	*uid = NobodyUid;
2887
2888	if (die) {
2889		DEBUG(2, "Forced server death\n");
2890		_exit(0);
2891	}
2892
2893	if (!gssd_check(CAST(void *, *gss_context)) || !gssd_check(CAST(void *, *cred_handle))) {
2894		*major_stat = badcall("svc_mach_gss_accept_sec_context",
2895				      minor_stat, gss_context, cred_handle,
2896				      inout_gssd_flags,
2897				      skey, skeyCnt, otoken, otokenCnt);
2898
2899		end_worker_thread();
2900		vproc_transaction_end(NULL, gssd_vproc_handle);
2901
2902		return (KERN_SUCCESS);
2903	}
2904
2905	g_cntx = gssd_get_context(*gss_context, NULL);
2906	gss_buffer_desc intoken = {itokenCnt, itoken};
2907	gss_buffer_desc outtoken = {0, NULL};;
2908	*major_stat = 0;
2909	*minor_stat = 0;
2910
2911	DEBUG(4, "minor_stat = %d\n", (int) *minor_stat);
2912	DEBUG(4, "\tcred = %p\n", (void *)(uintptr_t)*cred_handle);
2913	DEBUG(4, "\tgss_context = %p\n", g_cntx);
2914	DEBUG(3, "itokenCnt = %d\n", itokenCnt);
2915	HEXDUMP(3, (char *)itoken, (itokenCnt > 80) ? 80 : itokenCnt);
2916
2917	*major_stat = gss_accept_sec_context(
2918					     minor_stat,
2919					     &g_cntx,			// Context handle
2920					     CAST(gss_cred_id_t, *cred_handle),	// Acceptor's credential handle
2921					     &intoken,			// Token from context initiator
2922					     GSS_C_NO_CHANNEL_BINDINGS,	// Channel bindings
2923					     &princ,				// Context initiator's name
2924					     &oid,				// Mech types
2925					     &outtoken,			// Token for context initiator
2926					     ret_flags,			// Flags out
2927					     NULL,				// Time requirement
2928					     NULL);				// Delegated creds
2929
2930	vm_alloc_buffer(&outtoken, otoken, otokenCnt);
2931	gss_release_buffer(&mstat, &outtoken);
2932
2933	if (*major_stat == GSS_S_COMPLETE ) {
2934		/*
2935		 * Turn the principal name into UNIX creds
2936		 */
2937		*major_stat = gss_name_to_ucred(minor_stat, princ,
2938						uid, gids, gidsCnt);
2939		if (*major_stat != GSS_S_COMPLETE) {
2940			kr = KERN_FAILURE;
2941			goto done;
2942		}
2943		/*
2944		 * Fetch the (sub)session key from the context
2945		 */
2946		*major_stat = GetSessionKey(minor_stat, oid, g_cntx,
2947					    skey, skeyCnt);
2948
2949		DEBUG(2, "Server key length = %d\n", *skeyCnt);
2950		HEXDUMP(2, (char *) *skey, *skeyCnt);
2951	} else if (*major_stat == GSS_S_CONTINUE_NEEDED) {
2952		*gss_context = gssd_set_context(g_cntx, NULL);
2953		if (*gss_context == 0)
2954			*major_stat = GSS_S_FAILURE;
2955
2956		/*
2957		 * Register our context handle
2958		 */
2959		gssd_enter(CAST(void *, *gss_context));
2960	}
2961	if (*major_stat == GSS_S_COMPLETE || *major_stat == GSS_S_CONTINUE_NEEDED) {
2962		DEBUG(3, "otokenCnt = %d", *otokenCnt);
2963		HEXDUMP(3, (char *)*otoken, (*otokenCnt > 80) ? 80 : *otokenCnt);
2964	}
2965done:
2966	gss_release_name(&mstat, &princ);
2967	if (*major_stat != GSS_S_CONTINUE_NEEDED) {
2968		gssd_remove(CAST(void *, *cred_handle));
2969		(void)gss_release_cred(&mstat, (gss_cred_id_t *) cred_handle);
2970		if (g_cntx != GSS_C_NO_CONTEXT)
2971			(void) gss_delete_sec_context(&mstat, &g_cntx, GSS_C_NO_BUFFER);
2972	}
2973
2974	OSAtomicIncrement32(&acceptCnt);
2975	if (*major_stat != GSS_S_CONTINUE_NEEDED && *major_stat != GSS_S_COMPLETE)
2976		OSAtomicIncrement32(&acceptErr);
2977	DEBUG(3, "Returning from accept %d erros of of %d total calls\n", acceptErr, acceptCnt);
2978
2979	Info("gss_accept_sec_context %K; %#k", *major_stat, oid, *minor_stat);
2980out:
2981	end_worker_thread();
2982	vproc_transaction_end(NULL, gssd_vproc_handle);
2983
2984	DEBUG(2, "Exit");
2985
2986	return (kr);
2987}
2988
2989
2990#define MSG(f, ...) do {\
2991	if (f) { \
2992		Debug(__VA_ARGS__); \
2993	} else { \
2994		Log(__VA_ARGS__); \
2995	} \
2996} while (0)
2997
2998
2999
3000/*
3001 * Mig dispatch routine to log GSS-API errors
3002 */
3003kern_return_t
3004svc_mach_gss_log_error(
3005	mach_port_t test_port __attribute__((unused)),
3006	gssd_string mnt,
3007	uint32_t uid,
3008	gssd_string source,
3009	uint32_t major,
3010	uint32_t minor,
3011	audit_token_t atok)
3012{
3013	OM_uint32 msg_context = 0;
3014	OM_uint32 min_stat = 0;
3015	OM_uint32 maj_stat = 0;
3016	gss_buffer_desc errBuf;
3017	char msgbuf[1024];
3018	char *errStr;
3019	int full = 0;
3020	vproc_transaction_t gssd_vproc_handle;
3021	kern_return_t kr = KERN_SUCCESS;
3022
3023	DEBUG(2, "Enter");
3024	gssd_vproc_handle = vproc_transaction_begin(NULL);
3025	new_worker_thread();
3026
3027	if (!check_audit(atok, FALSE)) {
3028		kr = KERN_NO_ACCESS;
3029		goto out;
3030	}
3031
3032	(void) snprintf(msgbuf, sizeof(msgbuf), "nfs %s Kerberos: %s, uid=%d",
3033		source, mnt, uid);
3034
3035	/*
3036	 * Start with the major error string(s)
3037	 * The strings are concatenated into a fixed size log
3038	 * message buffer.  If the messages exceed the buffer
3039	 * size then we truncate.
3040	 */
3041	do {
3042		if (major == GSS_S_FAILURE)	// more info in minor msg
3043			break;
3044		maj_stat = gss_display_status(&min_stat, major, GSS_C_GSS_CODE,
3045					GSS_C_NULL_OID, &msg_context, &errBuf);
3046		errStr = buf_to_str(&errBuf);
3047		if (maj_stat != GSS_S_COMPLETE)
3048			goto done;
3049		full = strlcat(msgbuf, " - ", sizeof(msgbuf)) >= sizeof(msgbuf) ||
3050		    strlcat(msgbuf, errStr, sizeof(msgbuf)) >= sizeof(msgbuf);
3051		free(errStr);
3052		if (full)
3053			goto done;
3054	} while (msg_context != 0);
3055
3056	/*
3057	 * Append any minor error string(s)
3058	 */
3059	msg_context = 0;
3060	do {
3061		maj_stat = gss_display_status (&min_stat, minor, GSS_C_MECH_CODE,
3062					GSS_C_NULL_OID, &msg_context, &errBuf);
3063		errStr = buf_to_str(&errBuf);
3064		if (maj_stat != GSS_S_COMPLETE)
3065			goto done;
3066		full = strlcat(msgbuf, " - ", sizeof(msgbuf)) >= sizeof(msgbuf) ||
3067		    strlcat(msgbuf, errStr, sizeof(msgbuf)) >= sizeof(msgbuf);
3068		free(errStr);
3069		if (full)
3070			goto done;
3071	} while (msg_context != 0);
3072
3073done:
3074	MSG((major == GSS_S_NO_CRED), "%s", msgbuf);
3075
3076out:
3077	end_worker_thread();
3078	vproc_transaction_end(NULL, gssd_vproc_handle);
3079
3080	return (kr);
3081}
3082
3083kern_return_t
3084svc_mach_gss_hold_cred(mach_port_t server __unused,
3085		       gssd_mechtype mech,
3086		       gssd_nametype nt,
3087		       gssd_byte_buffer princ,
3088		       mach_msg_type_number_t princCnt,
3089		       audit_token_t atok,
3090		       uint32_t *major_stat,
3091		       uint32_t *minor_stat)
3092{
3093	gss_cred_id_t cred = NULL;
3094	uint32_t m;
3095	vproc_transaction_t gssd_vproc_handle;
3096	kern_return_t kr = KERN_SUCCESS;
3097
3098	DEBUG(2, "Enter");
3099	gssd_vproc_handle = vproc_transaction_begin(NULL);
3100	new_worker_thread();
3101
3102	if (!check_audit(atok, FALSE)) {
3103		kr = KERN_NO_ACCESS;
3104		goto out;
3105	}
3106
3107	*major_stat = do_acquire_cred(minor_stat, nt, princ, princCnt, mech, &cred);
3108	if (*major_stat != GSS_S_COMPLETE)
3109		goto out;
3110	*major_stat = gss_cred_hold(minor_stat, cred);
3111	(void) gss_release_cred(&m, &cred);
3112
3113out:
3114	end_worker_thread();
3115	vproc_transaction_end(NULL, gssd_vproc_handle);
3116
3117	return (kr);
3118}
3119
3120kern_return_t
3121svc_mach_gss_unhold_cred(mach_port_t server __unused,
3122			 gssd_mechtype mech,
3123			 gssd_nametype nt,
3124			 gssd_byte_buffer princ,
3125			 mach_msg_type_number_t princCnt,
3126			 audit_token_t atok,
3127			 uint32_t *major_stat,
3128			 uint32_t *minor_stat)
3129{
3130	gss_cred_id_t cred = NULL;
3131	uint32_t m;
3132	vproc_transaction_t gssd_vproc_handle;
3133	kern_return_t kr = KERN_SUCCESS;
3134
3135	DEBUG(2, "Enter");
3136	gssd_vproc_handle = vproc_transaction_begin(NULL);
3137	new_worker_thread();
3138
3139	if (!check_audit(atok, FALSE)) {
3140		kr = KERN_NO_ACCESS;
3141		goto out;
3142	}
3143
3144	*major_stat = do_acquire_cred(minor_stat, nt, princ, princCnt, mech, &cred);
3145	if (*major_stat != GSS_S_COMPLETE)
3146		goto out;
3147	*major_stat = gss_cred_unhold(minor_stat, cred);
3148	(void) gss_release_cred(&m, &cred);
3149
3150out:
3151	end_worker_thread();
3152	vproc_transaction_end(NULL, gssd_vproc_handle);
3153	return (kr);
3154}
3155
3156kern_return_t
3157svc_mach_gss_lookup(mach_port_t server,
3158		    uint32_t uid,
3159		    int32_t asid,
3160		    audit_token_t atok,
3161		    mach_port_t *gssd_port)
3162{
3163	kern_return_t kr = KERN_SUCCESS;
3164	uuid_t uuid;
3165	uuid_string_t uuidstr;
3166	vproc_transaction_t gssd_vproc_handle;
3167
3168	DEBUG(2, "Enter");
3169	gssd_vproc_handle = vproc_transaction_begin(NULL);
3170	new_worker_thread();
3171
3172	if (!check_audit(atok, kernel_only)) {
3173		kr = KERN_NO_ACCESS;
3174		goto out;
3175	}
3176
3177	*gssd_port = MACH_PORT_NULL;
3178	if (!check_session(asid)) {
3179		*gssd_port = server;
3180	} else {
3181		sessioninfo2uuid((uid_t)uid, (au_asid_t)asid, uuid);
3182		uuid_unparse(uuid, uuidstr);
3183		DEBUG(2, "Looking up %s for %d %d as instance %s", bname, uid, asid, uuidstr);
3184
3185		kr = bootstrap_look_up3(bootstrap_port, bname, gssd_port, 0, uuid, BOOTSTRAP_SPECIFIC_INSTANCE);
3186		if (kr != KERN_SUCCESS)
3187			Log("Could not lookup per instance port %d: %s", kr, bootstrap_strerror(kr));
3188
3189		DEBUG(2, "bootstap_look_up3 = %d port = %d,  server port = %d", kr, *gssd_port, server);
3190	}
3191out:
3192	end_worker_thread();
3193	vproc_transaction_end(NULL, gssd_vproc_handle);
3194	return (kr);
3195}
3196