xref: /illumos-gate/usr/src/cmd/smbsrv/smbd/smbd_authsvc.c (revision 8c69cc8fbe729fa7b091e901c4b50508ccc6bb33)
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 2014 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 ommit 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 		return (NT_STATUS_ACCESS_DENIED);
554 
555 	ctx->ctx_token = token;
556 
557 	return (rc);
558 }
559 
560 static int
561 smbd_authsvc_clinfo(authsvc_context_t *ctx)
562 {
563 
564 	if (ctx->ctx_irawlen != sizeof (smb_lsa_clinfo_t))
565 		return (NT_STATUS_INTERNAL_ERROR);
566 	(void) memcpy(&ctx->ctx_clinfo, ctx->ctx_irawbuf,
567 	    sizeof (smb_lsa_clinfo_t));
568 
569 	ctx->ctx_orawtype = LSA_MTYPE_OK;
570 	ctx->ctx_orawlen = 0;
571 	return (0);
572 }
573 
574 /*
575  * Handle a security blob we've received from the client.
576  * Incoming type: LSA_MTYPE_ESFIRST
577  * Outgoing types: LSA_MTYPE_ES_CONT, LSA_MTYPE_ES_DONE,
578  *   LSA_MTYPE_ERROR
579  */
580 static int
581 smbd_authsvc_esfirst(authsvc_context_t *ctx)
582 {
583 	const spnego_mech_handler_t *mh;
584 	int idx, pref, rc;
585 	int best_pref = 1000;
586 	int best_mhidx = -1;
587 
588 	/*
589 	 * NTLMSSP header is 8+, SPNEGO is 10+
590 	 */
591 	if (ctx->ctx_irawlen < 8) {
592 		smbd_report("authsvc: short blob");
593 		return (NT_STATUS_INVALID_PARAMETER);
594 	}
595 
596 	/*
597 	 * We could have "Raw NTLMSSP" here intead of SPNEGO.
598 	 */
599 	if (bcmp(ctx->ctx_irawbuf, "NTLMSSP", 8) == 0) {
600 		rc = smbd_raw_ntlmssp_esfirst(ctx);
601 		return (rc);
602 	}
603 
604 	/*
605 	 * Parse the SPNEGO token, check its type.
606 	 */
607 	rc = spnegoInitFromBinary(ctx->ctx_irawbuf,
608 	    ctx->ctx_irawlen, &ctx->ctx_itoken);
609 	if (rc != 0) {
610 		smbd_report("authsvc: spnego parse failed");
611 		return (NT_STATUS_INVALID_PARAMETER);
612 	}
613 
614 	rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype);
615 	if (rc != 0) {
616 		smbd_report("authsvc: spnego get token type failed");
617 		return (NT_STATUS_INVALID_PARAMETER);
618 	}
619 
620 	if (ctx->ctx_itoktype != SPNEGO_TOKEN_INIT) {
621 		smbd_report("authsvc: spnego wrong token type %d",
622 		    ctx->ctx_itoktype);
623 		return (NT_STATUS_INVALID_PARAMETER);
624 	}
625 
626 	/*
627 	 * Figure out which mech type to use.  We want to use the
628 	 * first of the client's supported mechanisms that we also
629 	 * support.  Unfortunately, the spnego code does not have an
630 	 * interface to walk the token's mech list, so we have to
631 	 * ask about each mech type we know and keep track of which
632 	 * was earliest in the token's mech list.
633 	 *
634 	 * Also, skip the Kerberos mechanisms in workgroup mode.
635 	 */
636 	idx = 0;
637 	mh = mech_table;
638 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) {
639 		idx = MECH_TBL_IDX_NTLMSSP;
640 		mh = &mech_table[idx];
641 	}
642 	for (; mh->mh_init != NULL; idx++, mh++) {
643 
644 		if (spnegoIsMechTypeAvailable(ctx->ctx_itoken,
645 		    mh->mh_oid, &pref) != 0)
646 			continue;
647 
648 		if (pref < best_pref) {
649 			best_pref = pref;
650 			best_mhidx = idx;
651 		}
652 	}
653 	if (best_mhidx == -1) {
654 		smbd_report("authsvc: no supported spnego mechanism");
655 		return (NT_STATUS_INVALID_PARAMETER);
656 	}
657 
658 	/* Found a mutually agreeable mech. */
659 	mh = &mech_table[best_mhidx];
660 	ctx->ctx_mech_oid = mh->mh_oid;
661 	ctx->ctx_mh_work = mh->mh_work;
662 	ctx->ctx_mh_fini = mh->mh_fini;
663 	rc = mh->mh_init(ctx);
664 	if (rc != 0) {
665 		smbd_report("authsvc: mech init failed");
666 		return (rc);
667 	}
668 
669 	/*
670 	 * Common to LSA_MTYPE_ESFIRST, LSA_MTYPE_ESNEXT
671 	 */
672 	rc = smbd_authsvc_escmn(ctx);
673 	return (rc);
674 }
675 
676 /*
677  * Handle a security blob we've received from the client.
678  * Incoming type: LSA_MTYPE_ESNEXT
679  * Outgoing types: LSA_MTYPE_ES_CONT, LSA_MTYPE_ES_DONE,
680  *   LSA_MTYPE_ERROR
681  */
682 static int
683 smbd_authsvc_esnext(authsvc_context_t *ctx)
684 {
685 	int rc;
686 
687 	/*
688 	 * Make sure LSA_MTYPE_ESFIRST was handled
689 	 * previously, so we have a work function.
690 	 */
691 	if (ctx->ctx_mh_work == NULL)
692 		return (NT_STATUS_INVALID_PARAMETER);
693 
694 	if (ctx->ctx_mech_oid == special_mech_raw_NTLMSSP) {
695 		rc = smbd_raw_ntlmssp_esnext(ctx);
696 		return (rc);
697 	}
698 
699 	/*
700 	 * Cleanup state from previous calls.
701 	 */
702 	if (ctx->ctx_itoken != NULL) {
703 		spnegoFreeData(ctx->ctx_itoken);
704 		ctx->ctx_itoken = NULL;
705 	}
706 
707 	/*
708 	 * Parse the SPNEGO token, check its type.
709 	 */
710 	rc = spnegoInitFromBinary(ctx->ctx_irawbuf,
711 	    ctx->ctx_irawlen, &ctx->ctx_itoken);
712 	if (rc != 0)
713 		return (NT_STATUS_INVALID_PARAMETER);
714 
715 	rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype);
716 	if (rc != 0)
717 		return (NT_STATUS_INVALID_PARAMETER);
718 
719 	if (ctx->ctx_itoktype != SPNEGO_TOKEN_TARG)
720 		return (NT_STATUS_INVALID_PARAMETER);
721 
722 	rc = smbd_authsvc_escmn(ctx);
723 	return (rc);
724 }
725 
726 static int
727 smbd_authsvc_escmn(authsvc_context_t *ctx)
728 {
729 	SPNEGO_MECH_OID oid;
730 	ulong_t toklen;
731 	int rc;
732 
733 	/*
734 	 * Cleanup state from previous calls.
735 	 */
736 	if (ctx->ctx_otoken != NULL) {
737 		spnegoFreeData(ctx->ctx_otoken);
738 		ctx->ctx_otoken = NULL;
739 	}
740 
741 	/*
742 	 * Extract the payload (mech token).
743 	 */
744 	toklen = ctx->ctx_ibodylen;
745 	rc = spnegoGetMechToken(ctx->ctx_itoken,
746 	    ctx->ctx_ibodybuf, &toklen);
747 	switch (rc) {
748 	case SPNEGO_E_SUCCESS:
749 		break;
750 	case SPNEGO_E_ELEMENT_UNAVAILABLE:
751 		toklen = 0;
752 		break;
753 	case SPNEGO_E_BUFFER_TOO_SMALL:
754 		return (NT_STATUS_BUFFER_TOO_SMALL);
755 	default:
756 		return (NT_STATUS_INTERNAL_ERROR);
757 	}
758 	ctx->ctx_ibodylen = toklen;
759 
760 	/*
761 	 * Now that we have the incoming "body" (mech. token),
762 	 * call the back-end mech-specific work function to
763 	 * create the outgoing "body" (mech. token).
764 	 *
765 	 * The worker must fill in:  ctx->ctx_negresult,
766 	 * and: ctx->ctx_obodylen, but ctx->ctx_obodybuf
767 	 * is optional, and is typically NULL after the
768 	 * final message of an auth sequence, where
769 	 * negresult == spnego_negresult_complete.
770 	 */
771 	rc = ctx->ctx_mh_work(ctx);
772 	if (rc != 0)
773 		return (rc);
774 
775 	/*
776 	 * Wrap the outgoing body in a negTokenTarg SPNEGO token.
777 	 * The selected mech. OID is returned only when the
778 	 * incoming token was of type SPNEGO_TOKEN_INIT.
779 	 */
780 	if (ctx->ctx_itoktype == SPNEGO_TOKEN_INIT) {
781 		/* tell the client the selected mech. */
782 		oid = ctx->ctx_mech_oid;
783 	} else {
784 		/* Ommit the "supported mech." field. */
785 		oid = spnego_mech_oid_NotUsed;
786 	}
787 
788 	/*
789 	 * Determine the spnego "negresult" from the
790 	 * reply message type (from the work func).
791 	 */
792 	switch (ctx->ctx_orawtype) {
793 	case LSA_MTYPE_ERROR:
794 		ctx->ctx_negresult = spnego_negresult_rejected;
795 		break;
796 	case LSA_MTYPE_ES_DONE:
797 		ctx->ctx_negresult = spnego_negresult_success;
798 		break;
799 	case LSA_MTYPE_ES_CONT:
800 		ctx->ctx_negresult = spnego_negresult_incomplete;
801 		break;
802 	default:
803 		return (-1);
804 	}
805 
806 	rc = spnegoCreateNegTokenTarg(
807 	    oid,
808 	    ctx->ctx_negresult,
809 	    ctx->ctx_obodybuf, /* may be NULL */
810 	    ctx->ctx_obodylen,
811 	    NULL, 0,
812 	    &ctx->ctx_otoken);
813 
814 	/*
815 	 * Convert the SPNEGO token into binary form,
816 	 * writing it to the output buffer.
817 	 */
818 	toklen = smbd_authsvc_bufsize;
819 	rc = spnegoTokenGetBinary(ctx->ctx_otoken,
820 	    (uchar_t *)ctx->ctx_orawbuf, &toklen);
821 	if (rc)
822 		rc = NT_STATUS_INTERNAL_ERROR;
823 	ctx->ctx_orawlen = (uint_t)toklen;
824 
825 	return (rc);
826 }
827 
828 /*
829  * Wrapper for "Raw NTLMSSP", which is exactly like the
830  * normal (SPNEGO-wrapped) NTLMSSP but without SPNEGO.
831  * Setup back-end handler for: special_mech_raw_NTLMSSP
832  * Compare with smbd_authsvc_esfirst().
833  */
834 static int
835 smbd_raw_ntlmssp_esfirst(authsvc_context_t *ctx)
836 {
837 	const spnego_mech_handler_t *mh;
838 	int rc;
839 
840 	mh = &smbd_auth_mech_raw_ntlmssp;
841 	rc = mh->mh_init(ctx);
842 	if (rc != 0)
843 		return (rc);
844 
845 	ctx->ctx_mech_oid = mh->mh_oid;
846 	ctx->ctx_mh_work = mh->mh_work;
847 	ctx->ctx_mh_fini = mh->mh_fini;
848 
849 	rc = smbd_raw_ntlmssp_esnext(ctx);
850 
851 	return (rc);
852 }
853 
854 
855 /*
856  * Wrapper for "Raw NTLMSSP", which is exactly like the
857  * normal (SPNEGO-wrapped) NTLMSSP but without SPNEGO.
858  * Just copy "raw" to "body", and vice versa.
859  * Compare with smbd_authsvc_esnext, smbd_authsvc_escmn
860  */
861 static int
862 smbd_raw_ntlmssp_esnext(authsvc_context_t *ctx)
863 {
864 	int rc;
865 
866 	ctx->ctx_ibodylen = ctx->ctx_irawlen;
867 	(void) memcpy(ctx->ctx_ibodybuf,
868 	    ctx->ctx_irawbuf, ctx->ctx_irawlen);
869 
870 	rc = ctx->ctx_mh_work(ctx);
871 
872 	ctx->ctx_orawlen = ctx->ctx_obodylen;
873 	(void) memcpy(ctx->ctx_orawbuf,
874 	    ctx->ctx_obodybuf, ctx->ctx_obodylen);
875 
876 	return (rc);
877 }
878 
879 
880 /*
881  * After a successful authentication, request the access token.
882  */
883 static int
884 smbd_authsvc_gettoken(authsvc_context_t *ctx)
885 {
886 	XDR		xdrs;
887 	smb_token_t	*token = NULL;
888 	int		rc = 0;
889 	int		len;
890 
891 	if ((token = ctx->ctx_token) == NULL)
892 		return (NT_STATUS_ACCESS_DENIED);
893 
894 	/*
895 	 * Encode the token response
896 	 */
897 	len = xdr_sizeof(smb_token_xdr, token);
898 	if (len > ctx->ctx_orawlen) {
899 		if ((ctx->ctx_orawbuf = realloc(ctx->ctx_orawbuf, len)) ==
900 		    NULL) {
901 			return (NT_STATUS_INTERNAL_ERROR);
902 		}
903 	}
904 
905 	ctx->ctx_orawtype = LSA_MTYPE_TOKEN;
906 	ctx->ctx_orawlen = len;
907 	xdrmem_create(&xdrs, ctx->ctx_orawbuf, len, XDR_ENCODE);
908 	if (!smb_token_xdr(&xdrs, token))
909 		rc = NT_STATUS_INTERNAL_ERROR;
910 	xdr_destroy(&xdrs);
911 
912 	return (rc);
913 }
914 
915 /*
916  * Initialization time code to figure out what mechanisms we support.
917  * Careful with this table; the code below knows its format and may
918  * skip the fist two entries to ommit Kerberos.
919  */
920 static SPNEGO_MECH_OID MechTypeList[] = {
921 	spnego_mech_oid_Kerberos_V5,
922 	spnego_mech_oid_Kerberos_V5_Legacy,
923 #define	MECH_OID_IDX_NTLMSSP	2
924 	spnego_mech_oid_NTLMSSP,
925 };
926 static int MechTypeCnt = sizeof (MechTypeList) /
927 	sizeof (MechTypeList[0]);
928 
929 /* This string is just like Windows. */
930 static char IgnoreSPN[] = "not_defined_in_RFC4178@please_ignore";
931 
932 /*
933  * Build the SPNEGO "hint" token based on the
934  * configured authentication mechanisms.
935  * (NTLMSSP, and maybe Kerberos)
936  */
937 void
938 smbd_get_authconf(smb_kmod_cfg_t *kcfg)
939 {
940 	SPNEGO_MECH_OID *mechList = MechTypeList;
941 	int mechCnt = MechTypeCnt;
942 	SPNEGO_TOKEN_HANDLE hSpnegoToken = NULL;
943 	uchar_t *pBuf = kcfg->skc_negtok;
944 	uint32_t *pBufLen = &kcfg->skc_negtok_len;
945 	ulong_t tLen = sizeof (kcfg->skc_negtok);
946 	int rc;
947 
948 	/*
949 	 * In workgroup mode, skip Kerberos.
950 	 */
951 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) {
952 		mechList += MECH_OID_IDX_NTLMSSP;
953 		mechCnt  -= MECH_OID_IDX_NTLMSSP;
954 	}
955 
956 	rc = spnegoCreateNegTokenHint(mechList, mechCnt,
957 	    (uchar_t *)IgnoreSPN, &hSpnegoToken);
958 	if (rc != SPNEGO_E_SUCCESS) {
959 		syslog(LOG_DEBUG, "smb_config_get_negtok: "
960 		    "spnegoCreateNegTokenHint, rc=%d", rc);
961 		*pBufLen = 0;
962 		return;
963 	}
964 	rc = spnegoTokenGetBinary(hSpnegoToken, pBuf, &tLen);
965 	if (rc != SPNEGO_E_SUCCESS) {
966 		syslog(LOG_DEBUG, "smb_config_get_negtok: "
967 		    "spnegoTokenGetBinary, rc=%d", rc);
968 		*pBufLen = 0;
969 	} else {
970 		*pBufLen = (uint32_t)tLen;
971 	}
972 	spnegoFreeData(hSpnegoToken);
973 }
974