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