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


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.

  26  */
  27 
  28 /*
  29  * Functions to setup connections (TCP and/or NetBIOS)
  30  * This has the fall-back logic for IP6, IP4, NBT
  31  */
  32 
  33 #include <errno.h>
  34 #include <stdio.h>
  35 #include <string.h>
  36 #include <strings.h>
  37 #include <stdlib.h>
  38 #include <unistd.h>
  39 #include <netdb.h>
  40 #include <libintl.h>
  41 #include <xti.h>
  42 #include <assert.h>
  43 
  44 #include <sys/types.h>
  45 #include <sys/time.h>
  46 #include <sys/byteorder.h>
  47 #include <sys/socket.h>
  48 #include <sys/fcntl.h>
  49 
  50 #include <netinet/in.h>
  51 #include <netinet/tcp.h>
  52 #include <arpa/inet.h>

  53 
  54 #include <netsmb/smb.h>
  55 #include <netsmb/smb_lib.h>

  56 #include <netsmb/netbios.h>
  57 #include <netsmb/nb_lib.h>
  58 #include <netsmb/smb_dev.h>
  59 


  60 #include "charsets.h"
  61 #include "private.h"

  62 
  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 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;
  88 
  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;
  95 
  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)
 121 {
 122         int err;
 123 
 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;
 307                 break;
 308         case AF_INET:
 309                 break;
 310         default:
 311                 DPRINT("bad af %d", sin.sin_family);
 312                 return (EINVAL);
 313         }
 314         port = IPPORT_NETBIOS_SSN;
 315 
 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);
 372 }
 373 
 374 /*
 375  * Make a new connection, or reconnect.




 376  */
 377 int
 378 smb_iod_connect(smb_ctx_t *ctx)
 379 {
 380         struct sockaddr *sa;
 381         int err, err2;
 382         struct mbdata blob;
 383 
 384         memset(&blob, 0, sizeof (blob));

 385 
 386         if (ctx->ct_srvname[0] == '\0') {
 387                 DPRINT("sername not set!");
 388                 return (EINVAL);






 389         }
 390         DPRINT("server: %s", ctx->ct_srvname);



 391 
 392         if (smb_debug)
 393                 dump_ctx("smb_iod_connect", ctx);
 394 
 395         /*
 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          * Get local machine name.
 406          * Full name - not a NetBIOS name.
 407          */
 408         if (ctx->ct_locname == NULL) {
 409                 err = smb_getlocalname(&ctx->ct_locname);
 410                 if (err) {
 411                         smb_error(dgettext(TEXT_DOMAIN,
 412                             "can't get local name"), err);
 413                         return (err);
 414                 }

 415         }
 416 
 417         /*
 418          * We're called with each IP address
 419          * already copied into ct_srvaddr.

 420          */
 421         ctx->ct_flags |= SMBCF_RESOLVED;
 422 
 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);
 460                 return (err);
 461         }

 462 
 463         /*
 464          * Do SMB Negotiate Protocol.



 465          */
 466         err = smb_negprot(ctx, &blob);
 467         if (err)
 468                 goto out;
 469 
 470         /*
 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].
 476          */
 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;
 483         }
 484 
 485         /*
 486          * 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.
 491          */
 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 {
 506                         /*
 507                          * Don't return EAUTH, because a new
 508                          * password prompt will not help.
 509                          */
 510                         DPRINT("No NTLM authflags");
 511                         err = ENOTSUP;









 512                 }
 513         }

 514 
 515 out:
 516         mb_done(&blob);
 517 
 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);
 525         }
 526 
 527         return (err);
 528 }


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  *
  26  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  27  */
  28 
  29 /*
  30  * Functions to setup connections (TCP and/or NetBIOS)
  31  * This has the fall-back logic for IP6, IP4, NBT
  32  */
  33 
  34 #include <errno.h>
  35 #include <stdio.h>
  36 #include <string.h>
  37 #include <strings.h>
  38 #include <stdlib.h>
  39 #include <unistd.h>
  40 #include <netdb.h>
  41 #include <libintl.h>
  42 #include <xti.h>
  43 #include <assert.h>
  44 
  45 #include <sys/types.h>
  46 #include <sys/time.h>
  47 #include <sys/byteorder.h>
  48 #include <sys/socket.h>
  49 #include <sys/fcntl.h>
  50 
  51 #include <netinet/in.h>
  52 #include <netinet/tcp.h>
  53 #include <arpa/inet.h>
  54 #include <uuid/uuid.h>
  55 
  56 #include <netsmb/smb.h>
  57 #include <netsmb/smb_lib.h>
  58 #include <netsmb/mchain.h>
  59 #include <netsmb/netbios.h>
  60 #include <netsmb/nb_lib.h>
  61 #include <netsmb/smb_dev.h>
  62 
  63 #include <cflib.h>
  64 
  65 #include "charsets.h"
  66 #include "private.h"
  67 #include "smb_crypt.h"
  68 
  69 static int
  70 smb__ssnsetup(struct smb_ctx *ctx,
  71         struct mbdata *mbc1, struct mbdata *mbc2);





  72 
  73 int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *);


  74 
  75 const char *
  76 smb_iod_state_name(enum smbiod_state st)




  77 {
  78         const char *n = "(?)";




  79 
  80         switch (st) {
  81         case SMBIOD_ST_UNINIT:
  82                 n = "UNINIT!";
  83                 break;
  84         case SMBIOD_ST_IDLE:
  85                 n = "IDLE";
  86                 break;
  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;
 114         }





 115 
 116         return (n);
 117 }
 118 
 119 /*
 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).
 126  */
































 127 int
 128 smb_iod_connect(smb_ctx_t *ctx)
 129 {
 130         smbioc_ossn_t *ossn = &ctx->ct_ssn;
 131         smbioc_ssn_work_t *work = &ctx->ct_work;
 132         char *uuid_str;
 133         int err;
 134         struct mbdata blob;
 135         char *nego_buf = NULL;
 136         uint32_t nego_len;
 137 
 138         memset(&blob, 0, sizeof (blob));
 139 
 140         if (ctx->ct_srvname[0] == '\0') {
 141                 DPRINT("sername not set!");
 142                 return (EINVAL);
 143         }
 144         DPRINT("server: %s", ctx->ct_srvname);

 145 
 146         if (smb_debug)
 147                 dump_ctx("smb_iod_connect", ctx);

 148 
 149         /*
 150          * Get local machine name.
 151          * Full name - not a NetBIOS name.
 152          */
 153         if (ctx->ct_locname == NULL) {
 154                 err = smb_getlocalname(&ctx->ct_locname);
 155                 if (err) {
 156                         smb_error(dgettext(TEXT_DOMAIN,
 157                             "can't get local name"), err);
 158                         return (err);
 159                 }









 160         }










 161 
 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         /*
 177          * We're called with each IP address
 178          * already copied into ct_srvaddr.
 179          */
 180         ctx->ct_flags |= SMBCF_RESOLVED;







 181 
 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);
 191                 return (err);
 192         }
 193         DPRINT("Connect OK, new state=%s",
 194             smb_iod_state_name(work->wk_out_state));


















 195 
 196         /*
 197          * Setup a buffer to recv the nego. hint.
 198          */
 199         nego_len = 4096;
 200         err = mb_init_sz(&blob, nego_len);
 201         if (err)
 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;
 206 
 207         /*
 208          * Ask the driver for SMB negotiate












 209          */
 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;
 217         }
 218         DPRINT("Negotiate OK, new state=%s",
 219             smb_iod_state_name(work->wk_out_state));
 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 
 229         /*
 230          * Do SMB Session Setup (authenticate)
 231          * Always "extended security" now (SPNEGO)




 232          */
 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) {


 286                         /*
 287                          * Session setup complete w/ success.
 288                          * Should have state AUTHOK
 289                          */
 290                         if (work->wk_out_state != SMBIOD_ST_AUTHOK) {
 291                                 DPRINT("Wrong state (expected AUTHOK)");

 292                         }
 293                         break;
 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                 }
 322         }
 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 
 339 out:
 340         /* Done with ctx->ct_ssp_ctx */
 341         ssp_ctx_destroy(ctx);
 342 
 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                 }
 385         }
 386         DPRINT("Session setup ret %d", err);
 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 
 395         return (err);
 396 }