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-2023 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
smbd_authsvc_start(void)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
smbd_authsvc_stop(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
smbd_authsock_create(void)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
smbd_authsock_destroy(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 /*
230 * Decide whether to communicate with the client on this AF_UNIX socket.
231 * Normally the caller should be the (in-kernel) SMB service which has
232 * (typically) all privileges. We test for PRIV_SYS_SMB here, which
233 * only the SMB service should have.
234 */
235 static boolean_t
authsock_has_priv(int sock)236 authsock_has_priv(int sock)
237 {
238 ucred_t *uc = NULL;
239 const priv_set_t *ps = NULL;
240 boolean_t ret = B_FALSE;
241 pid_t clpid;
242
243 if (getpeerucred(sock, &uc) != 0) {
244 smbd_report("authsvc: getpeerucred err %d", errno);
245 return (B_FALSE);
246 }
247 clpid = ucred_getpid(uc);
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 * 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 *
smbd_authsvc_listen(void * arg)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 smbd_nomem();
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 ctx = NULL;
353 smbd_nomem();
354 }
355 ctx = NULL; /* given to the new thread or destroyed */
356 (void) pthread_detach(tid);
357 }
358
359 out:
360 (void) pthread_attr_destroy(&attr);
361 smbd_authsock_destroy();
362 return (NULL);
363 }
364
365 static void
smbd_authsvc_flood(void)366 smbd_authsvc_flood(void)
367 {
368 static uint_t count;
369 static time_t last_report;
370 time_t now = time(NULL);
371
372 count++;
373 if (last_report + 60 < now) {
374 last_report = now;
375 smbd_report("authsvc: flooded %u", count);
376 count = 0;
377 }
378 }
379
380 authsvc_context_t *
smbd_authctx_create(void)381 smbd_authctx_create(void)
382 {
383 authsvc_context_t *ctx;
384
385 ctx = malloc(sizeof (*ctx));
386 if (ctx == NULL)
387 return (NULL);
388 bzero(ctx, sizeof (*ctx));
389
390 ctx->ctx_irawlen = smbd_authsvc_bufsize;
391 ctx->ctx_irawbuf = malloc(ctx->ctx_irawlen);
392 ctx->ctx_orawlen = smbd_authsvc_bufsize;
393 ctx->ctx_orawbuf = malloc(ctx->ctx_orawlen);
394 if (ctx->ctx_irawbuf == NULL || ctx->ctx_orawbuf == NULL)
395 goto errout;
396
397 ctx->ctx_ibodylen = smbd_authsvc_bufsize;
398 ctx->ctx_ibodybuf = malloc(ctx->ctx_ibodylen);
399 ctx->ctx_obodylen = smbd_authsvc_bufsize;
400 ctx->ctx_obodybuf = malloc(ctx->ctx_obodylen);
401 if (ctx->ctx_ibodybuf == NULL || ctx->ctx_obodybuf == NULL)
402 goto errout;
403
404 return (ctx);
405
406 errout:
407 smbd_authctx_destroy(ctx);
408 return (NULL);
409 }
410
411 void
smbd_authctx_destroy(authsvc_context_t * ctx)412 smbd_authctx_destroy(authsvc_context_t *ctx)
413 {
414 if (ctx->ctx_socket != -1) {
415 (void) close(ctx->ctx_socket);
416 ctx->ctx_socket = -1;
417 }
418
419 if (ctx->ctx_token != NULL)
420 smb_token_destroy(ctx->ctx_token);
421
422 if (ctx->ctx_itoken != NULL)
423 spnegoFreeData(ctx->ctx_itoken);
424 if (ctx->ctx_otoken != NULL)
425 spnegoFreeData(ctx->ctx_otoken);
426
427 free(ctx->ctx_irawbuf);
428 free(ctx->ctx_orawbuf);
429 free(ctx->ctx_ibodybuf);
430 free(ctx->ctx_obodybuf);
431
432 free(ctx);
433 }
434
435 /*
436 * Limit how long smbd_authsvc_work will wait for the client to
437 * send us the next part of the authentication sequence.
438 */
439 static struct timeval recv_tmo = { 30, 0 };
440
441 /*
442 * Also set a timeout for send, where we're sending a response to
443 * the client side (in smbsrv). That should always be waiting in
444 * recv by the time we send, so a short timeout is OK.
445 */
446 static struct timeval send_tmo = { 15, 0 };
447
448 static void *
smbd_authsvc_work(void * arg)449 smbd_authsvc_work(void *arg)
450 {
451 authsvc_context_t *ctx = arg;
452 smb_lsa_msg_hdr_t hdr;
453 int sock = ctx->ctx_socket;
454 int len, rc;
455
456 if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
457 (char *)&send_tmo, sizeof (send_tmo)) != 0) {
458 smbd_report("authsvc_work: set set timeout: %m");
459 goto out;
460 }
461
462 if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
463 (char *)&recv_tmo, sizeof (recv_tmo)) != 0) {
464 smbd_report("authsvc_work: set recv timeout: %m");
465 goto out;
466 }
467
468 for (;;) {
469
470 len = recv(sock, &hdr, sizeof (hdr), MSG_WAITALL);
471 if (len <= 0) {
472 /* normal termination */
473 break;
474 }
475 if (len != sizeof (hdr)) {
476 smbd_report("authsvc_work: read header failed");
477 break;
478 }
479
480 if (hdr.lmh_msglen > smbd_authsvc_bufsize) {
481 smbd_report("authsvc_work: msg too large");
482 break;
483 }
484
485 if (hdr.lmh_msglen > 0) {
486 len = recv(sock, ctx->ctx_irawbuf, hdr.lmh_msglen,
487 MSG_WAITALL);
488 if (len != hdr.lmh_msglen) {
489 smbd_report("authsvc_work: read mesg failed");
490 break;
491 }
492 }
493 ctx->ctx_irawtype = hdr.lmh_msgtype;
494 ctx->ctx_irawlen = hdr.lmh_msglen;
495 ctx->ctx_orawlen = smbd_authsvc_bufsize;
496 ctx->ctx_ibodylen = smbd_authsvc_bufsize;
497 ctx->ctx_obodylen = smbd_authsvc_bufsize;
498
499 /*
500 * The real work happens here.
501 */
502 rc = smbd_authsvc_dispatch(ctx);
503 if (rc)
504 break;
505
506 hdr.lmh_msgtype = ctx->ctx_orawtype;
507 hdr.lmh_msglen = ctx->ctx_orawlen;
508 len = send(sock, &hdr, sizeof (hdr), 0);
509 if (len != sizeof (hdr)) {
510 smbd_report("authsvc_work: send failed");
511 break;
512 }
513
514 if (ctx->ctx_orawlen > 0) {
515 len = send(sock, ctx->ctx_orawbuf,
516 ctx->ctx_orawlen, 0);
517 if (len != ctx->ctx_orawlen) {
518 smbd_report("authsvc_work: send failed");
519 break;
520 }
521 }
522 }
523
524 out:
525 if (ctx->ctx_mh_fini)
526 (ctx->ctx_mh_fini)(ctx);
527
528 smbd_authctx_destroy(ctx);
529
530 (void) mutex_lock(&smbd_authsvc_mutex);
531 smbd_authsvc_thrcnt--;
532 (void) mutex_unlock(&smbd_authsvc_mutex);
533
534 return (NULL); /* implied pthread_exit() */
535 }
536
537 /*
538 * Dispatch based on message type LSA_MTYPE_...
539 * Non-zero return here ends the conversation.
540 */
541 int
smbd_authsvc_dispatch(authsvc_context_t * ctx)542 smbd_authsvc_dispatch(authsvc_context_t *ctx)
543 {
544 int rc;
545
546 switch (ctx->ctx_irawtype) {
547
548 case LSA_MTYPE_OLDREQ:
549 #ifdef DEBUG
550 if (smbd_authsvc_slowdown)
551 (void) sleep(smbd_authsvc_slowdown);
552 #endif
553 rc = smbd_authsvc_oldreq(ctx);
554 break;
555
556 case LSA_MTYPE_CLINFO:
557 rc = smbd_authsvc_clinfo(ctx);
558 break;
559
560 case LSA_MTYPE_ESFIRST:
561 rc = smbd_authsvc_esfirst(ctx);
562 break;
563
564 case LSA_MTYPE_ESNEXT:
565 #ifdef DEBUG
566 if (smbd_authsvc_slowdown)
567 (void) sleep(smbd_authsvc_slowdown);
568 #endif
569 rc = smbd_authsvc_esnext(ctx);
570 break;
571
572 case LSA_MTYPE_GETTOK:
573 rc = smbd_authsvc_gettoken(ctx);
574 break;
575
576 /* response types */
577 case LSA_MTYPE_OK:
578 case LSA_MTYPE_ERROR:
579 case LSA_MTYPE_TOKEN:
580 case LSA_MTYPE_ES_CONT:
581 case LSA_MTYPE_ES_DONE:
582 default:
583 return (-1);
584 }
585
586 if (rc == NT_STATUS_NO_MEMORY)
587 smbd_nomem();
588
589 if (rc != 0) {
590 smb_lsa_eresp_t *er = ctx->ctx_orawbuf;
591 ctx->ctx_orawtype = LSA_MTYPE_ERROR;
592 ctx->ctx_orawlen = sizeof (*er);
593 er->ler_ntstatus = rc;
594 er->ler_errclass = 0;
595 er->ler_errcode = 0;
596 }
597 return (0);
598 }
599
600 static int
smbd_authsvc_oldreq(authsvc_context_t * ctx)601 smbd_authsvc_oldreq(authsvc_context_t *ctx)
602 {
603 smb_logon_t user_info;
604 XDR xdrs;
605 smb_token_t *token = NULL;
606 int rc = 0;
607
608 bzero(&user_info, sizeof (user_info));
609 xdrmem_create(&xdrs, ctx->ctx_irawbuf, ctx->ctx_irawlen,
610 XDR_DECODE);
611 if (!smb_logon_xdr(&xdrs, &user_info)) {
612 xdr_destroy(&xdrs);
613 return (NT_STATUS_INVALID_PARAMETER);
614 }
615 xdr_destroy(&xdrs);
616
617 token = smbd_user_auth_logon(&user_info);
618 xdr_free(smb_logon_xdr, (char *)&user_info);
619 if (token == NULL) {
620 rc = user_info.lg_status;
621 if (rc == 0) /* should not happen */
622 rc = NT_STATUS_INTERNAL_ERROR;
623 return (rc);
624 }
625
626 ctx->ctx_token = token;
627
628 return (rc);
629 }
630
631 static int
smbd_authsvc_clinfo(authsvc_context_t * ctx)632 smbd_authsvc_clinfo(authsvc_context_t *ctx)
633 {
634
635 if (ctx->ctx_irawlen != sizeof (smb_lsa_clinfo_t))
636 return (NT_STATUS_INTERNAL_ERROR);
637 (void) memcpy(&ctx->ctx_clinfo, ctx->ctx_irawbuf,
638 sizeof (smb_lsa_clinfo_t));
639
640 ctx->ctx_orawtype = LSA_MTYPE_OK;
641 ctx->ctx_orawlen = 0;
642 return (0);
643 }
644
645 /*
646 * Handle a security blob we've received from the client.
647 * Incoming type: LSA_MTYPE_ESFIRST
648 * Outgoing types: LSA_MTYPE_ES_CONT, LSA_MTYPE_ES_DONE,
649 * LSA_MTYPE_ERROR
650 */
651 static int
smbd_authsvc_esfirst(authsvc_context_t * ctx)652 smbd_authsvc_esfirst(authsvc_context_t *ctx)
653 {
654 const spnego_mech_handler_t *mh;
655 int idx, pref, rc;
656 int best_pref = 1000;
657 int best_mhidx = -1;
658
659 /*
660 * NTLMSSP header is 8+, SPNEGO is 10+
661 */
662 if (ctx->ctx_irawlen < 8) {
663 smbd_report("authsvc: short blob");
664 return (NT_STATUS_INVALID_PARAMETER);
665 }
666
667 /*
668 * We could have "Raw NTLMSSP" here intead of SPNEGO.
669 */
670 if (bcmp(ctx->ctx_irawbuf, "NTLMSSP", 8) == 0) {
671 rc = smbd_raw_ntlmssp_esfirst(ctx);
672 return (rc);
673 }
674
675 /*
676 * Parse the SPNEGO token, check its type.
677 */
678 rc = spnegoInitFromBinary(ctx->ctx_irawbuf,
679 ctx->ctx_irawlen, &ctx->ctx_itoken);
680 if (rc != 0) {
681 smbd_report("authsvc: spnego parse failed");
682 return (NT_STATUS_INVALID_PARAMETER);
683 }
684
685 rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype);
686 if (rc != 0) {
687 smbd_report("authsvc: spnego get token type failed");
688 return (NT_STATUS_INVALID_PARAMETER);
689 }
690
691 if (ctx->ctx_itoktype != SPNEGO_TOKEN_INIT) {
692 smbd_report("authsvc: spnego wrong token type %d",
693 ctx->ctx_itoktype);
694 return (NT_STATUS_INVALID_PARAMETER);
695 }
696
697 /*
698 * Figure out which mech type to use. We want to use the
699 * first of the client's supported mechanisms that we also
700 * support. Unfortunately, the spnego code does not have an
701 * interface to walk the token's mech list, so we have to
702 * ask about each mech type we know and keep track of which
703 * was earliest in the token's mech list.
704 *
705 * Also, skip the Kerberos mechanisms in workgroup mode.
706 */
707 idx = 0;
708 mh = mech_table;
709 if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) {
710 idx = MECH_TBL_IDX_NTLMSSP;
711 mh = &mech_table[idx];
712 }
713 for (; mh->mh_init != NULL; idx++, mh++) {
714
715 if (spnegoIsMechTypeAvailable(ctx->ctx_itoken,
716 mh->mh_oid, &pref) != 0)
717 continue;
718
719 if (pref < best_pref) {
720 best_pref = pref;
721 best_mhidx = idx;
722 }
723 }
724 if (best_mhidx == -1) {
725 smbd_report("authsvc: no supported spnego mechanism");
726 return (NT_STATUS_INVALID_PARAMETER);
727 }
728
729 /* Found a mutually agreeable mech. */
730 mh = &mech_table[best_mhidx];
731 ctx->ctx_mech_oid = mh->mh_oid;
732 ctx->ctx_mh_work = mh->mh_work;
733 ctx->ctx_mh_fini = mh->mh_fini;
734 rc = mh->mh_init(ctx);
735 if (rc != 0) {
736 smbd_report("authsvc: mech init failed");
737 return (rc);
738 }
739
740 /*
741 * If the best supported mech was not the first in the list,
742 * we need to ask the client to use a different one, and
743 * skip (ignore) the provided token body.
744 */
745 if (best_pref != 0) {
746 rc = smbd_authsvc_newmech(ctx);
747 } else {
748 /*
749 * Common to LSA_MTYPE_ESFIRST, LSA_MTYPE_ESNEXT
750 */
751 rc = smbd_authsvc_escmn(ctx);
752 }
753 return (rc);
754 }
755
756 /*
757 * Handle a security blob we've received from the client.
758 * Incoming type: LSA_MTYPE_ESNEXT
759 * Outgoing types: LSA_MTYPE_ES_CONT, LSA_MTYPE_ES_DONE,
760 * LSA_MTYPE_ERROR
761 */
762 static int
smbd_authsvc_esnext(authsvc_context_t * ctx)763 smbd_authsvc_esnext(authsvc_context_t *ctx)
764 {
765 int rc;
766
767 /*
768 * Make sure LSA_MTYPE_ESFIRST was handled
769 * previously, so we have a work function.
770 */
771 if (ctx->ctx_mh_work == NULL)
772 return (NT_STATUS_INVALID_PARAMETER);
773
774 if (ctx->ctx_mech_oid == special_mech_raw_NTLMSSP) {
775 rc = smbd_raw_ntlmssp_esnext(ctx);
776 return (rc);
777 }
778
779 /*
780 * Cleanup state from previous calls.
781 */
782 if (ctx->ctx_itoken != NULL) {
783 spnegoFreeData(ctx->ctx_itoken);
784 ctx->ctx_itoken = NULL;
785 }
786
787 /*
788 * Parse the SPNEGO token, check its type.
789 */
790 rc = spnegoInitFromBinary(ctx->ctx_irawbuf,
791 ctx->ctx_irawlen, &ctx->ctx_itoken);
792 if (rc != 0)
793 return (NT_STATUS_INVALID_PARAMETER);
794
795 rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype);
796 if (rc != 0)
797 return (NT_STATUS_INVALID_PARAMETER);
798
799 if (ctx->ctx_itoktype != SPNEGO_TOKEN_TARG)
800 return (NT_STATUS_INVALID_PARAMETER);
801
802 rc = smbd_authsvc_escmn(ctx);
803 return (rc);
804 }
805
806 static int
smbd_authsvc_escmn(authsvc_context_t * ctx)807 smbd_authsvc_escmn(authsvc_context_t *ctx)
808 {
809 SPNEGO_MECH_OID oid;
810 ulong_t toklen;
811 int rc;
812
813 /*
814 * Cleanup state from previous calls.
815 */
816 if (ctx->ctx_otoken != NULL) {
817 spnegoFreeData(ctx->ctx_otoken);
818 ctx->ctx_otoken = NULL;
819 }
820
821 /*
822 * Extract the payload (mech token).
823 */
824 toklen = ctx->ctx_ibodylen;
825 rc = spnegoGetMechToken(ctx->ctx_itoken,
826 ctx->ctx_ibodybuf, &toklen);
827 switch (rc) {
828 case SPNEGO_E_SUCCESS:
829 break;
830 case SPNEGO_E_ELEMENT_UNAVAILABLE:
831 toklen = 0;
832 break;
833 case SPNEGO_E_BUFFER_TOO_SMALL:
834 return (NT_STATUS_BUFFER_TOO_SMALL);
835 default:
836 return (NT_STATUS_INTERNAL_ERROR);
837 }
838 ctx->ctx_ibodylen = toklen;
839
840 /*
841 * Now that we have the incoming "body" (mech. token),
842 * call the back-end mech-specific work function to
843 * create the outgoing "body" (mech. token).
844 *
845 * The worker must fill in: ctx->ctx_negresult,
846 * and: ctx->ctx_obodylen, but ctx->ctx_obodybuf
847 * is optional, and is typically NULL after the
848 * final message of an auth sequence, where
849 * negresult == spnego_negresult_complete.
850 */
851 rc = ctx->ctx_mh_work(ctx);
852 if (rc != 0)
853 return (rc);
854
855 /*
856 * Wrap the outgoing body in a negTokenTarg SPNEGO token.
857 * The selected mech. OID is returned only when the
858 * incoming token was of type SPNEGO_TOKEN_INIT.
859 */
860 if (ctx->ctx_itoktype == SPNEGO_TOKEN_INIT) {
861 /* tell the client the selected mech. */
862 oid = ctx->ctx_mech_oid;
863 } else {
864 /* Omit the "supported mech." field. */
865 oid = spnego_mech_oid_NotUsed;
866 }
867
868 /*
869 * Determine the spnego "negresult" from the
870 * reply message type (from the work func).
871 */
872 switch (ctx->ctx_orawtype) {
873 case LSA_MTYPE_ERROR:
874 ctx->ctx_negresult = spnego_negresult_rejected;
875 break;
876 case LSA_MTYPE_ES_DONE:
877 ctx->ctx_negresult = spnego_negresult_success;
878 break;
879 case LSA_MTYPE_ES_CONT:
880 ctx->ctx_negresult = spnego_negresult_incomplete;
881 break;
882 default:
883 return (-1);
884 }
885
886 rc = spnegoCreateNegTokenTarg(
887 oid,
888 ctx->ctx_negresult,
889 ctx->ctx_obodybuf, /* may be NULL */
890 ctx->ctx_obodylen,
891 NULL, 0,
892 &ctx->ctx_otoken);
893 if (rc != 0)
894 return (NT_STATUS_INTERNAL_ERROR);
895
896 /*
897 * Convert the SPNEGO token into binary form,
898 * writing it to the output buffer.
899 */
900 toklen = smbd_authsvc_bufsize;
901 rc = spnegoTokenGetBinary(ctx->ctx_otoken,
902 (uchar_t *)ctx->ctx_orawbuf, &toklen);
903 if (rc != 0)
904 rc = NT_STATUS_INTERNAL_ERROR;
905 ctx->ctx_orawlen = (uint_t)toklen;
906
907 return (rc);
908 }
909
910 /*
911 * The first NegTokenInit we receive, handled in smbd_authsvc_esfirst,
912 * contains a list of supported mechanisms, in order from the client's
913 * most preferred to least preferred. The token also contains a body
914 * for the first mechanism listed, which is used immediately if the
915 * first mechanism is mutually agreeable. If the first mechanism is
916 * not supported on our side, we must "propose a new mechanism" from
917 * the list. Our caller has selected a mech and initialized the ctx
918 * mech functions. Here compose a reply with an empty body and the
919 * proposed new mechanism OID. The token body received is for some
920 * other mech, so we skip calling the work function with that token.
921 *
922 * Just send a NegTokenTarg with an empty body and the OID for the
923 * proposed mechanism. The next message should be the real first
924 * token for this mechanism, handled in smbd_authsvc_exnext.
925 */
926 static int
smbd_authsvc_newmech(authsvc_context_t * ctx)927 smbd_authsvc_newmech(authsvc_context_t *ctx)
928 {
929 ulong_t toklen;
930 int rc;
931
932 /*
933 * Don't call mh_work here.
934 * Just tell the clint the selected mech.
935 */
936 ctx->ctx_ibodylen = 0;
937 ctx->ctx_orawtype = LSA_MTYPE_ES_CONT;
938 ctx->ctx_obodylen = 0;
939 ctx->ctx_negresult = spnego_negresult_request_mic;
940
941 rc = spnegoCreateNegTokenTarg(
942 ctx->ctx_mech_oid,
943 ctx->ctx_negresult,
944 NULL, 0,
945 NULL, 0,
946 &ctx->ctx_otoken);
947 if (rc != 0)
948 return (NT_STATUS_INTERNAL_ERROR);
949
950 /*
951 * Convert the SPNEGO token into binary form,
952 * writing it to the output buffer.
953 */
954 toklen = smbd_authsvc_bufsize;
955 rc = spnegoTokenGetBinary(ctx->ctx_otoken,
956 (uchar_t *)ctx->ctx_orawbuf, &toklen);
957 if (rc)
958 rc = NT_STATUS_INTERNAL_ERROR;
959 ctx->ctx_orawlen = (uint_t)toklen;
960
961 return (rc);
962 }
963
964 /*
965 * Wrapper for "Raw NTLMSSP", which is exactly like the
966 * normal (SPNEGO-wrapped) NTLMSSP but without SPNEGO.
967 * Setup back-end handler for: special_mech_raw_NTLMSSP
968 * Compare with smbd_authsvc_esfirst().
969 */
970 static int
smbd_raw_ntlmssp_esfirst(authsvc_context_t * ctx)971 smbd_raw_ntlmssp_esfirst(authsvc_context_t *ctx)
972 {
973 const spnego_mech_handler_t *mh;
974 int rc;
975
976 mh = &smbd_auth_mech_raw_ntlmssp;
977 rc = mh->mh_init(ctx);
978 if (rc != 0)
979 return (rc);
980
981 ctx->ctx_mech_oid = mh->mh_oid;
982 ctx->ctx_mh_work = mh->mh_work;
983 ctx->ctx_mh_fini = mh->mh_fini;
984
985 rc = smbd_raw_ntlmssp_esnext(ctx);
986
987 return (rc);
988 }
989
990
991 /*
992 * Wrapper for "Raw NTLMSSP", which is exactly like the
993 * normal (SPNEGO-wrapped) NTLMSSP but without SPNEGO.
994 * Just copy "raw" to "body", and vice versa.
995 * Compare with smbd_authsvc_esnext, smbd_authsvc_escmn
996 */
997 static int
smbd_raw_ntlmssp_esnext(authsvc_context_t * ctx)998 smbd_raw_ntlmssp_esnext(authsvc_context_t *ctx)
999 {
1000 int rc;
1001
1002 ctx->ctx_ibodylen = ctx->ctx_irawlen;
1003 (void) memcpy(ctx->ctx_ibodybuf,
1004 ctx->ctx_irawbuf, ctx->ctx_irawlen);
1005
1006 rc = ctx->ctx_mh_work(ctx);
1007
1008 ctx->ctx_orawlen = ctx->ctx_obodylen;
1009 (void) memcpy(ctx->ctx_orawbuf,
1010 ctx->ctx_obodybuf, ctx->ctx_obodylen);
1011
1012 return (rc);
1013 }
1014
1015
1016 /*
1017 * After a successful authentication, request the access token.
1018 */
1019 static int
smbd_authsvc_gettoken(authsvc_context_t * ctx)1020 smbd_authsvc_gettoken(authsvc_context_t *ctx)
1021 {
1022 XDR xdrs;
1023 smb_token_t *token = NULL;
1024 int rc = 0;
1025 int len;
1026
1027 if ((token = ctx->ctx_token) == NULL)
1028 return (NT_STATUS_ACCESS_DENIED);
1029
1030 /*
1031 * Encode the token response
1032 */
1033 len = xdr_sizeof(smb_token_xdr, token);
1034 if (len > ctx->ctx_orawlen) {
1035 if ((ctx->ctx_orawbuf = realloc(ctx->ctx_orawbuf, len)) ==
1036 NULL) {
1037 return (NT_STATUS_NO_MEMORY);
1038 }
1039 }
1040
1041 ctx->ctx_orawtype = LSA_MTYPE_TOKEN;
1042 ctx->ctx_orawlen = len;
1043 xdrmem_create(&xdrs, ctx->ctx_orawbuf, len, XDR_ENCODE);
1044 if (!smb_token_xdr(&xdrs, token))
1045 rc = NT_STATUS_INTERNAL_ERROR;
1046 xdr_destroy(&xdrs);
1047
1048 return (rc);
1049 }
1050
1051 /*
1052 * Initialization time code to figure out what mechanisms we support.
1053 * Careful with this table; the code below knows its format and may
1054 * skip the fist two entries to omit Kerberos.
1055 */
1056 static SPNEGO_MECH_OID MechTypeList[] = {
1057 spnego_mech_oid_Kerberos_V5,
1058 spnego_mech_oid_Kerberos_V5_Legacy,
1059 #define MECH_OID_IDX_NTLMSSP 2
1060 spnego_mech_oid_NTLMSSP,
1061 };
1062 static int MechTypeCnt = sizeof (MechTypeList) /
1063 sizeof (MechTypeList[0]);
1064
1065 /* This string is just like Windows. */
1066 static char IgnoreSPN[] = "not_defined_in_RFC4178@please_ignore";
1067
1068 /*
1069 * Build the SPNEGO "hint" token based on the
1070 * configured authentication mechanisms.
1071 * (NTLMSSP, and maybe Kerberos)
1072 */
1073 void
smbd_get_authconf(smb_kmod_cfg_t * kcfg)1074 smbd_get_authconf(smb_kmod_cfg_t *kcfg)
1075 {
1076 SPNEGO_MECH_OID *mechList = MechTypeList;
1077 int mechCnt = MechTypeCnt;
1078 SPNEGO_TOKEN_HANDLE hSpnegoToken = NULL;
1079 uchar_t *pBuf = kcfg->skc_negtok;
1080 uint32_t *pBufLen = &kcfg->skc_negtok_len;
1081 ulong_t tLen = sizeof (kcfg->skc_negtok);
1082 int rc;
1083
1084 /*
1085 * In workgroup mode, skip Kerberos.
1086 */
1087 if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) {
1088 mechList += MECH_OID_IDX_NTLMSSP;
1089 mechCnt -= MECH_OID_IDX_NTLMSSP;
1090 }
1091
1092 rc = spnegoCreateNegTokenHint(mechList, mechCnt,
1093 (uchar_t *)IgnoreSPN, &hSpnegoToken);
1094 if (rc != SPNEGO_E_SUCCESS) {
1095 syslog(LOG_DEBUG, "smb_config_get_negtok: "
1096 "spnegoCreateNegTokenHint, rc=%d", rc);
1097 *pBufLen = 0;
1098 return;
1099 }
1100 rc = spnegoTokenGetBinary(hSpnegoToken, pBuf, &tLen);
1101 if (rc != SPNEGO_E_SUCCESS) {
1102 syslog(LOG_DEBUG, "smb_config_get_negtok: "
1103 "spnegoTokenGetBinary, rc=%d", rc);
1104 *pBufLen = 0;
1105 } else {
1106 *pBufLen = (uint32_t)tLen;
1107 }
1108 spnegoFreeData(hSpnegoToken);
1109 }
1110