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