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
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>
35 #include <net/route.h>
36 #include <sys/sockio.h>
37 #include <sys/socket.h>
39 #include <netinet/in.h>
43 #include <smbsrv/libsmb.h>
44 #include <netsmb/spnego.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 */
98 int smbd_authsvc_slowdown
= 0;
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
111 spnego_mech_oid_Kerberos_V5
,
117 spnego_mech_oid_Kerberos_V5_Legacy
,
122 #define MECH_TBL_IDX_NTLMSSP 2
124 spnego_mech_oid_NTLMSSP
,
131 spnego_mech_oid_NotUsed
,
136 static const spnego_mech_handler_t
137 smbd_auth_mech_raw_ntlmssp
= {
138 special_mech_raw_NTLMSSP
,
146 * Start the authentication service.
147 * Returns non-zero on error.
150 smbd_authsvc_start(void)
156 rc
= smbd_authsock_create();
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
);
165 smbd_authsock_destroy();
169 smbd
.s_authsvc_tid
= tid
;
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;
184 smbd_authsock_create(void)
188 sock
= socket(AF_UNIX
, SOCK_STREAM
, 0);
190 smbd_report("authsvc, socket create failed, %d", 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
);
202 if (listen(sock
, SOMAXCONN
) < 0) {
203 smbd_report("authsvc, socket listen failed, %d", errno
);
208 smbd
.s_authsvc_sock
= sock
;
213 smbd_authsock_destroy(void)
217 if ((fid
= smbd
.s_authsvc_sock
) != -1) {
218 smbd
.s_authsvc_sock
= -1;
224 smbd_authsvc_listen(void *arg
)
226 authsvc_context_t
*ctx
;
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
;
241 ns
= accept(ls
, NULL
, &slen
);
247 /* normal termination */
250 smbd_report("authsvc, socket accept failed,"
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
);
264 smbd_authsvc_flood();
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();
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
);
281 ctx
->ctx_socket
= ns
;
283 rc
= pthread_create(&tid
, &attr
, smbd_authsvc_work
, ctx
);
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
);
292 ctx
= NULL
; /* given to the new thread */
296 (void) pthread_attr_destroy(&attr
);
297 smbd_authsock_destroy();
302 smbd_authsvc_flood(void)
305 static time_t last_report
;
306 time_t now
= time(NULL
);
309 if (last_report
+ 60 < now
) {
311 smbd_report("authsvc: flooded %u", count
);
317 smbd_authctx_create(void)
319 authsvc_context_t
*ctx
;
321 ctx
= malloc(sizeof (*ctx
));
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
)
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
)
343 smbd_authctx_destroy(ctx
);
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
);
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 };
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
;
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");
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");
406 len
= recv(sock
, &hdr
, sizeof (hdr
), MSG_WAITALL
);
408 /* normal termination */
411 if (len
!= sizeof (hdr
)) {
412 smbd_report("authsvc_work: read header failed");
416 if (hdr
.lmh_msglen
> smbd_authsvc_bufsize
) {
417 smbd_report("authsvc_work: msg too large");
421 if (hdr
.lmh_msglen
> 0) {
422 len
= recv(sock
, ctx
->ctx_irawbuf
, hdr
.lmh_msglen
,
424 if (len
!= hdr
.lmh_msglen
) {
425 smbd_report("authsvc_work: read mesg failed");
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
);
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");
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");
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
)
482 switch (ctx
->ctx_irawtype
) {
484 case LSA_MTYPE_OLDREQ
:
486 if (smbd_authsvc_slowdown
)
487 (void) sleep(smbd_authsvc_slowdown
);
489 rc
= smbd_authsvc_oldreq(ctx
);
492 case LSA_MTYPE_CLINFO
:
493 rc
= smbd_authsvc_clinfo(ctx
);
496 case LSA_MTYPE_ESFIRST
:
497 rc
= smbd_authsvc_esfirst(ctx
);
500 case LSA_MTYPE_ESNEXT
:
502 if (smbd_authsvc_slowdown
)
503 (void) sleep(smbd_authsvc_slowdown
);
505 rc
= smbd_authsvc_esnext(ctx
);
508 case LSA_MTYPE_GETTOK
:
509 rc
= smbd_authsvc_gettoken(ctx
);
514 case LSA_MTYPE_ERROR
:
515 case LSA_MTYPE_TOKEN
:
516 case LSA_MTYPE_ES_CONT
:
517 case LSA_MTYPE_ES_DONE
:
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;
534 smbd_authsvc_oldreq(authsvc_context_t
*ctx
)
536 smb_logon_t user_info
;
538 smb_token_t
*token
= NULL
;
541 bzero(&user_info
, sizeof (user_info
));
542 xdrmem_create(&xdrs
, ctx
->ctx_irawbuf
, ctx
->ctx_irawlen
,
544 if (!smb_logon_xdr(&xdrs
, &user_info
)) {
546 return (NT_STATUS_INVALID_PARAMETER
);
550 token
= smbd_user_auth_logon(&user_info
);
551 xdr_free(smb_logon_xdr
, (char *)&user_info
);
553 return (NT_STATUS_ACCESS_DENIED
);
555 ctx
->ctx_token
= token
;
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;
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,
581 smbd_authsvc_esfirst(authsvc_context_t
*ctx
)
583 const spnego_mech_handler_t
*mh
;
585 int best_pref
= 1000;
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
);
605 * Parse the SPNEGO token, check its type.
607 rc
= spnegoInitFromBinary(ctx
->ctx_irawbuf
,
608 ctx
->ctx_irawlen
, &ctx
->ctx_itoken
);
610 smbd_report("authsvc: spnego parse failed");
611 return (NT_STATUS_INVALID_PARAMETER
);
614 rc
= spnegoGetTokenType(ctx
->ctx_itoken
, &ctx
->ctx_itoktype
);
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",
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.
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)
648 if (pref
< best_pref
) {
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
);
665 smbd_report("authsvc: mech init failed");
670 * Common to LSA_MTYPE_ESFIRST, LSA_MTYPE_ESNEXT
672 rc
= smbd_authsvc_escmn(ctx
);
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,
683 smbd_authsvc_esnext(authsvc_context_t
*ctx
)
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
);
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
);
713 return (NT_STATUS_INVALID_PARAMETER
);
715 rc
= spnegoGetTokenType(ctx
->ctx_itoken
, &ctx
->ctx_itoktype
);
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
);
727 smbd_authsvc_escmn(authsvc_context_t
*ctx
)
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
);
748 case SPNEGO_E_SUCCESS
:
750 case SPNEGO_E_ELEMENT_UNAVAILABLE
:
753 case SPNEGO_E_BUFFER_TOO_SMALL
:
754 return (NT_STATUS_BUFFER_TOO_SMALL
);
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
);
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
;
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
;
796 case LSA_MTYPE_ES_DONE
:
797 ctx
->ctx_negresult
= spnego_negresult_success
;
799 case LSA_MTYPE_ES_CONT
:
800 ctx
->ctx_negresult
= spnego_negresult_incomplete
;
806 rc
= spnegoCreateNegTokenTarg(
809 ctx
->ctx_obodybuf
, /* may be NULL */
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
);
822 rc
= NT_STATUS_INTERNAL_ERROR
;
823 ctx
->ctx_orawlen
= (uint_t
)toklen
;
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().
835 smbd_raw_ntlmssp_esfirst(authsvc_context_t
*ctx
)
837 const spnego_mech_handler_t
*mh
;
840 mh
= &smbd_auth_mech_raw_ntlmssp
;
841 rc
= mh
->mh_init(ctx
);
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
);
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
862 smbd_raw_ntlmssp_esnext(authsvc_context_t
*ctx
)
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
);
881 * After a successful authentication, request the access token.
884 smbd_authsvc_gettoken(authsvc_context_t
*ctx
)
887 smb_token_t
*token
= NULL
;
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
)) ==
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
;
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)
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
);
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
);
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
);
970 *pBufLen
= (uint32_t)tLen
;
972 spnegoFreeData(hSpnegoToken
);