xref: /illumos-gate/usr/src/cmd/smbsrv/smbd/smbd_authsvc.c (revision a99cb9618990662acbd3bab1b4a5b05a6ca62556)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
14  */
15 
16 /*
17  * SMB authentication service
18  *
19  * This service listens on a local AF_UNIX socket, spawning a
20  * thread to service each connection.  The client-side of such
21  * connections is the in-kernel SMB service, with an open and
22  * connect done in the SMB session setup handler.
23  */
24 
25 #include <sys/types.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <strings.h>
30 #include <unistd.h>
31 #include <signal.h>
32 #include <stdio.h>
33 #include <note.h>
34 #include <net/if.h>
35 #include <net/route.h>
36 #include <sys/sockio.h>
37 #include <sys/socket.h>
38 #include <sys/un.h>
39 #include <netinet/in.h>
40 #include <fcntl.h>
41 #include <pthread.h>
42 #include <syslog.h>
43 #include <smbsrv/libsmb.h>
44 #include <netsmb/spnego.h>
45 
46 #include "smbd.h"
47 #include "smbd_authsvc.h"
48 
49 /* Arbitrary value outside the (small) range of valid OIDs */
50 #define	special_mech_raw_NTLMSSP	(spnego_mech_oid_NTLMSSP + 100)
51 
52 static struct sockaddr_un smbauth_sockname = {
53 	AF_UNIX, SMB_AUTHSVC_SOCKNAME };
54 
55 typedef struct spnego_mech_handler {
56 	int mh_oid; /* SPNEGO_MECH_OID */
57 	int (*mh_init)(authsvc_context_t *);
58 	int (*mh_work)(authsvc_context_t *);
59 	void (*mh_fini)(authsvc_context_t *);
60 } spnego_mech_handler_t;
61 
62 static int smbd_authsock_create(void);
63 static void smbd_authsock_destroy(void);
64 static void *smbd_authsvc_listen(void *);
65 static void *smbd_authsvc_work(void *);
66 static void smbd_authsvc_flood(void);
67 
68 static int smbd_authsvc_oldreq(authsvc_context_t *);
69 static int smbd_authsvc_clinfo(authsvc_context_t *);
70 static int smbd_authsvc_esfirst(authsvc_context_t *);
71 static int smbd_authsvc_esnext(authsvc_context_t *);
72 static int smbd_authsvc_escmn(authsvc_context_t *);
73 static int smbd_authsvc_gettoken(authsvc_context_t *);
74 static int smbd_raw_ntlmssp_esfirst(authsvc_context_t *);
75 static int smbd_raw_ntlmssp_esnext(authsvc_context_t *);
76 
77 /*
78  * We can get relatively large tokens now, thanks to krb5 PAC.
79  * Might be better to size these buffers dynamically, but these
80  * are all short-lived so not bothering with that for now.
81  */
82 int smbd_authsvc_bufsize = 65000;
83 
84 static mutex_t smbd_authsvc_mutex = DEFAULTMUTEX;
85 
86 /*
87  * The maximum number of authentication thread is limited by the
88  * smbsrv smb_threshold_...(->sv_ssetup_ct) mechanism.  However,
89  * due to occasional delays closing these auth. sockets, we need
90  * a little "slack" on the number of threads we'll allow, as
91  * compared with the in-kernel limit.  We could perhaps just
92  * remove this limit now, but want it for extra safety.
93  */
94 int smbd_authsvc_maxthread = SMB_AUTHSVC_MAXTHREAD + 32;
95 int smbd_authsvc_thrcnt = 0;	/* current thrcnt */
96 int smbd_authsvc_hiwat = 0;	/* largest thrcnt seen */
97 #ifdef DEBUG
98 int smbd_authsvc_slowdown = 0;
99 #endif
100 
101 /*
102  * These are the mechanisms we support, in order of preference.
103  * But note: it's really the _client's_ preference that matters.
104  * See &pref in the spnegoIsMechTypeAvailable() calls below.
105  * Careful with this table; the code below knows its format and
106  * may skip the fist two entries to omit Kerberos.
107  */
108 static const spnego_mech_handler_t
109 mech_table[] = {
110 	{
111 		spnego_mech_oid_Kerberos_V5,
112 		smbd_krb5ssp_init,
113 		smbd_krb5ssp_work,
114 		smbd_krb5ssp_fini
115 	},
116 	{
117 		spnego_mech_oid_Kerberos_V5_Legacy,
118 		smbd_krb5ssp_init,
119 		smbd_krb5ssp_work,
120 		smbd_krb5ssp_fini
121 	},
122 #define	MECH_TBL_IDX_NTLMSSP	2
123 	{
124 		spnego_mech_oid_NTLMSSP,
125 		smbd_ntlmssp_init,
126 		smbd_ntlmssp_work,
127 		smbd_ntlmssp_fini
128 	},
129 	{
130 		/* end marker */
131 		spnego_mech_oid_NotUsed,
132 		NULL, NULL, NULL
133 	},
134 };
135 
136 static const spnego_mech_handler_t
137 smbd_auth_mech_raw_ntlmssp = {
138 	special_mech_raw_NTLMSSP,
139 	smbd_ntlmssp_init,
140 	smbd_ntlmssp_work,
141 	smbd_ntlmssp_fini
142 };
143 
144 
145 /*
146  * Start the authentication service.
147  * Returns non-zero on error.
148  */
149 int
150 smbd_authsvc_start(void)
151 {
152 	pthread_attr_t	attr;
153 	pthread_t	tid;
154 	int		rc;
155 
156 	rc = smbd_authsock_create();
157 	if (rc)
158 		return (rc);
159 
160 	(void) pthread_attr_init(&attr);
161 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
162 	rc = pthread_create(&tid, &attr, smbd_authsvc_listen, &smbd);
163 	(void) pthread_attr_destroy(&attr);
164 	if (rc) {
165 		smbd_authsock_destroy();
166 		return (rc);
167 	}
168 
169 	smbd.s_authsvc_tid = tid;
170 	return (0);
171 }
172 
173 void
174 smbd_authsvc_stop(void)
175 {
176 
177 	if (smbd.s_authsvc_tid != 0) {
178 		(void) pthread_kill(smbd.s_authsvc_tid, SIGTERM);
179 		smbd.s_authsvc_tid = 0;
180 	}
181 }
182 
183 static int
184 smbd_authsock_create(void)
185 {
186 	int sock = -1;
187 
188 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
189 	if (sock < 0) {
190 		smbd_report("authsvc, socket create failed, %d", errno);
191 		return (errno);
192 	}
193 
194 	(void) unlink(smbauth_sockname.sun_path);
195 	if (bind(sock, (struct sockaddr *)&smbauth_sockname,
196 	    sizeof (smbauth_sockname)) < 0) {
197 		smbd_report("authsvc, socket bind failed, %d", errno);
198 		(void) close(sock);
199 		return (errno);
200 	}
201 
202 	if (listen(sock, SOMAXCONN) < 0) {
203 		smbd_report("authsvc, socket listen failed, %d", errno);
204 		(void) close(sock);
205 		return (errno);
206 	}
207 
208 	smbd.s_authsvc_sock = sock;
209 	return (0);
210 }
211 
212 static void
213 smbd_authsock_destroy(void)
214 {
215 	int fid;
216 
217 	if ((fid = smbd.s_authsvc_sock) != -1) {
218 		smbd.s_authsvc_sock = -1;
219 		(void) close(fid);
220 	}
221 }
222 
223 static void *
224 smbd_authsvc_listen(void *arg)
225 {
226 	authsvc_context_t *ctx;
227 	pthread_attr_t	attr;
228 	pthread_t	tid;
229 	socklen_t	slen;
230 	int		ls, ns, rc;
231 
232 	_NOTE(ARGUNUSED(arg))
233 
234 	(void) pthread_attr_init(&attr);
235 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
236 
237 	ls = smbd.s_authsvc_sock;
238 	for (;;) {
239 
240 		slen = 0;
241 		ns = accept(ls, NULL, &slen);
242 		if (ns < 0) {
243 			switch (errno) {
244 			case ECONNABORTED:
245 				continue;
246 			case EINTR:
247 				/* normal termination */
248 				goto out;
249 			default:
250 				smbd_report("authsvc, socket accept failed,"
251 				    " %d", errno);
252 				goto out;
253 			}
254 		}
255 
256 		/*
257 		 * Limit the number of auth. sockets
258 		 * (and the threads that service them).
259 		 */
260 		(void) mutex_lock(&smbd_authsvc_mutex);
261 		if (smbd_authsvc_thrcnt >= smbd_authsvc_maxthread) {
262 			(void) mutex_unlock(&smbd_authsvc_mutex);
263 			(void) close(ns);
264 			smbd_authsvc_flood();
265 			continue;
266 		}
267 		smbd_authsvc_thrcnt++;
268 		if (smbd_authsvc_hiwat < smbd_authsvc_thrcnt)
269 			smbd_authsvc_hiwat = smbd_authsvc_thrcnt;
270 		(void) mutex_unlock(&smbd_authsvc_mutex);
271 
272 		ctx = smbd_authctx_create();
273 		if (ctx == NULL) {
274 			smbd_report("authsvc, can't allocate context");
275 			(void) mutex_lock(&smbd_authsvc_mutex);
276 			smbd_authsvc_thrcnt--;
277 			(void) mutex_unlock(&smbd_authsvc_mutex);
278 			(void) close(ns);
279 			goto out;
280 		}
281 		ctx->ctx_socket = ns;
282 
283 		rc = pthread_create(&tid, &attr, smbd_authsvc_work, ctx);
284 		if (rc) {
285 			smbd_report("authsvc, thread create failed, %d", rc);
286 			(void) mutex_lock(&smbd_authsvc_mutex);
287 			smbd_authsvc_thrcnt--;
288 			(void) mutex_unlock(&smbd_authsvc_mutex);
289 			smbd_authctx_destroy(ctx);
290 			goto out;
291 		}
292 		ctx = NULL; /* given to the new thread */
293 	}
294 
295 out:
296 	(void) pthread_attr_destroy(&attr);
297 	smbd_authsock_destroy();
298 	return (NULL);
299 }
300 
301 static void
302 smbd_authsvc_flood(void)
303 {
304 	static uint_t count;
305 	static time_t last_report;
306 	time_t now = time(NULL);
307 
308 	count++;
309 	if (last_report + 60 < now) {
310 		last_report = now;
311 		smbd_report("authsvc: flooded %u", count);
312 		count = 0;
313 	}
314 }
315 
316 authsvc_context_t *
317 smbd_authctx_create(void)
318 {
319 	authsvc_context_t *ctx;
320 
321 	ctx = malloc(sizeof (*ctx));
322 	if (ctx == NULL)
323 		return (NULL);
324 	bzero(ctx, sizeof (*ctx));
325 
326 	ctx->ctx_irawlen = smbd_authsvc_bufsize;
327 	ctx->ctx_irawbuf = malloc(ctx->ctx_irawlen);
328 	ctx->ctx_orawlen = smbd_authsvc_bufsize;
329 	ctx->ctx_orawbuf = malloc(ctx->ctx_orawlen);
330 	if (ctx->ctx_irawbuf == NULL || ctx->ctx_orawbuf == NULL)
331 		goto errout;
332 
333 	ctx->ctx_ibodylen = smbd_authsvc_bufsize;
334 	ctx->ctx_ibodybuf = malloc(ctx->ctx_ibodylen);
335 	ctx->ctx_obodylen = smbd_authsvc_bufsize;
336 	ctx->ctx_obodybuf = malloc(ctx->ctx_obodylen);
337 	if (ctx->ctx_ibodybuf == NULL || ctx->ctx_obodybuf == NULL)
338 		goto errout;
339 
340 	return (ctx);
341 
342 errout:
343 	smbd_authctx_destroy(ctx);
344 	return (NULL);
345 }
346 
347 void
348 smbd_authctx_destroy(authsvc_context_t *ctx)
349 {
350 	if (ctx->ctx_socket != -1) {
351 		(void) close(ctx->ctx_socket);
352 		ctx->ctx_socket = -1;
353 	}
354 
355 	if (ctx->ctx_token != NULL)
356 		smb_token_destroy(ctx->ctx_token);
357 
358 	if (ctx->ctx_itoken != NULL)
359 		spnegoFreeData(ctx->ctx_itoken);
360 	if (ctx->ctx_otoken != NULL)
361 		spnegoFreeData(ctx->ctx_otoken);
362 
363 	free(ctx->ctx_irawbuf);
364 	free(ctx->ctx_orawbuf);
365 	free(ctx->ctx_ibodybuf);
366 	free(ctx->ctx_obodybuf);
367 
368 	free(ctx);
369 }
370 
371 /*
372  * Limit how long smbd_authsvc_work will wait for the client to
373  * send us the next part of the authentication sequence.
374  */
375 static struct timeval recv_tmo = { 30, 0 };
376 
377 /*
378  * Also set a timeout for send, where we're sending a response to
379  * the client side (in smbsrv).  That should always be waiting in
380  * recv by the time we send, so a short timeout is OK.
381  */
382 static struct timeval send_tmo = { 15, 0 };
383 
384 static void *
385 smbd_authsvc_work(void *arg)
386 {
387 	authsvc_context_t *ctx = arg;
388 	smb_lsa_msg_hdr_t	hdr;
389 	int sock = ctx->ctx_socket;
390 	int len, rc;
391 
392 	if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
393 	    (char *)&send_tmo,  sizeof (send_tmo)) != 0) {
394 		smbd_report("authsvc_work: set set timeout: %m");
395 		goto out;
396 	}
397 
398 	if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
399 	    (char *)&recv_tmo,  sizeof (recv_tmo)) != 0) {
400 		smbd_report("authsvc_work: set recv timeout: %m");
401 		goto out;
402 	}
403 
404 	for (;;) {
405 
406 		len = recv(sock, &hdr, sizeof (hdr), MSG_WAITALL);
407 		if (len <= 0) {
408 			/* normal termination */
409 			break;
410 		}
411 		if (len != sizeof (hdr)) {
412 			smbd_report("authsvc_work: read header failed");
413 			break;
414 		}
415 
416 		if (hdr.lmh_msglen > smbd_authsvc_bufsize) {
417 			smbd_report("authsvc_work: msg too large");
418 			break;
419 		}
420 
421 		if (hdr.lmh_msglen > 0) {
422 			len = recv(sock, ctx->ctx_irawbuf, hdr.lmh_msglen,
423 			    MSG_WAITALL);
424 			if (len != hdr.lmh_msglen) {
425 				smbd_report("authsvc_work: read mesg failed");
426 				break;
427 			}
428 		}
429 		ctx->ctx_irawtype = hdr.lmh_msgtype;
430 		ctx->ctx_irawlen = hdr.lmh_msglen;
431 		ctx->ctx_orawlen = smbd_authsvc_bufsize;
432 		ctx->ctx_ibodylen = smbd_authsvc_bufsize;
433 		ctx->ctx_obodylen = smbd_authsvc_bufsize;
434 
435 		/*
436 		 * The real work happens here.
437 		 */
438 		rc = smbd_authsvc_dispatch(ctx);
439 		if (rc)
440 			break;
441 
442 		hdr.lmh_msgtype = ctx->ctx_orawtype;
443 		hdr.lmh_msglen = ctx->ctx_orawlen;
444 		len = send(sock, &hdr, sizeof (hdr), 0);
445 		if (len != sizeof (hdr)) {
446 			smbd_report("authsvc_work: send failed");
447 			break;
448 		}
449 
450 		if (ctx->ctx_orawlen > 0) {
451 			len = send(sock, ctx->ctx_orawbuf,
452 			    ctx->ctx_orawlen, 0);
453 			if (len != ctx->ctx_orawlen) {
454 				smbd_report("authsvc_work: send failed");
455 				break;
456 			}
457 		}
458 	}
459 
460 out:
461 	if (ctx->ctx_mh_fini)
462 		(ctx->ctx_mh_fini)(ctx);
463 
464 	smbd_authctx_destroy(ctx);
465 
466 	(void) mutex_lock(&smbd_authsvc_mutex);
467 	smbd_authsvc_thrcnt--;
468 	(void) mutex_unlock(&smbd_authsvc_mutex);
469 
470 	return (NULL);	/* implied pthread_exit() */
471 }
472 
473 /*
474  * Dispatch based on message type LSA_MTYPE_...
475  * Non-zero return here ends the conversation.
476  */
477 int
478 smbd_authsvc_dispatch(authsvc_context_t *ctx)
479 {
480 	int rc;
481 
482 	switch (ctx->ctx_irawtype) {
483 
484 	case LSA_MTYPE_OLDREQ:
485 #ifdef DEBUG
486 		if (smbd_authsvc_slowdown)
487 			(void) sleep(smbd_authsvc_slowdown);
488 #endif
489 		rc = smbd_authsvc_oldreq(ctx);
490 		break;
491 
492 	case LSA_MTYPE_CLINFO:
493 		rc = smbd_authsvc_clinfo(ctx);
494 		break;
495 
496 	case LSA_MTYPE_ESFIRST:
497 		rc = smbd_authsvc_esfirst(ctx);
498 		break;
499 
500 	case LSA_MTYPE_ESNEXT:
501 #ifdef DEBUG
502 		if (smbd_authsvc_slowdown)
503 			(void) sleep(smbd_authsvc_slowdown);
504 #endif
505 		rc = smbd_authsvc_esnext(ctx);
506 		break;
507 
508 	case LSA_MTYPE_GETTOK:
509 		rc = smbd_authsvc_gettoken(ctx);
510 		break;
511 
512 		/* response types */
513 	case LSA_MTYPE_OK:
514 	case LSA_MTYPE_ERROR:
515 	case LSA_MTYPE_TOKEN:
516 	case LSA_MTYPE_ES_CONT:
517 	case LSA_MTYPE_ES_DONE:
518 	default:
519 		return (-1);
520 	}
521 
522 	if (rc != 0) {
523 		smb_lsa_eresp_t *er = ctx->ctx_orawbuf;
524 		ctx->ctx_orawtype = LSA_MTYPE_ERROR;
525 		ctx->ctx_orawlen = sizeof (*er);
526 		er->ler_ntstatus = rc;
527 		er->ler_errclass = 0;
528 		er->ler_errcode = 0;
529 	}
530 	return (0);
531 }
532 
533 static int
534 smbd_authsvc_oldreq(authsvc_context_t *ctx)
535 {
536 	smb_logon_t	user_info;
537 	XDR		xdrs;
538 	smb_token_t	*token = NULL;
539 	int		rc = 0;
540 
541 	bzero(&user_info, sizeof (user_info));
542 	xdrmem_create(&xdrs, ctx->ctx_irawbuf, ctx->ctx_irawlen,
543 	    XDR_DECODE);
544 	if (!smb_logon_xdr(&xdrs, &user_info)) {
545 		xdr_destroy(&xdrs);
546 		return (NT_STATUS_INVALID_PARAMETER);
547 	}
548 	xdr_destroy(&xdrs);
549 
550 	token = smbd_user_auth_logon(&user_info);
551 	xdr_free(smb_logon_xdr, (char *)&user_info);
552 	if (token == NULL) {
553 		rc = user_info.lg_status;
554 		if (rc == 0) /* should not happen */
555 			rc = NT_STATUS_INTERNAL_ERROR;
556 		return (rc);
557 	}
558 
559 	ctx->ctx_token = token;
560 
561 	return (rc);
562 }
563 
564 static int
565 smbd_authsvc_clinfo(authsvc_context_t *ctx)
566 {
567 
568 	if (ctx->ctx_irawlen != sizeof (smb_lsa_clinfo_t))
569 		return (NT_STATUS_INTERNAL_ERROR);
570 	(void) memcpy(&ctx->ctx_clinfo, ctx->ctx_irawbuf,
571 	    sizeof (smb_lsa_clinfo_t));
572 
573 	ctx->ctx_orawtype = LSA_MTYPE_OK;
574 	ctx->ctx_orawlen = 0;
575 	return (0);
576 }
577 
578 /*
579  * Handle a security blob we've received from the client.
580  * Incoming type: LSA_MTYPE_ESFIRST
581  * Outgoing types: LSA_MTYPE_ES_CONT, LSA_MTYPE_ES_DONE,
582  *   LSA_MTYPE_ERROR
583  */
584 static int
585 smbd_authsvc_esfirst(authsvc_context_t *ctx)
586 {
587 	const spnego_mech_handler_t *mh;
588 	int idx, pref, rc;
589 	int best_pref = 1000;
590 	int best_mhidx = -1;
591 
592 	/*
593 	 * NTLMSSP header is 8+, SPNEGO is 10+
594 	 */
595 	if (ctx->ctx_irawlen < 8) {
596 		smbd_report("authsvc: short blob");
597 		return (NT_STATUS_INVALID_PARAMETER);
598 	}
599 
600 	/*
601 	 * We could have "Raw NTLMSSP" here intead of SPNEGO.
602 	 */
603 	if (bcmp(ctx->ctx_irawbuf, "NTLMSSP", 8) == 0) {
604 		rc = smbd_raw_ntlmssp_esfirst(ctx);
605 		return (rc);
606 	}
607 
608 	/*
609 	 * Parse the SPNEGO token, check its type.
610 	 */
611 	rc = spnegoInitFromBinary(ctx->ctx_irawbuf,
612 	    ctx->ctx_irawlen, &ctx->ctx_itoken);
613 	if (rc != 0) {
614 		smbd_report("authsvc: spnego parse failed");
615 		return (NT_STATUS_INVALID_PARAMETER);
616 	}
617 
618 	rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype);
619 	if (rc != 0) {
620 		smbd_report("authsvc: spnego get token type failed");
621 		return (NT_STATUS_INVALID_PARAMETER);
622 	}
623 
624 	if (ctx->ctx_itoktype != SPNEGO_TOKEN_INIT) {
625 		smbd_report("authsvc: spnego wrong token type %d",
626 		    ctx->ctx_itoktype);
627 		return (NT_STATUS_INVALID_PARAMETER);
628 	}
629 
630 	/*
631 	 * Figure out which mech type to use.  We want to use the
632 	 * first of the client's supported mechanisms that we also
633 	 * support.  Unfortunately, the spnego code does not have an
634 	 * interface to walk the token's mech list, so we have to
635 	 * ask about each mech type we know and keep track of which
636 	 * was earliest in the token's mech list.
637 	 *
638 	 * Also, skip the Kerberos mechanisms in workgroup mode.
639 	 */
640 	idx = 0;
641 	mh = mech_table;
642 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) {
643 		idx = MECH_TBL_IDX_NTLMSSP;
644 		mh = &mech_table[idx];
645 	}
646 	for (; mh->mh_init != NULL; idx++, mh++) {
647 
648 		if (spnegoIsMechTypeAvailable(ctx->ctx_itoken,
649 		    mh->mh_oid, &pref) != 0)
650 			continue;
651 
652 		if (pref < best_pref) {
653 			best_pref = pref;
654 			best_mhidx = idx;
655 		}
656 	}
657 	if (best_mhidx == -1) {
658 		smbd_report("authsvc: no supported spnego mechanism");
659 		return (NT_STATUS_INVALID_PARAMETER);
660 	}
661 
662 	/* Found a mutually agreeable mech. */
663 	mh = &mech_table[best_mhidx];
664 	ctx->ctx_mech_oid = mh->mh_oid;
665 	ctx->ctx_mh_work = mh->mh_work;
666 	ctx->ctx_mh_fini = mh->mh_fini;
667 	rc = mh->mh_init(ctx);
668 	if (rc != 0) {
669 		smbd_report("authsvc: mech init failed");
670 		return (rc);
671 	}
672 
673 	/*
674 	 * Common to LSA_MTYPE_ESFIRST, LSA_MTYPE_ESNEXT
675 	 */
676 	rc = smbd_authsvc_escmn(ctx);
677 	return (rc);
678 }
679 
680 /*
681  * Handle a security blob we've received from the client.
682  * Incoming type: LSA_MTYPE_ESNEXT
683  * Outgoing types: LSA_MTYPE_ES_CONT, LSA_MTYPE_ES_DONE,
684  *   LSA_MTYPE_ERROR
685  */
686 static int
687 smbd_authsvc_esnext(authsvc_context_t *ctx)
688 {
689 	int rc;
690 
691 	/*
692 	 * Make sure LSA_MTYPE_ESFIRST was handled
693 	 * previously, so we have a work function.
694 	 */
695 	if (ctx->ctx_mh_work == NULL)
696 		return (NT_STATUS_INVALID_PARAMETER);
697 
698 	if (ctx->ctx_mech_oid == special_mech_raw_NTLMSSP) {
699 		rc = smbd_raw_ntlmssp_esnext(ctx);
700 		return (rc);
701 	}
702 
703 	/*
704 	 * Cleanup state from previous calls.
705 	 */
706 	if (ctx->ctx_itoken != NULL) {
707 		spnegoFreeData(ctx->ctx_itoken);
708 		ctx->ctx_itoken = NULL;
709 	}
710 
711 	/*
712 	 * Parse the SPNEGO token, check its type.
713 	 */
714 	rc = spnegoInitFromBinary(ctx->ctx_irawbuf,
715 	    ctx->ctx_irawlen, &ctx->ctx_itoken);
716 	if (rc != 0)
717 		return (NT_STATUS_INVALID_PARAMETER);
718 
719 	rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype);
720 	if (rc != 0)
721 		return (NT_STATUS_INVALID_PARAMETER);
722 
723 	if (ctx->ctx_itoktype != SPNEGO_TOKEN_TARG)
724 		return (NT_STATUS_INVALID_PARAMETER);
725 
726 	rc = smbd_authsvc_escmn(ctx);
727 	return (rc);
728 }
729 
730 static int
731 smbd_authsvc_escmn(authsvc_context_t *ctx)
732 {
733 	SPNEGO_MECH_OID oid;
734 	ulong_t toklen;
735 	int rc;
736 
737 	/*
738 	 * Cleanup state from previous calls.
739 	 */
740 	if (ctx->ctx_otoken != NULL) {
741 		spnegoFreeData(ctx->ctx_otoken);
742 		ctx->ctx_otoken = NULL;
743 	}
744 
745 	/*
746 	 * Extract the payload (mech token).
747 	 */
748 	toklen = ctx->ctx_ibodylen;
749 	rc = spnegoGetMechToken(ctx->ctx_itoken,
750 	    ctx->ctx_ibodybuf, &toklen);
751 	switch (rc) {
752 	case SPNEGO_E_SUCCESS:
753 		break;
754 	case SPNEGO_E_ELEMENT_UNAVAILABLE:
755 		toklen = 0;
756 		break;
757 	case SPNEGO_E_BUFFER_TOO_SMALL:
758 		return (NT_STATUS_BUFFER_TOO_SMALL);
759 	default:
760 		return (NT_STATUS_INTERNAL_ERROR);
761 	}
762 	ctx->ctx_ibodylen = toklen;
763 
764 	/*
765 	 * Now that we have the incoming "body" (mech. token),
766 	 * call the back-end mech-specific work function to
767 	 * create the outgoing "body" (mech. token).
768 	 *
769 	 * The worker must fill in:  ctx->ctx_negresult,
770 	 * and: ctx->ctx_obodylen, but ctx->ctx_obodybuf
771 	 * is optional, and is typically NULL after the
772 	 * final message of an auth sequence, where
773 	 * negresult == spnego_negresult_complete.
774 	 */
775 	rc = ctx->ctx_mh_work(ctx);
776 	if (rc != 0)
777 		return (rc);
778 
779 	/*
780 	 * Wrap the outgoing body in a negTokenTarg SPNEGO token.
781 	 * The selected mech. OID is returned only when the
782 	 * incoming token was of type SPNEGO_TOKEN_INIT.
783 	 */
784 	if (ctx->ctx_itoktype == SPNEGO_TOKEN_INIT) {
785 		/* tell the client the selected mech. */
786 		oid = ctx->ctx_mech_oid;
787 	} else {
788 		/* Omit the "supported mech." field. */
789 		oid = spnego_mech_oid_NotUsed;
790 	}
791 
792 	/*
793 	 * Determine the spnego "negresult" from the
794 	 * reply message type (from the work func).
795 	 */
796 	switch (ctx->ctx_orawtype) {
797 	case LSA_MTYPE_ERROR:
798 		ctx->ctx_negresult = spnego_negresult_rejected;
799 		break;
800 	case LSA_MTYPE_ES_DONE:
801 		ctx->ctx_negresult = spnego_negresult_success;
802 		break;
803 	case LSA_MTYPE_ES_CONT:
804 		ctx->ctx_negresult = spnego_negresult_incomplete;
805 		break;
806 	default:
807 		return (-1);
808 	}
809 
810 	rc = spnegoCreateNegTokenTarg(
811 	    oid,
812 	    ctx->ctx_negresult,
813 	    ctx->ctx_obodybuf, /* may be NULL */
814 	    ctx->ctx_obodylen,
815 	    NULL, 0,
816 	    &ctx->ctx_otoken);
817 
818 	/*
819 	 * Convert the SPNEGO token into binary form,
820 	 * writing it to the output buffer.
821 	 */
822 	toklen = smbd_authsvc_bufsize;
823 	rc = spnegoTokenGetBinary(ctx->ctx_otoken,
824 	    (uchar_t *)ctx->ctx_orawbuf, &toklen);
825 	if (rc)
826 		rc = NT_STATUS_INTERNAL_ERROR;
827 	ctx->ctx_orawlen = (uint_t)toklen;
828 
829 	return (rc);
830 }
831 
832 /*
833  * Wrapper for "Raw NTLMSSP", which is exactly like the
834  * normal (SPNEGO-wrapped) NTLMSSP but without SPNEGO.
835  * Setup back-end handler for: special_mech_raw_NTLMSSP
836  * Compare with smbd_authsvc_esfirst().
837  */
838 static int
839 smbd_raw_ntlmssp_esfirst(authsvc_context_t *ctx)
840 {
841 	const spnego_mech_handler_t *mh;
842 	int rc;
843 
844 	mh = &smbd_auth_mech_raw_ntlmssp;
845 	rc = mh->mh_init(ctx);
846 	if (rc != 0)
847 		return (rc);
848 
849 	ctx->ctx_mech_oid = mh->mh_oid;
850 	ctx->ctx_mh_work = mh->mh_work;
851 	ctx->ctx_mh_fini = mh->mh_fini;
852 
853 	rc = smbd_raw_ntlmssp_esnext(ctx);
854 
855 	return (rc);
856 }
857 
858 
859 /*
860  * Wrapper for "Raw NTLMSSP", which is exactly like the
861  * normal (SPNEGO-wrapped) NTLMSSP but without SPNEGO.
862  * Just copy "raw" to "body", and vice versa.
863  * Compare with smbd_authsvc_esnext, smbd_authsvc_escmn
864  */
865 static int
866 smbd_raw_ntlmssp_esnext(authsvc_context_t *ctx)
867 {
868 	int rc;
869 
870 	ctx->ctx_ibodylen = ctx->ctx_irawlen;
871 	(void) memcpy(ctx->ctx_ibodybuf,
872 	    ctx->ctx_irawbuf, ctx->ctx_irawlen);
873 
874 	rc = ctx->ctx_mh_work(ctx);
875 
876 	ctx->ctx_orawlen = ctx->ctx_obodylen;
877 	(void) memcpy(ctx->ctx_orawbuf,
878 	    ctx->ctx_obodybuf, ctx->ctx_obodylen);
879 
880 	return (rc);
881 }
882 
883 
884 /*
885  * After a successful authentication, request the access token.
886  */
887 static int
888 smbd_authsvc_gettoken(authsvc_context_t *ctx)
889 {
890 	XDR		xdrs;
891 	smb_token_t	*token = NULL;
892 	int		rc = 0;
893 	int		len;
894 
895 	if ((token = ctx->ctx_token) == NULL)
896 		return (NT_STATUS_ACCESS_DENIED);
897 
898 	/*
899 	 * Encode the token response
900 	 */
901 	len = xdr_sizeof(smb_token_xdr, token);
902 	if (len > ctx->ctx_orawlen) {
903 		if ((ctx->ctx_orawbuf = realloc(ctx->ctx_orawbuf, len)) ==
904 		    NULL) {
905 			return (NT_STATUS_INTERNAL_ERROR);
906 		}
907 	}
908 
909 	ctx->ctx_orawtype = LSA_MTYPE_TOKEN;
910 	ctx->ctx_orawlen = len;
911 	xdrmem_create(&xdrs, ctx->ctx_orawbuf, len, XDR_ENCODE);
912 	if (!smb_token_xdr(&xdrs, token))
913 		rc = NT_STATUS_INTERNAL_ERROR;
914 	xdr_destroy(&xdrs);
915 
916 	return (rc);
917 }
918 
919 /*
920  * Initialization time code to figure out what mechanisms we support.
921  * Careful with this table; the code below knows its format and may
922  * skip the fist two entries to omit Kerberos.
923  */
924 static SPNEGO_MECH_OID MechTypeList[] = {
925 	spnego_mech_oid_Kerberos_V5,
926 	spnego_mech_oid_Kerberos_V5_Legacy,
927 #define	MECH_OID_IDX_NTLMSSP	2
928 	spnego_mech_oid_NTLMSSP,
929 };
930 static int MechTypeCnt = sizeof (MechTypeList) /
931 	sizeof (MechTypeList[0]);
932 
933 /* This string is just like Windows. */
934 static char IgnoreSPN[] = "not_defined_in_RFC4178@please_ignore";
935 
936 /*
937  * Build the SPNEGO "hint" token based on the
938  * configured authentication mechanisms.
939  * (NTLMSSP, and maybe Kerberos)
940  */
941 void
942 smbd_get_authconf(smb_kmod_cfg_t *kcfg)
943 {
944 	SPNEGO_MECH_OID *mechList = MechTypeList;
945 	int mechCnt = MechTypeCnt;
946 	SPNEGO_TOKEN_HANDLE hSpnegoToken = NULL;
947 	uchar_t *pBuf = kcfg->skc_negtok;
948 	uint32_t *pBufLen = &kcfg->skc_negtok_len;
949 	ulong_t tLen = sizeof (kcfg->skc_negtok);
950 	int rc;
951 
952 	/*
953 	 * In workgroup mode, skip Kerberos.
954 	 */
955 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) {
956 		mechList += MECH_OID_IDX_NTLMSSP;
957 		mechCnt  -= MECH_OID_IDX_NTLMSSP;
958 	}
959 
960 	rc = spnegoCreateNegTokenHint(mechList, mechCnt,
961 	    (uchar_t *)IgnoreSPN, &hSpnegoToken);
962 	if (rc != SPNEGO_E_SUCCESS) {
963 		syslog(LOG_DEBUG, "smb_config_get_negtok: "
964 		    "spnegoCreateNegTokenHint, rc=%d", rc);
965 		*pBufLen = 0;
966 		return;
967 	}
968 	rc = spnegoTokenGetBinary(hSpnegoToken, pBuf, &tLen);
969 	if (rc != SPNEGO_E_SUCCESS) {
970 		syslog(LOG_DEBUG, "smb_config_get_negtok: "
971 		    "spnegoTokenGetBinary, rc=%d", rc);
972 		*pBufLen = 0;
973 	} else {
974 		*pBufLen = (uint32_t)tLen;
975 	}
976 	spnegoFreeData(hSpnegoToken);
977 }
978