Print this page
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
NEX-16824 SMB client connection setup rework
NEX-17232 SMB client reconnect failures
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (improve debug)
NEX-15557 SMB client tries to connect twice
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15557 SMB client tries to connect twice
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
SUP-513 Unable to join AD domain (with NtlmMinSeverSec set in the registry)
 Implement "Extended Session Security" and "Key Exchange" in NTLMSSP
re #12394 rb3934 Even NULL sessions should use SPNEGO

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libsmbfs/smb/connect.c
          +++ new/usr/src/lib/libsmbfs/smb/connect.c
↓ open down ↓ 14 lines elided ↑ open up ↑
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
  25      - * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
       25 + *
       26 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  26   27   */
  27   28  
  28   29  /*
  29   30   * Functions to setup connections (TCP and/or NetBIOS)
  30   31   * This has the fall-back logic for IP6, IP4, NBT
  31   32   */
  32   33  
  33   34  #include <errno.h>
  34   35  #include <stdio.h>
  35   36  #include <string.h>
↓ open down ↓ 7 lines elided ↑ open up ↑
  43   44  
  44   45  #include <sys/types.h>
  45   46  #include <sys/time.h>
  46   47  #include <sys/byteorder.h>
  47   48  #include <sys/socket.h>
  48   49  #include <sys/fcntl.h>
  49   50  
  50   51  #include <netinet/in.h>
  51   52  #include <netinet/tcp.h>
  52   53  #include <arpa/inet.h>
       54 +#include <uuid/uuid.h>
  53   55  
  54   56  #include <netsmb/smb.h>
  55   57  #include <netsmb/smb_lib.h>
       58 +#include <netsmb/mchain.h>
  56   59  #include <netsmb/netbios.h>
  57   60  #include <netsmb/nb_lib.h>
  58   61  #include <netsmb/smb_dev.h>
  59   62  
       63 +#include <cflib.h>
       64 +
  60   65  #include "charsets.h"
  61   66  #include "private.h"
       67 +#include "smb_crypt.h"
  62   68  
  63      -/*
  64      - * SMB messages are up to 64K.
  65      - * Let's leave room for two.
  66      - */
  67      -static int smb_tcpsndbuf = 0x20000;
  68      -static int smb_tcprcvbuf = 0x20000;
  69      -static int smb_connect_timeout = 30; /* seconds */
  70      -int smb_recv_timeout = 30; /* seconds */
  71      -
  72      -int conn_tcp6(struct smb_ctx *, const struct sockaddr *, int);
  73      -int conn_tcp4(struct smb_ctx *, const struct sockaddr *, int);
  74      -int conn_nbt(struct smb_ctx *, const struct sockaddr *, char *);
  75      -
  76      -/*
  77      - * Internal set sockopt for int-sized options.
  78      - * Borrowed from: libnsl/rpc/ti_opts.c
  79      - */
  80   69  static int
  81      -smb_setopt_int(int fd, int level, int name, int val)
  82      -{
  83      -        struct t_optmgmt oreq, ores;
  84      -        struct {
  85      -                struct t_opthdr oh;
  86      -                int ival;
  87      -        } opts;
       70 +smb__ssnsetup(struct smb_ctx *ctx,
       71 +        struct mbdata *mbc1, struct mbdata *mbc2);
  88   72  
  89      -        /* opt header */
  90      -        opts.oh.len = sizeof (opts);
  91      -        opts.oh.level = level;
  92      -        opts.oh.name = name;
  93      -        opts.oh.status = 0;
  94      -        opts.ival = val;
       73 +int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *);
  95   74  
  96      -        oreq.flags = T_NEGOTIATE;
  97      -        oreq.opt.buf = (void *)&opts;
  98      -        oreq.opt.len = sizeof (opts);
  99      -
 100      -        ores.flags = 0;
 101      -        ores.opt.buf = NULL;
 102      -        ores.opt.maxlen = 0;
 103      -
 104      -        if (t_optmgmt(fd, &oreq, &ores) < 0) {
 105      -                DPRINT("t_opgmgnt, t_errno = %d", t_errno);
 106      -                if (t_errno == TSYSERR)
 107      -                        return (errno);
 108      -                return (EPROTO);
 109      -        }
 110      -        if (ores.flags != T_SUCCESS) {
 111      -                DPRINT("flags 0x%x, status 0x%x",
 112      -                    (int)ores.flags, (int)opts.oh.status);
 113      -                return (EPROTO);
 114      -        }
 115      -
 116      -        return (0);
 117      -}
 118      -
 119      -static int
 120      -smb_setopts(int fd)
       75 +const char *
       76 +smb_iod_state_name(enum smbiod_state st)
 121   77  {
 122      -        int err;
       78 +        const char *n = "(?)";
 123   79  
 124      -        /*
 125      -         * Set various socket/TCP options.
 126      -         * Failures here are not fatal -
 127      -         * just log a complaint.
 128      -         *
 129      -         * We don't need these two:
 130      -         *   SO_RCVTIMEO, SO_SNDTIMEO
 131      -         */
 132      -
 133      -        err = smb_setopt_int(fd, SOL_SOCKET, SO_SNDBUF, smb_tcpsndbuf);
 134      -        if (err) {
 135      -                DPRINT("set SO_SNDBUF, err %d", err);
 136      -        }
 137      -
 138      -        err = smb_setopt_int(fd, SOL_SOCKET, SO_RCVBUF, smb_tcprcvbuf);
 139      -        if (err) {
 140      -                DPRINT("set SO_RCVBUF, err %d", err);
 141      -        }
 142      -
 143      -        err = smb_setopt_int(fd, SOL_SOCKET, SO_KEEPALIVE, 1);
 144      -        if (err) {
 145      -                DPRINT("set SO_KEEPALIVE, err %d", err);
 146      -        }
 147      -
 148      -        err = smb_setopt_int(fd, IPPROTO_TCP, TCP_NODELAY, 1);
 149      -        if (err) {
 150      -                DPRINT("set TCP_NODELAY, err %d", err);
 151      -        }
 152      -
 153      -        /* Set the connect timeout (in milliseconds). */
 154      -        err = smb_setopt_int(fd, IPPROTO_TCP,
 155      -            TCP_CONN_ABORT_THRESHOLD,
 156      -            smb_connect_timeout * 1000);
 157      -        if (err) {
 158      -                DPRINT("set connect timeout, err %d", err);
 159      -        }
 160      -        return (0);
 161      -}
 162      -
 163      -
 164      -int
 165      -conn_tcp6(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
 166      -{
 167      -        struct sockaddr_in6 sin6;
 168      -        char *dev = "/dev/tcp6";
 169      -        char paddrbuf[INET6_ADDRSTRLEN];
 170      -        struct t_call sndcall;
 171      -        int fd, err;
 172      -
 173      -        if (sa->sa_family != AF_INET6) {
 174      -                DPRINT("bad af %d", sa->sa_family);
 175      -                return (EINVAL);
 176      -        }
 177      -        bcopy(sa, &sin6, sizeof (sin6));
 178      -        sin6.sin6_port = htons(port);
 179      -
 180      -        DPRINT("tcp6: %s (%d)",
 181      -            inet_ntop(AF_INET6, &sin6.sin6_addr,
 182      -            paddrbuf, sizeof (paddrbuf)), port);
 183      -
 184      -        fd = t_open(dev, O_RDWR, NULL);
 185      -        if (fd < 0) {
 186      -                /* Assume t_errno = TSYSERR */
 187      -                err = errno;
 188      -                perror(dev);
 189      -                return (err);
 190      -        }
 191      -        if ((err = smb_setopts(fd)) != 0)
 192      -                goto errout;
 193      -        if (t_bind(fd, NULL, NULL) < 0) {
 194      -                DPRINT("t_bind t_errno %d", t_errno);
 195      -                if (t_errno == TSYSERR)
 196      -                        err = errno;
 197      -                else
 198      -                        err = EPROTO;
 199      -                goto errout;
 200      -        }
 201      -        sndcall.addr.maxlen = sizeof (sin6);
 202      -        sndcall.addr.len = sizeof (sin6);
 203      -        sndcall.addr.buf = (void *) &sin6;
 204      -        sndcall.opt.len = 0;
 205      -        sndcall.udata.len = 0;
 206      -        if (t_connect(fd, &sndcall, NULL) < 0) {
 207      -                err = get_xti_err(fd);
 208      -                DPRINT("connect, err %d", err);
 209      -                goto errout;
 210      -        }
 211      -
 212      -        DPRINT("tcp6: connected, fd=%d", fd);
 213      -        ctx->ct_tran_fd = fd;
 214      -        return (0);
 215      -
 216      -errout:
 217      -        close(fd);
 218      -        return (err);
 219      -}
 220      -
 221      -/*
 222      - * This is used for both SMB over TCP (port 445)
 223      - * and NetBIOS - see conn_nbt().
 224      - */
 225      -int
 226      -conn_tcp4(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
 227      -{
 228      -        struct sockaddr_in sin;
 229      -        char *dev = "/dev/tcp";
 230      -        char paddrbuf[INET_ADDRSTRLEN];
 231      -        struct t_call sndcall;
 232      -        int fd, err;
 233      -
 234      -        if (sa->sa_family != AF_INET) {
 235      -                DPRINT("bad af %d", sa->sa_family);
 236      -                return (EINVAL);
 237      -        }
 238      -        bcopy(sa, &sin, sizeof (sin));
 239      -        sin.sin_port = htons(port);
 240      -
 241      -        DPRINT("tcp4: %s (%d)",
 242      -            inet_ntop(AF_INET, &sin.sin_addr,
 243      -            paddrbuf, sizeof (paddrbuf)), port);
 244      -
 245      -        fd = t_open(dev, O_RDWR, NULL);
 246      -        if (fd < 0) {
 247      -                /* Assume t_errno = TSYSERR */
 248      -                err = errno;
 249      -                perror(dev);
 250      -                return (err);
 251      -        }
 252      -        if ((err = smb_setopts(fd)) != 0)
 253      -                goto errout;
 254      -        if (t_bind(fd, NULL, NULL) < 0) {
 255      -                DPRINT("t_bind t_errno %d", t_errno);
 256      -                if (t_errno == TSYSERR)
 257      -                        err = errno;
 258      -                else
 259      -                        err = EPROTO;
 260      -                goto errout;
 261      -        }
 262      -        sndcall.addr.maxlen = sizeof (sin);
 263      -        sndcall.addr.len = sizeof (sin);
 264      -        sndcall.addr.buf = (void *) &sin;
 265      -        sndcall.opt.len = 0;
 266      -        sndcall.udata.len = 0;
 267      -        if (t_connect(fd, &sndcall, NULL) < 0) {
 268      -                err = get_xti_err(fd);
 269      -                DPRINT("connect, err %d", err);
 270      -                goto errout;
 271      -        }
 272      -
 273      -        DPRINT("tcp4: connected, fd=%d", fd);
 274      -        ctx->ct_tran_fd = fd;
 275      -        return (0);
 276      -
 277      -errout:
 278      -        close(fd);
 279      -        return (err);
 280      -}
 281      -
 282      -/*
 283      - * Open a NetBIOS connection (session, port 139)
 284      - *
 285      - * The optional name parameter, if passed, means
 286      - * we found the sockaddr via NetBIOS name lookup,
 287      - * and can just use that for our session request.
 288      - * Otherwise (if name is NULL), we're connecting
 289      - * by IP address, and need to come up with the
 290      - * NetBIOS name by other means.
 291      - */
 292      -int
 293      -conn_nbt(struct smb_ctx *ctx, const struct sockaddr *saarg, char *name)
 294      -{
 295      -        struct sockaddr_in sin;
 296      -        struct sockaddr *sa;
 297      -        char server[NB_NAMELEN];
 298      -        char workgroup[NB_NAMELEN];
 299      -        int err, nberr, port;
 300      -
 301      -        bcopy(saarg, &sin, sizeof (sin));
 302      -        sa = (struct sockaddr *)&sin;
 303      -
 304      -        switch (sin.sin_family) {
 305      -        case AF_NETBIOS:        /* our fake AF */
 306      -                sin.sin_family = AF_INET;
       80 +        switch (st) {
       81 +        case SMBIOD_ST_UNINIT:
       82 +                n = "UNINIT!";
 307   83                  break;
 308      -        case AF_INET:
       84 +        case SMBIOD_ST_IDLE:
       85 +                n = "IDLE";
 309   86                  break;
 310      -        default:
 311      -                DPRINT("bad af %d", sin.sin_family);
 312      -                return (EINVAL);
       87 +        case SMBIOD_ST_RECONNECT:
       88 +                n = "RECONNECT";
       89 +                break;
       90 +        case SMBIOD_ST_RCFAILED:
       91 +                n = "RCFAILED";
       92 +                break;
       93 +        case SMBIOD_ST_CONNECTED:
       94 +                n = "CONNECTED";
       95 +                break;
       96 +        case SMBIOD_ST_NEGOTIATED:
       97 +                n = "NEGOTIATED";
       98 +                break;
       99 +        case SMBIOD_ST_AUTHCONT:
      100 +                n = "AUTHCONT";
      101 +                break;
      102 +        case SMBIOD_ST_AUTHFAIL:
      103 +                n = "AUTHFAIL";
      104 +                break;
      105 +        case SMBIOD_ST_AUTHOK:
      106 +                n = "AUTHOK";
      107 +                break;
      108 +        case SMBIOD_ST_VCACTIVE:
      109 +                n = "VCACTIVE";
      110 +                break;
      111 +        case SMBIOD_ST_DEAD:
      112 +                n = "DEAD";
      113 +                break;
 313  114          }
 314      -        port = IPPORT_NETBIOS_SSN;
 315  115  
 316      -        /*
 317      -         * If we have a NetBIOS name, just use it.
 318      -         * This is the path taken when we've done a
 319      -         * NetBIOS name lookup on this name to get
 320      -         * the IP address in the passed sa. Otherwise,
 321      -         * we're connecting by IP address, and need to
 322      -         * figure out what NetBIOS name to use.
 323      -         */
 324      -        if (name) {
 325      -                strlcpy(server, name, sizeof (server));
 326      -                DPRINT("given name: %s", server);
 327      -        } else {
 328      -                /*
 329      -                 *
 330      -                 * Try a NetBIOS node status query,
 331      -                 * which searches for a type=[20] name.
 332      -                 * If that doesn't work, just use the
 333      -                 * (fake) "*SMBSERVER" name.
 334      -                 */
 335      -                DPRINT("try node status");
 336      -                server[0] = '\0';
 337      -                nberr = nbns_getnodestatus(ctx->ct_nb,
 338      -                    &sin.sin_addr, server, workgroup);
 339      -                if (nberr == 0 && server[0] != '\0') {
 340      -                        /* Found the name.  Save for reconnect. */
 341      -                        DPRINT("found name: %s", server);
 342      -                        strlcpy(ctx->ct_srvname, server,
 343      -                            sizeof (ctx->ct_srvname));
 344      -                } else {
 345      -                        DPRINT("getnodestatus, nberr %d", nberr);
 346      -                        strlcpy(server, "*SMBSERVER", sizeof (server));
 347      -                }
 348      -        }
 349      -
 350      -        /*
 351      -         * Establish the TCP connection.
 352      -         * Careful to close it on errors.
 353      -         */
 354      -        if ((err = conn_tcp4(ctx, sa, port)) != 0) {
 355      -                DPRINT("TCP connect: err=%d", err);
 356      -                goto out;
 357      -        }
 358      -
 359      -        /* Connected.  Do NetBIOS session request. */
 360      -        err = nb_ssn_request(ctx, server);
 361      -        if (err)
 362      -                DPRINT("ssn_rq, err %d", err);
 363      -
 364      -out:
 365      -        if (err) {
 366      -                if (ctx->ct_tran_fd != -1) {
 367      -                        close(ctx->ct_tran_fd);
 368      -                        ctx->ct_tran_fd = -1;
 369      -                }
 370      -        }
 371      -        return (err);
      116 +        return (n);
 372  117  }
 373  118  
 374  119  /*
 375  120   * Make a new connection, or reconnect.
      121 + *
      122 + * This is called first from the door service thread in smbiod
      123 + * (so that can report success or failure to the door client)
      124 + * and thereafter it's called when we need to reconnect after a
      125 + * network outage (or whatever might cause connection loss).
 376  126   */
 377  127  int
 378  128  smb_iod_connect(smb_ctx_t *ctx)
 379  129  {
 380      -        struct sockaddr *sa;
 381      -        int err, err2;
      130 +        smbioc_ossn_t *ossn = &ctx->ct_ssn;
      131 +        smbioc_ssn_work_t *work = &ctx->ct_work;
      132 +        char *uuid_str;
      133 +        int err;
 382  134          struct mbdata blob;
      135 +        char *nego_buf = NULL;
      136 +        uint32_t nego_len;
 383  137  
 384  138          memset(&blob, 0, sizeof (blob));
 385  139  
 386  140          if (ctx->ct_srvname[0] == '\0') {
 387  141                  DPRINT("sername not set!");
 388  142                  return (EINVAL);
 389  143          }
 390  144          DPRINT("server: %s", ctx->ct_srvname);
 391  145  
 392  146          if (smb_debug)
 393  147                  dump_ctx("smb_iod_connect", ctx);
 394  148  
 395  149          /*
 396      -         * This may be a reconnect, so
 397      -         * cleanup if necessary.
 398      -         */
 399      -        if (ctx->ct_tran_fd != -1) {
 400      -                close(ctx->ct_tran_fd);
 401      -                ctx->ct_tran_fd = -1;
 402      -        }
 403      -
 404      -        /*
 405  150           * Get local machine name.
 406  151           * Full name - not a NetBIOS name.
 407  152           */
 408  153          if (ctx->ct_locname == NULL) {
 409  154                  err = smb_getlocalname(&ctx->ct_locname);
 410  155                  if (err) {
 411  156                          smb_error(dgettext(TEXT_DOMAIN,
 412  157                              "can't get local name"), err);
 413  158                          return (err);
 414  159                  }
 415  160          }
 416  161  
 417  162          /*
      163 +         * Get local machine uuid.
      164 +         */
      165 +        uuid_str = cf_get_client_uuid();
      166 +        if (uuid_str == NULL) {
      167 +                err = EINVAL;
      168 +                smb_error(dgettext(TEXT_DOMAIN,
      169 +                    "can't get local UUID"), err);
      170 +                        return (err);
      171 +        }
      172 +        (void) uuid_parse(uuid_str, ctx->ct_work.wk_cl_guid);
      173 +        free(uuid_str);
      174 +        uuid_str = NULL;
      175 +
      176 +        /*
 418  177           * We're called with each IP address
 419  178           * already copied into ct_srvaddr.
 420  179           */
 421  180          ctx->ct_flags |= SMBCF_RESOLVED;
 422  181  
 423      -        sa = &ctx->ct_srvaddr.sa;
 424      -        switch (sa->sa_family) {
 425      -
 426      -        case AF_INET6:
 427      -                err = conn_tcp6(ctx, sa, IPPORT_SMB);
 428      -                break;
 429      -
 430      -        case AF_INET:
 431      -                err = conn_tcp4(ctx, sa, IPPORT_SMB);
 432      -                /*
 433      -                 * If port 445 was not listening, try port 139.
 434      -                 * Note: Not doing NetBIOS name lookup here.
 435      -                 * We already have the IP address.
 436      -                 */
 437      -                switch (err) {
 438      -                case ECONNRESET:
 439      -                case ECONNREFUSED:
 440      -                        err2 = conn_nbt(ctx, sa, NULL);
 441      -                        if (err2 == 0)
 442      -                                err = 0;
 443      -                }
 444      -                break;
 445      -
 446      -        case AF_NETBIOS:
 447      -                /* Like AF_INET, but use NetBIOS ssn. */
 448      -                err = conn_nbt(ctx, sa, ctx->ct_srvname);
 449      -                break;
 450      -
 451      -        default:
 452      -                DPRINT("skipped family %d", sa->sa_family);
 453      -                err = EPROTONOSUPPORT;
 454      -                break;
 455      -        }
 456      -
 457      -
 458      -        if (err) {
 459      -                DPRINT("connect, err=%d", err);
      182 +        /*
      183 +         * Ask the drvier to connect.
      184 +         */
      185 +        DPRINT("Try ioctl connect...");
      186 +        if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_CONNECT, work) < 0) {
      187 +                err = errno;
      188 +                smb_error(dgettext(TEXT_DOMAIN,
      189 +                    "%s: connect failed"),
      190 +                    err, ossn->ssn_srvname);
 460  191                  return (err);
 461  192          }
      193 +        DPRINT("Connect OK, new state=%s",
      194 +            smb_iod_state_name(work->wk_out_state));
 462  195  
 463  196          /*
 464      -         * Do SMB Negotiate Protocol.
      197 +         * Setup a buffer to recv the nego. hint.
 465  198           */
 466      -        err = smb_negprot(ctx, &blob);
      199 +        nego_len = 4096;
      200 +        err = mb_init_sz(&blob, nego_len);
 467  201          if (err)
 468  202                  goto out;
      203 +        nego_buf = blob.mb_top->m_data;
      204 +        work->wk_u_auth_rbuf.lp_ptr = nego_buf;
      205 +        work->wk_u_auth_rlen = nego_len;
 469  206  
 470  207          /*
 471      -         * Empty user name means an explicit request for
 472      -         * NULL session setup, which is a special case.
 473      -         * If negotiate determined that we want to do
 474      -         * SMB signing, we have to turn that off for a
 475      -         * NULL session. [MS-SMB 3.3.5.3].
      208 +         * Ask the driver for SMB negotiate
 476  209           */
 477      -        if (ctx->ct_user[0] == '\0') {
 478      -                /* Null user should have null domain too. */
 479      -                ctx->ct_domain[0] = '\0';
 480      -                ctx->ct_authflags = SMB_AT_ANON;
 481      -                ctx->ct_clnt_caps &= ~SMB_CAP_EXT_SECURITY;
 482      -                ctx->ct_vcflags &= ~SMBV_WILL_SIGN;
      210 +        DPRINT("Try ioctl negotiate...");
      211 +        if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_NEGOTIATE, work) < 0) {
      212 +                err = errno;
      213 +                smb_error(dgettext(TEXT_DOMAIN,
      214 +                    "%s: negotiate failed"),
      215 +                    err, ossn->ssn_srvname);
      216 +                goto out;
 483  217          }
      218 +        DPRINT("Negotiate OK, new state=%s",
      219 +            smb_iod_state_name(work->wk_out_state));
 484  220  
      221 +        nego_len = work->wk_u_auth_rlen;
      222 +        blob.mb_top->m_len = nego_len;
      223 +
      224 +        if (smb_debug) {
      225 +                DPRINT("Sec. blob: %d", nego_len);
      226 +                smb_hexdump(nego_buf, nego_len);
      227 +        }
      228 +
 485  229          /*
 486  230           * Do SMB Session Setup (authenticate)
 487      -         *
 488      -         * If the server negotiated extended security,
 489      -         * run the SPNEGO state machine, otherwise do
 490      -         * one of the old-style variants.
      231 +         * Always "extended security" now (SPNEGO)
 491  232           */
 492      -        if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
 493      -                err = smb_ssnsetup_spnego(ctx, &blob);
 494      -        } else {
 495      -                /*
 496      -                 * Server did NOT negotiate extended security.
 497      -                 * Try NTLMv2, NTLMv1, or ANON (if enabled).
 498      -                 */
 499      -                if (ctx->ct_authflags & SMB_AT_NTLM2) {
 500      -                        err = smb_ssnsetup_ntlm2(ctx);
 501      -                } else if (ctx->ct_authflags & SMB_AT_NTLM1) {
 502      -                        err = smb_ssnsetup_ntlm1(ctx);
 503      -                } else if (ctx->ct_authflags & SMB_AT_ANON) {
 504      -                        err = smb_ssnsetup_null(ctx);
 505      -                } else {
      233 +        DPRINT("Do session setup...");
      234 +        err = smb_ssnsetup_spnego(ctx, &blob);
      235 +        if (err != 0) {
      236 +                DPRINT("Session setup err=%d", err);
      237 +                goto out;
      238 +        }
      239 +
      240 +        /*
      241 +         * Success! We return zero now, and our caller (normally
      242 +         * the smbiod program) will then call smb_iod_work in a
      243 +         * new thread to service this VC as long as necessary.
      244 +         */
      245 +        DPRINT("Session setup OK");
      246 +
      247 +out:
      248 +        mb_done(&blob);
      249 +
      250 +        return (err);
      251 +}
      252 +
      253 +/*
      254 + * smb_ssnsetup_spnego
      255 + *
      256 + * This does an SMB session setup sequence using SPNEGO.
      257 + * The state changes seen during this sequence are there
      258 + * just to help track what's going on.
      259 + */
      260 +int
      261 +smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb)
      262 +{
      263 +        struct mbdata send_mb, recv_mb;
      264 +        smbioc_ssn_work_t *work = &ctx->ct_work;
      265 +        int             err;
      266 +
      267 +        bzero(&send_mb, sizeof (send_mb));
      268 +        bzero(&recv_mb, sizeof (recv_mb));
      269 +
      270 +        err = ssp_ctx_create_client(ctx, hint_mb);
      271 +        if (err)
      272 +                goto out;
      273 +
      274 +        /* NULL input indicates first call. */
      275 +        err = ssp_ctx_next_token(ctx, NULL, &send_mb);
      276 +        if (err) {
      277 +                DPRINT("smb__ssnsetup, ssp next, err=%d", err);
      278 +                goto out;
      279 +        }
      280 +        for (;;) {
      281 +                err = smb__ssnsetup(ctx, &send_mb, &recv_mb);
      282 +                DPRINT("smb__ssnsetup rc=%d, new state=%s", err,
      283 +                    smb_iod_state_name(work->wk_out_state));
      284 +
      285 +                if (err == 0) {
 506  286                          /*
 507      -                         * Don't return EAUTH, because a new
 508      -                         * password prompt will not help.
      287 +                         * Session setup complete w/ success.
      288 +                         * Should have state AUTHOK
 509  289                           */
 510      -                        DPRINT("No NTLM authflags");
 511      -                        err = ENOTSUP;
      290 +                        if (work->wk_out_state != SMBIOD_ST_AUTHOK) {
      291 +                                DPRINT("Wrong state (expected AUTHOK)");
      292 +                        }
      293 +                        break;
 512  294                  }
      295 +
      296 +                if (err != EINPROGRESS) {
      297 +                        /*
      298 +                         * Session setup complete w/ failure.
      299 +                         * Should have state AUTHFAIL
      300 +                         */
      301 +                        if (work->wk_out_state != SMBIOD_ST_AUTHFAIL) {
      302 +                                DPRINT("Wrong state (expected AUTHFAIL)");
      303 +                        }
      304 +                        goto out;
      305 +                }
      306 +
      307 +                /*
      308 +                 * err == EINPROGRESS
      309 +                 * Session setup continuing.
      310 +                 * Should have state AUTHCONT
      311 +                 */
      312 +                if (work->wk_out_state != SMBIOD_ST_AUTHCONT) {
      313 +                        DPRINT("Wrong state (expected AUTHCONT)");
      314 +                }
      315 +
      316 +                /* middle calls get both in, out */
      317 +                err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb);
      318 +                if (err) {
      319 +                        DPRINT("smb__ssnsetup, ssp next, err=%d", err);
      320 +                        goto out;
      321 +                }
 513  322          }
 514  323  
      324 +        /*
      325 +         * Only get here via break in the err==0 case above,
      326 +         * so we're finalizing a successful session setup.
      327 +         *
      328 +         * NULL output token here indicates the final call.
      329 +         */
      330 +        (void) ssp_ctx_next_token(ctx, &recv_mb, NULL);
      331 +
      332 +        /*
      333 +         * The signing key is in ctx->ct_mackey
      334 +         * (a.k.a. ct_work.wk_iods.is_u_mackey)
      335 +         * and session key is in ctx->ct_ssn_key
      336 +         * (a.k.a. ct_work.wk_iods.is_ssn_key)
      337 +         */
      338 +
 515  339  out:
 516      -        mb_done(&blob);
      340 +        /* Done with ctx->ct_ssp_ctx */
      341 +        ssp_ctx_destroy(ctx);
 517  342  
 518      -        if (err) {
 519      -                close(ctx->ct_tran_fd);
 520      -                ctx->ct_tran_fd = -1;
 521      -        } else {
 522      -                /* Tell library code we have a session. */
 523      -                ctx->ct_flags |= SMBCF_SSNACTIVE;
 524      -                DPRINT("tran_fd = %d", ctx->ct_tran_fd);
      343 +        return (err);
      344 +}
      345 +
      346 +int smb_max_authtok_sz = 0x10000;
      347 +
      348 +/*
      349 + * Session Setup function, calling the nsmb driver.
      350 + *
      351 + * Args
      352 + *      send_mb: [in]  outgoing blob data to send
      353 + *      recv_mb: [out] received blob data buffer
      354 + */
      355 +static int
      356 +smb__ssnsetup(struct smb_ctx *ctx,
      357 +        struct mbdata *send_mb, struct mbdata *recv_mb)
      358 +{
      359 +        smbioc_ossn_t *ossn = &ctx->ct_ssn;
      360 +        smbioc_ssn_work_t *work = &ctx->ct_work;
      361 +        mbuf_t *m;
      362 +        int err;
      363 +
      364 +        /* Setup receive buffer for the auth data. */
      365 +        err = mb_init_sz(recv_mb, smb_max_authtok_sz);
      366 +        if (err != 0)
      367 +                return (err);
      368 +        m = recv_mb->mb_top;
      369 +        work->wk_u_auth_rbuf.lp_ptr = m->m_data;
      370 +        work->wk_u_auth_rlen        = m->m_maxlen;
      371 +
      372 +        /* ... and the auth data to send. */
      373 +        m = send_mb->mb_top;
      374 +        work->wk_u_auth_wbuf.lp_ptr = m->m_data;
      375 +        work->wk_u_auth_wlen        = m->m_len;
      376 +
      377 +        DPRINT("Session setup ioctl...");
      378 +        if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_SSNSETUP, work) < 0) {
      379 +                err = errno;
      380 +                if (err != 0 && err != EINPROGRESS) {
      381 +                        smb_error(dgettext(TEXT_DOMAIN,
      382 +                            "%s: session setup "),
      383 +                            err, ossn->ssn_srvname);
      384 +                }
 525  385          }
      386 +        DPRINT("Session setup ret %d", err);
 526  387  
      388 +        /* Free the auth data we sent. */
      389 +        mb_done(send_mb);
      390 +
      391 +        /* Setup length of received auth data */
      392 +        m = recv_mb->mb_top;
      393 +        m->m_len = work->wk_u_auth_rlen;
      394 +
 527  395          return (err);
 528  396  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX