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