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
smbd_authsvc_start(void)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
smbd_authsvc_stop(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
smbd_authsock_create(void)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
smbd_authsock_destroy(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 *
smbd_authsvc_listen(void * arg)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
smbd_authsvc_flood(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 *
smbd_authctx_create(void)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
smbd_authctx_destroy(authsvc_context_t * ctx)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 *
smbd_authsvc_work(void * arg)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
smbd_authsvc_dispatch(authsvc_context_t * ctx)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
smbd_authsvc_oldreq(authsvc_context_t * ctx)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
smbd_authsvc_clinfo(authsvc_context_t * ctx)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
smbd_authsvc_esfirst(authsvc_context_t * ctx)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
smbd_authsvc_esnext(authsvc_context_t * ctx)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
smbd_authsvc_escmn(authsvc_context_t * ctx)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
smbd_raw_ntlmssp_esfirst(authsvc_context_t * ctx)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
smbd_raw_ntlmssp_esnext(authsvc_context_t * ctx)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
smbd_authsvc_gettoken(authsvc_context_t * ctx)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
smbd_get_authconf(smb_kmod_cfg_t * kcfg)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