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