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