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 }