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