1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   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 }