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