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