8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / smbsrv / smbd / smbd_authsvc.c
blob0b6af80bd8029999a61f7c7d9d2bda2ee1b702b0
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.
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.
13 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
17 * SMB authentication service
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.
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>
46 #include "smbd.h"
47 #include "smbd_authsvc.h"
49 /* Arbitrary value outside the (small) range of valid OIDs */
50 #define special_mech_raw_NTLMSSP (spnego_mech_oid_NTLMSSP + 100)
52 static struct sockaddr_un smbauth_sockname = {
53 AF_UNIX, SMB_AUTHSVC_SOCKNAME };
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;
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);
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 *);
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.
82 int smbd_authsvc_bufsize = 65000;
84 static mutex_t smbd_authsvc_mutex = DEFAULTMUTEX;
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.
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
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.
108 static const spnego_mech_handler_t
109 mech_table[] = {
111 spnego_mech_oid_Kerberos_V5,
112 smbd_krb5ssp_init,
113 smbd_krb5ssp_work,
114 smbd_krb5ssp_fini
117 spnego_mech_oid_Kerberos_V5_Legacy,
118 smbd_krb5ssp_init,
119 smbd_krb5ssp_work,
120 smbd_krb5ssp_fini
122 #define MECH_TBL_IDX_NTLMSSP 2
124 spnego_mech_oid_NTLMSSP,
125 smbd_ntlmssp_init,
126 smbd_ntlmssp_work,
127 smbd_ntlmssp_fini
130 /* end marker */
131 spnego_mech_oid_NotUsed,
132 NULL, NULL, NULL
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
146 * Start the authentication service.
147 * Returns non-zero on error.
150 smbd_authsvc_start(void)
152 pthread_attr_t attr;
153 pthread_t tid;
154 int rc;
156 rc = smbd_authsock_create();
157 if (rc)
158 return (rc);
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);
169 smbd.s_authsvc_tid = tid;
170 return (0);
173 void
174 smbd_authsvc_stop(void)
177 if (smbd.s_authsvc_tid != 0) {
178 (void) pthread_kill(smbd.s_authsvc_tid, SIGTERM);
179 smbd.s_authsvc_tid = 0;
183 static int
184 smbd_authsock_create(void)
186 int sock = -1;
188 sock = socket(AF_UNIX, SOCK_STREAM, 0);
189 if (sock < 0) {
190 smbd_report("authsvc, socket create failed, %d", errno);
191 return (errno);
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);
202 if (listen(sock, SOMAXCONN) < 0) {
203 smbd_report("authsvc, socket listen failed, %d", errno);
204 (void) close(sock);
205 return (errno);
208 smbd.s_authsvc_sock = sock;
209 return (0);
212 static void
213 smbd_authsock_destroy(void)
215 int fid;
217 if ((fid = smbd.s_authsvc_sock) != -1) {
218 smbd.s_authsvc_sock = -1;
219 (void) close(fid);
223 static void *
224 smbd_authsvc_listen(void *arg)
226 authsvc_context_t *ctx;
227 pthread_attr_t attr;
228 pthread_t tid;
229 socklen_t slen;
230 int ls, ns, rc;
232 _NOTE(ARGUNUSED(arg))
234 (void) pthread_attr_init(&attr);
235 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
237 ls = smbd.s_authsvc_sock;
238 for (;;) {
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;
257 * Limit the number of auth. sockets
258 * (and the threads that service them).
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;
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);
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;
281 ctx->ctx_socket = ns;
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;
292 ctx = NULL; /* given to the new thread */
295 out:
296 (void) pthread_attr_destroy(&attr);
297 smbd_authsock_destroy();
298 return (NULL);
301 static void
302 smbd_authsvc_flood(void)
304 static uint_t count;
305 static time_t last_report;
306 time_t now = time(NULL);
308 count++;
309 if (last_report + 60 < now) {
310 last_report = now;
311 smbd_report("authsvc: flooded %u", count);
312 count = 0;
316 authsvc_context_t *
317 smbd_authctx_create(void)
319 authsvc_context_t *ctx;
321 ctx = malloc(sizeof (*ctx));
322 if (ctx == NULL)
323 return (NULL);
324 bzero(ctx, sizeof (*ctx));
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;
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;
340 return (ctx);
342 errout:
343 smbd_authctx_destroy(ctx);
344 return (NULL);
347 void
348 smbd_authctx_destroy(authsvc_context_t *ctx)
350 if (ctx->ctx_socket != -1) {
351 (void) close(ctx->ctx_socket);
352 ctx->ctx_socket = -1;
355 if (ctx->ctx_token != NULL)
356 smb_token_destroy(ctx->ctx_token);
358 if (ctx->ctx_itoken != NULL)
359 spnegoFreeData(ctx->ctx_itoken);
360 if (ctx->ctx_otoken != NULL)
361 spnegoFreeData(ctx->ctx_otoken);
363 free(ctx->ctx_irawbuf);
364 free(ctx->ctx_orawbuf);
365 free(ctx->ctx_ibodybuf);
366 free(ctx->ctx_obodybuf);
368 free(ctx);
372 * Limit how long smbd_authsvc_work will wait for the client to
373 * send us the next part of the authentication sequence.
375 static struct timeval recv_tmo = { 30, 0 };
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.
382 static struct timeval send_tmo = { 15, 0 };
384 static void *
385 smbd_authsvc_work(void *arg)
387 authsvc_context_t *ctx = arg;
388 smb_lsa_msg_hdr_t hdr;
389 int sock = ctx->ctx_socket;
390 int len, rc;
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;
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;
404 for (;;) {
406 len = recv(sock, &hdr, sizeof (hdr), MSG_WAITALL);
407 if (len <= 0) {
408 /* normal termination */
409 break;
411 if (len != sizeof (hdr)) {
412 smbd_report("authsvc_work: read header failed");
413 break;
416 if (hdr.lmh_msglen > smbd_authsvc_bufsize) {
417 smbd_report("authsvc_work: msg too large");
418 break;
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;
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;
436 * The real work happens here.
438 rc = smbd_authsvc_dispatch(ctx);
439 if (rc)
440 break;
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;
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;
460 out:
461 if (ctx->ctx_mh_fini)
462 (ctx->ctx_mh_fini)(ctx);
464 smbd_authctx_destroy(ctx);
466 (void) mutex_lock(&smbd_authsvc_mutex);
467 smbd_authsvc_thrcnt--;
468 (void) mutex_unlock(&smbd_authsvc_mutex);
470 return (NULL); /* implied pthread_exit() */
474 * Dispatch based on message type LSA_MTYPE_...
475 * Non-zero return here ends the conversation.
478 smbd_authsvc_dispatch(authsvc_context_t *ctx)
480 int rc;
482 switch (ctx->ctx_irawtype) {
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;
492 case LSA_MTYPE_CLINFO:
493 rc = smbd_authsvc_clinfo(ctx);
494 break;
496 case LSA_MTYPE_ESFIRST:
497 rc = smbd_authsvc_esfirst(ctx);
498 break;
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;
508 case LSA_MTYPE_GETTOK:
509 rc = smbd_authsvc_gettoken(ctx);
510 break;
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);
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;
530 return (0);
533 static int
534 smbd_authsvc_oldreq(authsvc_context_t *ctx)
536 smb_logon_t user_info;
537 XDR xdrs;
538 smb_token_t *token = NULL;
539 int rc = 0;
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);
548 xdr_destroy(&xdrs);
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);
555 ctx->ctx_token = token;
557 return (rc);
560 static int
561 smbd_authsvc_clinfo(authsvc_context_t *ctx)
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));
569 ctx->ctx_orawtype = LSA_MTYPE_OK;
570 ctx->ctx_orawlen = 0;
571 return (0);
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
580 static int
581 smbd_authsvc_esfirst(authsvc_context_t *ctx)
583 const spnego_mech_handler_t *mh;
584 int idx, pref, rc;
585 int best_pref = 1000;
586 int best_mhidx = -1;
589 * NTLMSSP header is 8+, SPNEGO is 10+
591 if (ctx->ctx_irawlen < 8) {
592 smbd_report("authsvc: short blob");
593 return (NT_STATUS_INVALID_PARAMETER);
597 * We could have "Raw NTLMSSP" here intead of SPNEGO.
599 if (bcmp(ctx->ctx_irawbuf, "NTLMSSP", 8) == 0) {
600 rc = smbd_raw_ntlmssp_esfirst(ctx);
601 return (rc);
605 * Parse the SPNEGO token, check its type.
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);
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);
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);
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.
634 * Also, skip the Kerberos mechanisms in workgroup mode.
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];
642 for (; mh->mh_init != NULL; idx++, mh++) {
644 if (spnegoIsMechTypeAvailable(ctx->ctx_itoken,
645 mh->mh_oid, &pref) != 0)
646 continue;
648 if (pref < best_pref) {
649 best_pref = pref;
650 best_mhidx = idx;
653 if (best_mhidx == -1) {
654 smbd_report("authsvc: no supported spnego mechanism");
655 return (NT_STATUS_INVALID_PARAMETER);
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);
670 * Common to LSA_MTYPE_ESFIRST, LSA_MTYPE_ESNEXT
672 rc = smbd_authsvc_escmn(ctx);
673 return (rc);
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
682 static int
683 smbd_authsvc_esnext(authsvc_context_t *ctx)
685 int rc;
688 * Make sure LSA_MTYPE_ESFIRST was handled
689 * previously, so we have a work function.
691 if (ctx->ctx_mh_work == NULL)
692 return (NT_STATUS_INVALID_PARAMETER);
694 if (ctx->ctx_mech_oid == special_mech_raw_NTLMSSP) {
695 rc = smbd_raw_ntlmssp_esnext(ctx);
696 return (rc);
700 * Cleanup state from previous calls.
702 if (ctx->ctx_itoken != NULL) {
703 spnegoFreeData(ctx->ctx_itoken);
704 ctx->ctx_itoken = NULL;
708 * Parse the SPNEGO token, check its type.
710 rc = spnegoInitFromBinary(ctx->ctx_irawbuf,
711 ctx->ctx_irawlen, &ctx->ctx_itoken);
712 if (rc != 0)
713 return (NT_STATUS_INVALID_PARAMETER);
715 rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype);
716 if (rc != 0)
717 return (NT_STATUS_INVALID_PARAMETER);
719 if (ctx->ctx_itoktype != SPNEGO_TOKEN_TARG)
720 return (NT_STATUS_INVALID_PARAMETER);
722 rc = smbd_authsvc_escmn(ctx);
723 return (rc);
726 static int
727 smbd_authsvc_escmn(authsvc_context_t *ctx)
729 SPNEGO_MECH_OID oid;
730 ulong_t toklen;
731 int rc;
734 * Cleanup state from previous calls.
736 if (ctx->ctx_otoken != NULL) {
737 spnegoFreeData(ctx->ctx_otoken);
738 ctx->ctx_otoken = NULL;
742 * Extract the payload (mech token).
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);
758 ctx->ctx_ibodylen = toklen;
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).
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.
771 rc = ctx->ctx_mh_work(ctx);
772 if (rc != 0)
773 return (rc);
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.
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;
789 * Determine the spnego "negresult" from the
790 * reply message type (from the work func).
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);
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);
815 * Convert the SPNEGO token into binary form,
816 * writing it to the output buffer.
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;
825 return (rc);
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().
834 static int
835 smbd_raw_ntlmssp_esfirst(authsvc_context_t *ctx)
837 const spnego_mech_handler_t *mh;
838 int rc;
840 mh = &smbd_auth_mech_raw_ntlmssp;
841 rc = mh->mh_init(ctx);
842 if (rc != 0)
843 return (rc);
845 ctx->ctx_mech_oid = mh->mh_oid;
846 ctx->ctx_mh_work = mh->mh_work;
847 ctx->ctx_mh_fini = mh->mh_fini;
849 rc = smbd_raw_ntlmssp_esnext(ctx);
851 return (rc);
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
861 static int
862 smbd_raw_ntlmssp_esnext(authsvc_context_t *ctx)
864 int rc;
866 ctx->ctx_ibodylen = ctx->ctx_irawlen;
867 (void) memcpy(ctx->ctx_ibodybuf,
868 ctx->ctx_irawbuf, ctx->ctx_irawlen);
870 rc = ctx->ctx_mh_work(ctx);
872 ctx->ctx_orawlen = ctx->ctx_obodylen;
873 (void) memcpy(ctx->ctx_orawbuf,
874 ctx->ctx_obodybuf, ctx->ctx_obodylen);
876 return (rc);
881 * After a successful authentication, request the access token.
883 static int
884 smbd_authsvc_gettoken(authsvc_context_t *ctx)
886 XDR xdrs;
887 smb_token_t *token = NULL;
888 int rc = 0;
889 int len;
891 if ((token = ctx->ctx_token) == NULL)
892 return (NT_STATUS_ACCESS_DENIED);
895 * Encode the token response
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);
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);
912 return (rc);
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.
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,
926 static int MechTypeCnt = sizeof (MechTypeList) /
927 sizeof (MechTypeList[0]);
929 /* This string is just like Windows. */
930 static char IgnoreSPN[] = "not_defined_in_RFC4178@please_ignore";
933 * Build the SPNEGO "hint" token based on the
934 * configured authentication mechanisms.
935 * (NTLMSSP, and maybe Kerberos)
937 void
938 smbd_get_authconf(smb_kmod_cfg_t *kcfg)
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;
949 * In workgroup mode, skip Kerberos.
951 if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) {
952 mechList += MECH_OID_IDX_NTLMSSP;
953 mechCnt -= MECH_OID_IDX_NTLMSSP;
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;
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;
972 spnegoFreeData(hSpnegoToken);