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 goto out; 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 goto out; 291 } 292 ctx = NULL; /* given to the new thread */ 293 } 294 295 out: 296 (void) pthread_attr_destroy(&attr); 297 smbd_authsock_destroy(); 298 return (NULL); 299 } 300 301 static void 302 smbd_authsvc_flood(void) 303 { 304 static uint_t count; 305 static time_t last_report; 306 time_t now = time(NULL); 307 308 count++; 309 if (last_report + 60 < now) { 310 last_report = now; 311 smbd_report("authsvc: flooded %u", count); 312 count = 0; 313 } 314 } 315 316 authsvc_context_t * 317 smbd_authctx_create(void) 318 { 319 authsvc_context_t *ctx; 320 321 ctx = malloc(sizeof (*ctx)); 322 if (ctx == NULL) 323 return (NULL); 324 bzero(ctx, sizeof (*ctx)); 325 326 ctx->ctx_irawlen = smbd_authsvc_bufsize; 327 ctx->ctx_irawbuf = malloc(ctx->ctx_irawlen); 328 ctx->ctx_orawlen = smbd_authsvc_bufsize; 329 ctx->ctx_orawbuf = malloc(ctx->ctx_orawlen); 330 if (ctx->ctx_irawbuf == NULL || ctx->ctx_orawbuf == NULL) 331 goto errout; 332 333 ctx->ctx_ibodylen = smbd_authsvc_bufsize; 334 ctx->ctx_ibodybuf = malloc(ctx->ctx_ibodylen); 335 ctx->ctx_obodylen = smbd_authsvc_bufsize; 336 ctx->ctx_obodybuf = malloc(ctx->ctx_obodylen); 337 if (ctx->ctx_ibodybuf == NULL || ctx->ctx_obodybuf == NULL) 338 goto errout; 339 340 return (ctx); 341 342 errout: 343 smbd_authctx_destroy(ctx); 344 return (NULL); 345 } 346 347 void 348 smbd_authctx_destroy(authsvc_context_t *ctx) 349 { 350 if (ctx->ctx_socket != -1) { 351 (void) close(ctx->ctx_socket); 352 ctx->ctx_socket = -1; 353 } 354 355 if (ctx->ctx_token != NULL) 356 smb_token_destroy(ctx->ctx_token); 357 358 if (ctx->ctx_itoken != NULL) 359 spnegoFreeData(ctx->ctx_itoken); 360 if (ctx->ctx_otoken != NULL) 361 spnegoFreeData(ctx->ctx_otoken); 362 363 free(ctx->ctx_irawbuf); 364 free(ctx->ctx_orawbuf); 365 free(ctx->ctx_ibodybuf); 366 free(ctx->ctx_obodybuf); 367 368 free(ctx); 369 } 370 371 /* 372 * Limit how long smbd_authsvc_work will wait for the client to 373 * send us the next part of the authentication sequence. 374 */ 375 static struct timeval recv_tmo = { 30, 0 }; 376 377 /* 378 * Also set a timeout for send, where we're sending a response to 379 * the client side (in smbsrv). That should always be waiting in 380 * recv by the time we send, so a short timeout is OK. 381 */ 382 static struct timeval send_tmo = { 15, 0 }; 383 384 static void * 385 smbd_authsvc_work(void *arg) 386 { 387 authsvc_context_t *ctx = arg; 388 smb_lsa_msg_hdr_t hdr; 389 int sock = ctx->ctx_socket; 390 int len, rc; 391 392 if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, 393 (char *)&send_tmo, sizeof (send_tmo)) != 0) { 394 smbd_report("authsvc_work: set set timeout: %m"); 395 goto out; 396 } 397 398 if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, 399 (char *)&recv_tmo, sizeof (recv_tmo)) != 0) { 400 smbd_report("authsvc_work: set recv timeout: %m"); 401 goto out; 402 } 403 404 for (;;) { 405 406 len = recv(sock, &hdr, sizeof (hdr), MSG_WAITALL); 407 if (len <= 0) { 408 /* normal termination */ 409 break; 410 } 411 if (len != sizeof (hdr)) { 412 smbd_report("authsvc_work: read header failed"); 413 break; 414 } 415 416 if (hdr.lmh_msglen > smbd_authsvc_bufsize) { 417 smbd_report("authsvc_work: msg too large"); 418 break; 419 } 420 421 if (hdr.lmh_msglen > 0) { 422 len = recv(sock, ctx->ctx_irawbuf, hdr.lmh_msglen, 423 MSG_WAITALL); 424 if (len != hdr.lmh_msglen) { 425 smbd_report("authsvc_work: read mesg failed"); 426 break; 427 } 428 } 429 ctx->ctx_irawtype = hdr.lmh_msgtype; 430 ctx->ctx_irawlen = hdr.lmh_msglen; 431 ctx->ctx_orawlen = smbd_authsvc_bufsize; 432 ctx->ctx_ibodylen = smbd_authsvc_bufsize; 433 ctx->ctx_obodylen = smbd_authsvc_bufsize; 434 435 /* 436 * The real work happens here. 437 */ 438 rc = smbd_authsvc_dispatch(ctx); 439 if (rc) 440 break; 441 442 hdr.lmh_msgtype = ctx->ctx_orawtype; 443 hdr.lmh_msglen = ctx->ctx_orawlen; 444 len = send(sock, &hdr, sizeof (hdr), 0); 445 if (len != sizeof (hdr)) { 446 smbd_report("authsvc_work: send failed"); 447 break; 448 } 449 450 if (ctx->ctx_orawlen > 0) { 451 len = send(sock, ctx->ctx_orawbuf, 452 ctx->ctx_orawlen, 0); 453 if (len != ctx->ctx_orawlen) { 454 smbd_report("authsvc_work: send failed"); 455 break; 456 } 457 } 458 } 459 460 out: 461 if (ctx->ctx_mh_fini) 462 (ctx->ctx_mh_fini)(ctx); 463 464 smbd_authctx_destroy(ctx); 465 466 (void) mutex_lock(&smbd_authsvc_mutex); 467 smbd_authsvc_thrcnt--; 468 (void) mutex_unlock(&smbd_authsvc_mutex); 469 470 return (NULL); /* implied pthread_exit() */ 471 } 472 473 /* 474 * Dispatch based on message type LSA_MTYPE_... 475 * Non-zero return here ends the conversation. 476 */ 477 int 478 smbd_authsvc_dispatch(authsvc_context_t *ctx) 479 { 480 int rc; 481 482 switch (ctx->ctx_irawtype) { 483 484 case LSA_MTYPE_OLDREQ: 485 #ifdef DEBUG 486 if (smbd_authsvc_slowdown) 487 (void) sleep(smbd_authsvc_slowdown); 488 #endif 489 rc = smbd_authsvc_oldreq(ctx); 490 break; 491 492 case LSA_MTYPE_CLINFO: 493 rc = smbd_authsvc_clinfo(ctx); 494 break; 495 496 case LSA_MTYPE_ESFIRST: 497 rc = smbd_authsvc_esfirst(ctx); 498 break; 499 500 case LSA_MTYPE_ESNEXT: 501 #ifdef DEBUG 502 if (smbd_authsvc_slowdown) 503 (void) sleep(smbd_authsvc_slowdown); 504 #endif 505 rc = smbd_authsvc_esnext(ctx); 506 break; 507 508 case LSA_MTYPE_GETTOK: 509 rc = smbd_authsvc_gettoken(ctx); 510 break; 511 512 /* response types */ 513 case LSA_MTYPE_OK: 514 case LSA_MTYPE_ERROR: 515 case LSA_MTYPE_TOKEN: 516 case LSA_MTYPE_ES_CONT: 517 case LSA_MTYPE_ES_DONE: 518 default: 519 return (-1); 520 } 521 522 if (rc != 0) { 523 smb_lsa_eresp_t *er = ctx->ctx_orawbuf; 524 ctx->ctx_orawtype = LSA_MTYPE_ERROR; 525 ctx->ctx_orawlen = sizeof (*er); 526 er->ler_ntstatus = rc; 527 er->ler_errclass = 0; 528 er->ler_errcode = 0; 529 } 530 return (0); 531 } 532 533 static int 534 smbd_authsvc_oldreq(authsvc_context_t *ctx) 535 { 536 smb_logon_t user_info; 537 XDR xdrs; 538 smb_token_t *token = NULL; 539 int rc = 0; 540 541 bzero(&user_info, sizeof (user_info)); 542 xdrmem_create(&xdrs, ctx->ctx_irawbuf, ctx->ctx_irawlen, 543 XDR_DECODE); 544 if (!smb_logon_xdr(&xdrs, &user_info)) { 545 xdr_destroy(&xdrs); 546 return (NT_STATUS_INVALID_PARAMETER); 547 } 548 xdr_destroy(&xdrs); 549 550 token = smbd_user_auth_logon(&user_info); 551 xdr_free(smb_logon_xdr, (char *)&user_info); 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 } 558 559 ctx->ctx_token = token; 560 561 return (rc); 562 } 563 564 static int 565 smbd_authsvc_clinfo(authsvc_context_t *ctx) 566 { 567 568 if (ctx->ctx_irawlen != sizeof (smb_lsa_clinfo_t)) 569 return (NT_STATUS_INTERNAL_ERROR); 570 (void) memcpy(&ctx->ctx_clinfo, ctx->ctx_irawbuf, 571 sizeof (smb_lsa_clinfo_t)); 572 573 ctx->ctx_orawtype = LSA_MTYPE_OK; 574 ctx->ctx_orawlen = 0; 575 return (0); 576 } 577 578 /* 579 * Handle a security blob we've received from the client. 580 * Incoming type: LSA_MTYPE_ESFIRST 581 * Outgoing types: LSA_MTYPE_ES_CONT, LSA_MTYPE_ES_DONE, 582 * LSA_MTYPE_ERROR 583 */ 584 static int 585 smbd_authsvc_esfirst(authsvc_context_t *ctx) 586 { 587 const spnego_mech_handler_t *mh; 588 int idx, pref, rc; 589 int best_pref = 1000; 590 int best_mhidx = -1; 591 592 /* 593 * NTLMSSP header is 8+, SPNEGO is 10+ 594 */ 595 if (ctx->ctx_irawlen < 8) { 596 smbd_report("authsvc: short blob"); 597 return (NT_STATUS_INVALID_PARAMETER); 598 } 599 600 /* 601 * We could have "Raw NTLMSSP" here intead of SPNEGO. 602 */ 603 if (bcmp(ctx->ctx_irawbuf, "NTLMSSP", 8) == 0) { 604 rc = smbd_raw_ntlmssp_esfirst(ctx); 605 return (rc); 606 } 607 608 /* 609 * Parse the SPNEGO token, check its type. 610 */ 611 rc = spnegoInitFromBinary(ctx->ctx_irawbuf, 612 ctx->ctx_irawlen, &ctx->ctx_itoken); 613 if (rc != 0) { 614 smbd_report("authsvc: spnego parse failed"); 615 return (NT_STATUS_INVALID_PARAMETER); 616 } 617 618 rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype); 619 if (rc != 0) { 620 smbd_report("authsvc: spnego get token type failed"); 621 return (NT_STATUS_INVALID_PARAMETER); 622 } 623 624 if (ctx->ctx_itoktype != SPNEGO_TOKEN_INIT) { 625 smbd_report("authsvc: spnego wrong token type %d", 626 ctx->ctx_itoktype); 627 return (NT_STATUS_INVALID_PARAMETER); 628 } 629 630 /* 631 * Figure out which mech type to use. We want to use the 632 * first of the client's supported mechanisms that we also 633 * support. Unfortunately, the spnego code does not have an 634 * interface to walk the token's mech list, so we have to 635 * ask about each mech type we know and keep track of which 636 * was earliest in the token's mech list. 637 * 638 * Also, skip the Kerberos mechanisms in workgroup mode. 639 */ 640 idx = 0; 641 mh = mech_table; 642 if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) { 643 idx = MECH_TBL_IDX_NTLMSSP; 644 mh = &mech_table[idx]; 645 } 646 for (; mh->mh_init != NULL; idx++, mh++) { 647 648 if (spnegoIsMechTypeAvailable(ctx->ctx_itoken, 649 mh->mh_oid, &pref) != 0) 650 continue; 651 652 if (pref < best_pref) { 653 best_pref = pref; 654 best_mhidx = idx; 655 } 656 } 657 if (best_mhidx == -1) { 658 smbd_report("authsvc: no supported spnego mechanism"); 659 return (NT_STATUS_INVALID_PARAMETER); 660 } 661 662 /* Found a mutually agreeable mech. */ 663 mh = &mech_table[best_mhidx]; 664 ctx->ctx_mech_oid = mh->mh_oid; 665 ctx->ctx_mh_work = mh->mh_work; 666 ctx->ctx_mh_fini = mh->mh_fini; 667 rc = mh->mh_init(ctx); 668 if (rc != 0) { 669 smbd_report("authsvc: mech init failed"); 670 return (rc); 671 } 672 673 /* 674 * Common to LSA_MTYPE_ESFIRST, LSA_MTYPE_ESNEXT 675 */ 676 rc = smbd_authsvc_escmn(ctx); 677 return (rc); 678 } 679 680 /* 681 * Handle a security blob we've received from the client. 682 * Incoming type: LSA_MTYPE_ESNEXT 683 * Outgoing types: LSA_MTYPE_ES_CONT, LSA_MTYPE_ES_DONE, 684 * LSA_MTYPE_ERROR 685 */ 686 static int 687 smbd_authsvc_esnext(authsvc_context_t *ctx) 688 { 689 int rc; 690 691 /* 692 * Make sure LSA_MTYPE_ESFIRST was handled 693 * previously, so we have a work function. 694 */ 695 if (ctx->ctx_mh_work == NULL) 696 return (NT_STATUS_INVALID_PARAMETER); 697 698 if (ctx->ctx_mech_oid == special_mech_raw_NTLMSSP) { 699 rc = smbd_raw_ntlmssp_esnext(ctx); 700 return (rc); 701 } 702 703 /* 704 * Cleanup state from previous calls. 705 */ 706 if (ctx->ctx_itoken != NULL) { 707 spnegoFreeData(ctx->ctx_itoken); 708 ctx->ctx_itoken = NULL; 709 } 710 711 /* 712 * Parse the SPNEGO token, check its type. 713 */ 714 rc = spnegoInitFromBinary(ctx->ctx_irawbuf, 715 ctx->ctx_irawlen, &ctx->ctx_itoken); 716 if (rc != 0) 717 return (NT_STATUS_INVALID_PARAMETER); 718 719 rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype); 720 if (rc != 0) 721 return (NT_STATUS_INVALID_PARAMETER); 722 723 if (ctx->ctx_itoktype != SPNEGO_TOKEN_TARG) 724 return (NT_STATUS_INVALID_PARAMETER); 725 726 rc = smbd_authsvc_escmn(ctx); 727 return (rc); 728 } 729 730 static int 731 smbd_authsvc_escmn(authsvc_context_t *ctx) 732 { 733 SPNEGO_MECH_OID oid; 734 ulong_t toklen; 735 int rc; 736 737 /* 738 * Cleanup state from previous calls. 739 */ 740 if (ctx->ctx_otoken != NULL) { 741 spnegoFreeData(ctx->ctx_otoken); 742 ctx->ctx_otoken = NULL; 743 } 744 745 /* 746 * Extract the payload (mech token). 747 */ 748 toklen = ctx->ctx_ibodylen; 749 rc = spnegoGetMechToken(ctx->ctx_itoken, 750 ctx->ctx_ibodybuf, &toklen); 751 switch (rc) { 752 case SPNEGO_E_SUCCESS: 753 break; 754 case SPNEGO_E_ELEMENT_UNAVAILABLE: 755 toklen = 0; 756 break; 757 case SPNEGO_E_BUFFER_TOO_SMALL: 758 return (NT_STATUS_BUFFER_TOO_SMALL); 759 default: 760 return (NT_STATUS_INTERNAL_ERROR); 761 } 762 ctx->ctx_ibodylen = toklen; 763 764 /* 765 * Now that we have the incoming "body" (mech. token), 766 * call the back-end mech-specific work function to 767 * create the outgoing "body" (mech. token). 768 * 769 * The worker must fill in: ctx->ctx_negresult, 770 * and: ctx->ctx_obodylen, but ctx->ctx_obodybuf 771 * is optional, and is typically NULL after the 772 * final message of an auth sequence, where 773 * negresult == spnego_negresult_complete. 774 */ 775 rc = ctx->ctx_mh_work(ctx); 776 if (rc != 0) 777 return (rc); 778 779 /* 780 * Wrap the outgoing body in a negTokenTarg SPNEGO token. 781 * The selected mech. OID is returned only when the 782 * incoming token was of type SPNEGO_TOKEN_INIT. 783 */ 784 if (ctx->ctx_itoktype == SPNEGO_TOKEN_INIT) { 785 /* tell the client the selected mech. */ 786 oid = ctx->ctx_mech_oid; 787 } else { 788 /* Omit the "supported mech." field. */ 789 oid = spnego_mech_oid_NotUsed; 790 } 791 792 /* 793 * Determine the spnego "negresult" from the 794 * reply message type (from the work func). 795 */ 796 switch (ctx->ctx_orawtype) { 797 case LSA_MTYPE_ERROR: 798 ctx->ctx_negresult = spnego_negresult_rejected; 799 break; 800 case LSA_MTYPE_ES_DONE: 801 ctx->ctx_negresult = spnego_negresult_success; 802 break; 803 case LSA_MTYPE_ES_CONT: 804 ctx->ctx_negresult = spnego_negresult_incomplete; 805 break; 806 default: 807 return (-1); 808 } 809 810 rc = spnegoCreateNegTokenTarg( 811 oid, 812 ctx->ctx_negresult, 813 ctx->ctx_obodybuf, /* may be NULL */ 814 ctx->ctx_obodylen, 815 NULL, 0, 816 &ctx->ctx_otoken); 817 818 /* 819 * Convert the SPNEGO token into binary form, 820 * writing it to the output buffer. 821 */ 822 toklen = smbd_authsvc_bufsize; 823 rc = spnegoTokenGetBinary(ctx->ctx_otoken, 824 (uchar_t *)ctx->ctx_orawbuf, &toklen); 825 if (rc) 826 rc = NT_STATUS_INTERNAL_ERROR; 827 ctx->ctx_orawlen = (uint_t)toklen; 828 829 return (rc); 830 } 831 832 /* 833 * Wrapper for "Raw NTLMSSP", which is exactly like the 834 * normal (SPNEGO-wrapped) NTLMSSP but without SPNEGO. 835 * Setup back-end handler for: special_mech_raw_NTLMSSP 836 * Compare with smbd_authsvc_esfirst(). 837 */ 838 static int 839 smbd_raw_ntlmssp_esfirst(authsvc_context_t *ctx) 840 { 841 const spnego_mech_handler_t *mh; 842 int rc; 843 844 mh = &smbd_auth_mech_raw_ntlmssp; 845 rc = mh->mh_init(ctx); 846 if (rc != 0) 847 return (rc); 848 849 ctx->ctx_mech_oid = mh->mh_oid; 850 ctx->ctx_mh_work = mh->mh_work; 851 ctx->ctx_mh_fini = mh->mh_fini; 852 853 rc = smbd_raw_ntlmssp_esnext(ctx); 854 855 return (rc); 856 } 857 858 859 /* 860 * Wrapper for "Raw NTLMSSP", which is exactly like the 861 * normal (SPNEGO-wrapped) NTLMSSP but without SPNEGO. 862 * Just copy "raw" to "body", and vice versa. 863 * Compare with smbd_authsvc_esnext, smbd_authsvc_escmn 864 */ 865 static int 866 smbd_raw_ntlmssp_esnext(authsvc_context_t *ctx) 867 { 868 int rc; 869 870 ctx->ctx_ibodylen = ctx->ctx_irawlen; 871 (void) memcpy(ctx->ctx_ibodybuf, 872 ctx->ctx_irawbuf, ctx->ctx_irawlen); 873 874 rc = ctx->ctx_mh_work(ctx); 875 876 ctx->ctx_orawlen = ctx->ctx_obodylen; 877 (void) memcpy(ctx->ctx_orawbuf, 878 ctx->ctx_obodybuf, ctx->ctx_obodylen); 879 880 return (rc); 881 } 882 883 884 /* 885 * After a successful authentication, request the access token. 886 */ 887 static int 888 smbd_authsvc_gettoken(authsvc_context_t *ctx) 889 { 890 XDR xdrs; 891 smb_token_t *token = NULL; 892 int rc = 0; 893 int len; 894 895 if ((token = ctx->ctx_token) == NULL) 896 return (NT_STATUS_ACCESS_DENIED); 897 898 /* 899 * Encode the token response 900 */ 901 len = xdr_sizeof(smb_token_xdr, token); 902 if (len > ctx->ctx_orawlen) { 903 if ((ctx->ctx_orawbuf = realloc(ctx->ctx_orawbuf, len)) == 904 NULL) { 905 return (NT_STATUS_INTERNAL_ERROR); 906 } 907 } 908 909 ctx->ctx_orawtype = LSA_MTYPE_TOKEN; 910 ctx->ctx_orawlen = len; 911 xdrmem_create(&xdrs, ctx->ctx_orawbuf, len, XDR_ENCODE); 912 if (!smb_token_xdr(&xdrs, token)) 913 rc = NT_STATUS_INTERNAL_ERROR; 914 xdr_destroy(&xdrs); 915 916 return (rc); 917 } 918 919 /* 920 * Initialization time code to figure out what mechanisms we support. 921 * Careful with this table; the code below knows its format and may 922 * skip the fist two entries to omit Kerberos. 923 */ 924 static SPNEGO_MECH_OID MechTypeList[] = { 925 spnego_mech_oid_Kerberos_V5, 926 spnego_mech_oid_Kerberos_V5_Legacy, 927 #define MECH_OID_IDX_NTLMSSP 2 928 spnego_mech_oid_NTLMSSP, 929 }; 930 static int MechTypeCnt = sizeof (MechTypeList) / 931 sizeof (MechTypeList[0]); 932 933 /* This string is just like Windows. */ 934 static char IgnoreSPN[] = "not_defined_in_RFC4178@please_ignore"; 935 936 /* 937 * Build the SPNEGO "hint" token based on the 938 * configured authentication mechanisms. 939 * (NTLMSSP, and maybe Kerberos) 940 */ 941 void 942 smbd_get_authconf(smb_kmod_cfg_t *kcfg) 943 { 944 SPNEGO_MECH_OID *mechList = MechTypeList; 945 int mechCnt = MechTypeCnt; 946 SPNEGO_TOKEN_HANDLE hSpnegoToken = NULL; 947 uchar_t *pBuf = kcfg->skc_negtok; 948 uint32_t *pBufLen = &kcfg->skc_negtok_len; 949 ulong_t tLen = sizeof (kcfg->skc_negtok); 950 int rc; 951 952 /* 953 * In workgroup mode, skip Kerberos. 954 */ 955 if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) { 956 mechList += MECH_OID_IDX_NTLMSSP; 957 mechCnt -= MECH_OID_IDX_NTLMSSP; 958 } 959 960 rc = spnegoCreateNegTokenHint(mechList, mechCnt, 961 (uchar_t *)IgnoreSPN, &hSpnegoToken); 962 if (rc != SPNEGO_E_SUCCESS) { 963 syslog(LOG_DEBUG, "smb_config_get_negtok: " 964 "spnegoCreateNegTokenHint, rc=%d", rc); 965 *pBufLen = 0; 966 return; 967 } 968 rc = spnegoTokenGetBinary(hSpnegoToken, pBuf, &tLen); 969 if (rc != SPNEGO_E_SUCCESS) { 970 syslog(LOG_DEBUG, "smb_config_get_negtok: " 971 "spnegoTokenGetBinary, rc=%d", rc); 972 *pBufLen = 0; 973 } else { 974 *pBufLen = (uint32_t)tLen; 975 } 976 spnegoFreeData(hSpnegoToken); 977 } 978