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