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 2014 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 ommit 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 return (NT_STATUS_ACCESS_DENIED); 554 555 ctx->ctx_token = token; 556 557 return (rc); 558 } 559 560 static int 561 smbd_authsvc_clinfo(authsvc_context_t *ctx) 562 { 563 564 if (ctx->ctx_irawlen != sizeof (smb_lsa_clinfo_t)) 565 return (NT_STATUS_INTERNAL_ERROR); 566 (void) memcpy(&ctx->ctx_clinfo, ctx->ctx_irawbuf, 567 sizeof (smb_lsa_clinfo_t)); 568 569 ctx->ctx_orawtype = LSA_MTYPE_OK; 570 ctx->ctx_orawlen = 0; 571 return (0); 572 } 573 574 /* 575 * Handle a security blob we've received from the client. 576 * Incoming type: LSA_MTYPE_ESFIRST 577 * Outgoing types: LSA_MTYPE_ES_CONT, LSA_MTYPE_ES_DONE, 578 * LSA_MTYPE_ERROR 579 */ 580 static int 581 smbd_authsvc_esfirst(authsvc_context_t *ctx) 582 { 583 const spnego_mech_handler_t *mh; 584 int idx, pref, rc; 585 int best_pref = 1000; 586 int best_mhidx = -1; 587 588 /* 589 * NTLMSSP header is 8+, SPNEGO is 10+ 590 */ 591 if (ctx->ctx_irawlen < 8) { 592 smbd_report("authsvc: short blob"); 593 return (NT_STATUS_INVALID_PARAMETER); 594 } 595 596 /* 597 * We could have "Raw NTLMSSP" here intead of SPNEGO. 598 */ 599 if (bcmp(ctx->ctx_irawbuf, "NTLMSSP", 8) == 0) { 600 rc = smbd_raw_ntlmssp_esfirst(ctx); 601 return (rc); 602 } 603 604 /* 605 * Parse the SPNEGO token, check its type. 606 */ 607 rc = spnegoInitFromBinary(ctx->ctx_irawbuf, 608 ctx->ctx_irawlen, &ctx->ctx_itoken); 609 if (rc != 0) { 610 smbd_report("authsvc: spnego parse failed"); 611 return (NT_STATUS_INVALID_PARAMETER); 612 } 613 614 rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype); 615 if (rc != 0) { 616 smbd_report("authsvc: spnego get token type failed"); 617 return (NT_STATUS_INVALID_PARAMETER); 618 } 619 620 if (ctx->ctx_itoktype != SPNEGO_TOKEN_INIT) { 621 smbd_report("authsvc: spnego wrong token type %d", 622 ctx->ctx_itoktype); 623 return (NT_STATUS_INVALID_PARAMETER); 624 } 625 626 /* 627 * Figure out which mech type to use. We want to use the 628 * first of the client's supported mechanisms that we also 629 * support. Unfortunately, the spnego code does not have an 630 * interface to walk the token's mech list, so we have to 631 * ask about each mech type we know and keep track of which 632 * was earliest in the token's mech list. 633 * 634 * Also, skip the Kerberos mechanisms in workgroup mode. 635 */ 636 idx = 0; 637 mh = mech_table; 638 if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) { 639 idx = MECH_TBL_IDX_NTLMSSP; 640 mh = &mech_table[idx]; 641 } 642 for (; mh->mh_init != NULL; idx++, mh++) { 643 644 if (spnegoIsMechTypeAvailable(ctx->ctx_itoken, 645 mh->mh_oid, &pref) != 0) 646 continue; 647 648 if (pref < best_pref) { 649 best_pref = pref; 650 best_mhidx = idx; 651 } 652 } 653 if (best_mhidx == -1) { 654 smbd_report("authsvc: no supported spnego mechanism"); 655 return (NT_STATUS_INVALID_PARAMETER); 656 } 657 658 /* Found a mutually agreeable mech. */ 659 mh = &mech_table[best_mhidx]; 660 ctx->ctx_mech_oid = mh->mh_oid; 661 ctx->ctx_mh_work = mh->mh_work; 662 ctx->ctx_mh_fini = mh->mh_fini; 663 rc = mh->mh_init(ctx); 664 if (rc != 0) { 665 smbd_report("authsvc: mech init failed"); 666 return (rc); 667 } 668 669 /* 670 * Common to LSA_MTYPE_ESFIRST, LSA_MTYPE_ESNEXT 671 */ 672 rc = smbd_authsvc_escmn(ctx); 673 return (rc); 674 } 675 676 /* 677 * Handle a security blob we've received from the client. 678 * Incoming type: LSA_MTYPE_ESNEXT 679 * Outgoing types: LSA_MTYPE_ES_CONT, LSA_MTYPE_ES_DONE, 680 * LSA_MTYPE_ERROR 681 */ 682 static int 683 smbd_authsvc_esnext(authsvc_context_t *ctx) 684 { 685 int rc; 686 687 /* 688 * Make sure LSA_MTYPE_ESFIRST was handled 689 * previously, so we have a work function. 690 */ 691 if (ctx->ctx_mh_work == NULL) 692 return (NT_STATUS_INVALID_PARAMETER); 693 694 if (ctx->ctx_mech_oid == special_mech_raw_NTLMSSP) { 695 rc = smbd_raw_ntlmssp_esnext(ctx); 696 return (rc); 697 } 698 699 /* 700 * Cleanup state from previous calls. 701 */ 702 if (ctx->ctx_itoken != NULL) { 703 spnegoFreeData(ctx->ctx_itoken); 704 ctx->ctx_itoken = NULL; 705 } 706 707 /* 708 * Parse the SPNEGO token, check its type. 709 */ 710 rc = spnegoInitFromBinary(ctx->ctx_irawbuf, 711 ctx->ctx_irawlen, &ctx->ctx_itoken); 712 if (rc != 0) 713 return (NT_STATUS_INVALID_PARAMETER); 714 715 rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype); 716 if (rc != 0) 717 return (NT_STATUS_INVALID_PARAMETER); 718 719 if (ctx->ctx_itoktype != SPNEGO_TOKEN_TARG) 720 return (NT_STATUS_INVALID_PARAMETER); 721 722 rc = smbd_authsvc_escmn(ctx); 723 return (rc); 724 } 725 726 static int 727 smbd_authsvc_escmn(authsvc_context_t *ctx) 728 { 729 SPNEGO_MECH_OID oid; 730 ulong_t toklen; 731 int rc; 732 733 /* 734 * Cleanup state from previous calls. 735 */ 736 if (ctx->ctx_otoken != NULL) { 737 spnegoFreeData(ctx->ctx_otoken); 738 ctx->ctx_otoken = NULL; 739 } 740 741 /* 742 * Extract the payload (mech token). 743 */ 744 toklen = ctx->ctx_ibodylen; 745 rc = spnegoGetMechToken(ctx->ctx_itoken, 746 ctx->ctx_ibodybuf, &toklen); 747 switch (rc) { 748 case SPNEGO_E_SUCCESS: 749 break; 750 case SPNEGO_E_ELEMENT_UNAVAILABLE: 751 toklen = 0; 752 break; 753 case SPNEGO_E_BUFFER_TOO_SMALL: 754 return (NT_STATUS_BUFFER_TOO_SMALL); 755 default: 756 return (NT_STATUS_INTERNAL_ERROR); 757 } 758 ctx->ctx_ibodylen = toklen; 759 760 /* 761 * Now that we have the incoming "body" (mech. token), 762 * call the back-end mech-specific work function to 763 * create the outgoing "body" (mech. token). 764 * 765 * The worker must fill in: ctx->ctx_negresult, 766 * and: ctx->ctx_obodylen, but ctx->ctx_obodybuf 767 * is optional, and is typically NULL after the 768 * final message of an auth sequence, where 769 * negresult == spnego_negresult_complete. 770 */ 771 rc = ctx->ctx_mh_work(ctx); 772 if (rc != 0) 773 return (rc); 774 775 /* 776 * Wrap the outgoing body in a negTokenTarg SPNEGO token. 777 * The selected mech. OID is returned only when the 778 * incoming token was of type SPNEGO_TOKEN_INIT. 779 */ 780 if (ctx->ctx_itoktype == SPNEGO_TOKEN_INIT) { 781 /* tell the client the selected mech. */ 782 oid = ctx->ctx_mech_oid; 783 } else { 784 /* Ommit the "supported mech." field. */ 785 oid = spnego_mech_oid_NotUsed; 786 } 787 788 /* 789 * Determine the spnego "negresult" from the 790 * reply message type (from the work func). 791 */ 792 switch (ctx->ctx_orawtype) { 793 case LSA_MTYPE_ERROR: 794 ctx->ctx_negresult = spnego_negresult_rejected; 795 break; 796 case LSA_MTYPE_ES_DONE: 797 ctx->ctx_negresult = spnego_negresult_success; 798 break; 799 case LSA_MTYPE_ES_CONT: 800 ctx->ctx_negresult = spnego_negresult_incomplete; 801 break; 802 default: 803 return (-1); 804 } 805 806 rc = spnegoCreateNegTokenTarg( 807 oid, 808 ctx->ctx_negresult, 809 ctx->ctx_obodybuf, /* may be NULL */ 810 ctx->ctx_obodylen, 811 NULL, 0, 812 &ctx->ctx_otoken); 813 814 /* 815 * Convert the SPNEGO token into binary form, 816 * writing it to the output buffer. 817 */ 818 toklen = smbd_authsvc_bufsize; 819 rc = spnegoTokenGetBinary(ctx->ctx_otoken, 820 (uchar_t *)ctx->ctx_orawbuf, &toklen); 821 if (rc) 822 rc = NT_STATUS_INTERNAL_ERROR; 823 ctx->ctx_orawlen = (uint_t)toklen; 824 825 return (rc); 826 } 827 828 /* 829 * Wrapper for "Raw NTLMSSP", which is exactly like the 830 * normal (SPNEGO-wrapped) NTLMSSP but without SPNEGO. 831 * Setup back-end handler for: special_mech_raw_NTLMSSP 832 * Compare with smbd_authsvc_esfirst(). 833 */ 834 static int 835 smbd_raw_ntlmssp_esfirst(authsvc_context_t *ctx) 836 { 837 const spnego_mech_handler_t *mh; 838 int rc; 839 840 mh = &smbd_auth_mech_raw_ntlmssp; 841 rc = mh->mh_init(ctx); 842 if (rc != 0) 843 return (rc); 844 845 ctx->ctx_mech_oid = mh->mh_oid; 846 ctx->ctx_mh_work = mh->mh_work; 847 ctx->ctx_mh_fini = mh->mh_fini; 848 849 rc = smbd_raw_ntlmssp_esnext(ctx); 850 851 return (rc); 852 } 853 854 855 /* 856 * Wrapper for "Raw NTLMSSP", which is exactly like the 857 * normal (SPNEGO-wrapped) NTLMSSP but without SPNEGO. 858 * Just copy "raw" to "body", and vice versa. 859 * Compare with smbd_authsvc_esnext, smbd_authsvc_escmn 860 */ 861 static int 862 smbd_raw_ntlmssp_esnext(authsvc_context_t *ctx) 863 { 864 int rc; 865 866 ctx->ctx_ibodylen = ctx->ctx_irawlen; 867 (void) memcpy(ctx->ctx_ibodybuf, 868 ctx->ctx_irawbuf, ctx->ctx_irawlen); 869 870 rc = ctx->ctx_mh_work(ctx); 871 872 ctx->ctx_orawlen = ctx->ctx_obodylen; 873 (void) memcpy(ctx->ctx_orawbuf, 874 ctx->ctx_obodybuf, ctx->ctx_obodylen); 875 876 return (rc); 877 } 878 879 880 /* 881 * After a successful authentication, request the access token. 882 */ 883 static int 884 smbd_authsvc_gettoken(authsvc_context_t *ctx) 885 { 886 XDR xdrs; 887 smb_token_t *token = NULL; 888 int rc = 0; 889 int len; 890 891 if ((token = ctx->ctx_token) == NULL) 892 return (NT_STATUS_ACCESS_DENIED); 893 894 /* 895 * Encode the token response 896 */ 897 len = xdr_sizeof(smb_token_xdr, token); 898 if (len > ctx->ctx_orawlen) { 899 if ((ctx->ctx_orawbuf = realloc(ctx->ctx_orawbuf, len)) == 900 NULL) { 901 return (NT_STATUS_INTERNAL_ERROR); 902 } 903 } 904 905 ctx->ctx_orawtype = LSA_MTYPE_TOKEN; 906 ctx->ctx_orawlen = len; 907 xdrmem_create(&xdrs, ctx->ctx_orawbuf, len, XDR_ENCODE); 908 if (!smb_token_xdr(&xdrs, token)) 909 rc = NT_STATUS_INTERNAL_ERROR; 910 xdr_destroy(&xdrs); 911 912 return (rc); 913 } 914 915 /* 916 * Initialization time code to figure out what mechanisms we support. 917 * Careful with this table; the code below knows its format and may 918 * skip the fist two entries to ommit Kerberos. 919 */ 920 static SPNEGO_MECH_OID MechTypeList[] = { 921 spnego_mech_oid_Kerberos_V5, 922 spnego_mech_oid_Kerberos_V5_Legacy, 923 #define MECH_OID_IDX_NTLMSSP 2 924 spnego_mech_oid_NTLMSSP, 925 }; 926 static int MechTypeCnt = sizeof (MechTypeList) / 927 sizeof (MechTypeList[0]); 928 929 /* This string is just like Windows. */ 930 static char IgnoreSPN[] = "not_defined_in_RFC4178@please_ignore"; 931 932 /* 933 * Build the SPNEGO "hint" token based on the 934 * configured authentication mechanisms. 935 * (NTLMSSP, and maybe Kerberos) 936 */ 937 void 938 smbd_get_authconf(smb_kmod_cfg_t *kcfg) 939 { 940 SPNEGO_MECH_OID *mechList = MechTypeList; 941 int mechCnt = MechTypeCnt; 942 SPNEGO_TOKEN_HANDLE hSpnegoToken = NULL; 943 uchar_t *pBuf = kcfg->skc_negtok; 944 uint32_t *pBufLen = &kcfg->skc_negtok_len; 945 ulong_t tLen = sizeof (kcfg->skc_negtok); 946 int rc; 947 948 /* 949 * In workgroup mode, skip Kerberos. 950 */ 951 if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) { 952 mechList += MECH_OID_IDX_NTLMSSP; 953 mechCnt -= MECH_OID_IDX_NTLMSSP; 954 } 955 956 rc = spnegoCreateNegTokenHint(mechList, mechCnt, 957 (uchar_t *)IgnoreSPN, &hSpnegoToken); 958 if (rc != SPNEGO_E_SUCCESS) { 959 syslog(LOG_DEBUG, "smb_config_get_negtok: " 960 "spnegoCreateNegTokenHint, rc=%d", rc); 961 *pBufLen = 0; 962 return; 963 } 964 rc = spnegoTokenGetBinary(hSpnegoToken, pBuf, &tLen); 965 if (rc != SPNEGO_E_SUCCESS) { 966 syslog(LOG_DEBUG, "smb_config_get_negtok: " 967 "spnegoTokenGetBinary, rc=%d", rc); 968 *pBufLen = 0; 969 } else { 970 *pBufLen = (uint32_t)tLen; 971 } 972 spnegoFreeData(hSpnegoToken); 973 } 974