1613a2f6bSGordon Ross /* 2613a2f6bSGordon Ross * CDDL HEADER START 3613a2f6bSGordon Ross * 4613a2f6bSGordon Ross * The contents of this file are subject to the terms of the 5613a2f6bSGordon Ross * Common Development and Distribution License (the "License"). 6613a2f6bSGordon Ross * You may not use this file except in compliance with the License. 7613a2f6bSGordon Ross * 8613a2f6bSGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9613a2f6bSGordon Ross * or http://www.opensolaris.org/os/licensing. 10613a2f6bSGordon Ross * See the License for the specific language governing permissions 11613a2f6bSGordon Ross * and limitations under the License. 12613a2f6bSGordon Ross * 13613a2f6bSGordon Ross * When distributing Covered Code, include this CDDL HEADER in each 14613a2f6bSGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15613a2f6bSGordon Ross * If applicable, add the following below this CDDL HEADER, with the 16613a2f6bSGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying 17613a2f6bSGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner] 18613a2f6bSGordon Ross * 19613a2f6bSGordon Ross * CDDL HEADER END 20613a2f6bSGordon Ross */ 21613a2f6bSGordon Ross 22613a2f6bSGordon Ross /* 23613a2f6bSGordon Ross * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24613a2f6bSGordon Ross * Use is subject to license terms. 25*85e6b674SGordon Ross * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 26613a2f6bSGordon Ross */ 27613a2f6bSGordon Ross 28613a2f6bSGordon Ross /* 29613a2f6bSGordon Ross * Functions to setup connections (TCP and/or NetBIOS) 30613a2f6bSGordon Ross * This has the fall-back logic for IP6, IP4, NBT 31613a2f6bSGordon Ross */ 32613a2f6bSGordon Ross 33613a2f6bSGordon Ross #include <errno.h> 34613a2f6bSGordon Ross #include <stdio.h> 35613a2f6bSGordon Ross #include <string.h> 36613a2f6bSGordon Ross #include <strings.h> 37613a2f6bSGordon Ross #include <stdlib.h> 38613a2f6bSGordon Ross #include <unistd.h> 39613a2f6bSGordon Ross #include <netdb.h> 40613a2f6bSGordon Ross #include <libintl.h> 41613a2f6bSGordon Ross #include <xti.h> 42613a2f6bSGordon Ross #include <assert.h> 43613a2f6bSGordon Ross 44613a2f6bSGordon Ross #include <sys/types.h> 45613a2f6bSGordon Ross #include <sys/time.h> 46613a2f6bSGordon Ross #include <sys/byteorder.h> 47613a2f6bSGordon Ross #include <sys/socket.h> 48613a2f6bSGordon Ross #include <sys/fcntl.h> 49613a2f6bSGordon Ross 50613a2f6bSGordon Ross #include <netinet/in.h> 51613a2f6bSGordon Ross #include <netinet/tcp.h> 52613a2f6bSGordon Ross #include <arpa/inet.h> 53613a2f6bSGordon Ross 54613a2f6bSGordon Ross #include <netsmb/smb.h> 55613a2f6bSGordon Ross #include <netsmb/smb_lib.h> 56613a2f6bSGordon Ross #include <netsmb/netbios.h> 57613a2f6bSGordon Ross #include <netsmb/nb_lib.h> 58613a2f6bSGordon Ross #include <netsmb/smb_dev.h> 59613a2f6bSGordon Ross 60613a2f6bSGordon Ross #include "charsets.h" 61613a2f6bSGordon Ross #include "private.h" 62613a2f6bSGordon Ross 63613a2f6bSGordon Ross /* 64613a2f6bSGordon Ross * SMB messages are up to 64K. 65613a2f6bSGordon Ross * Let's leave room for two. 66613a2f6bSGordon Ross */ 67613a2f6bSGordon Ross static int smb_tcpsndbuf = 0x20000; 68613a2f6bSGordon Ross static int smb_tcprcvbuf = 0x20000; 69613a2f6bSGordon Ross static int smb_connect_timeout = 30; /* seconds */ 70613a2f6bSGordon Ross int smb_recv_timeout = 30; /* seconds */ 71613a2f6bSGordon Ross 72613a2f6bSGordon Ross int conn_tcp6(struct smb_ctx *, const struct sockaddr *, int); 73613a2f6bSGordon Ross int conn_tcp4(struct smb_ctx *, const struct sockaddr *, int); 74613a2f6bSGordon Ross int conn_nbt(struct smb_ctx *, const struct sockaddr *, char *); 75613a2f6bSGordon Ross 76613a2f6bSGordon Ross /* 77613a2f6bSGordon Ross * Internal set sockopt for int-sized options. 78613a2f6bSGordon Ross * Borrowed from: libnsl/rpc/ti_opts.c 79613a2f6bSGordon Ross */ 80613a2f6bSGordon Ross static int 81613a2f6bSGordon Ross smb_setopt_int(int fd, int level, int name, int val) 82613a2f6bSGordon Ross { 83613a2f6bSGordon Ross struct t_optmgmt oreq, ores; 84613a2f6bSGordon Ross struct { 85613a2f6bSGordon Ross struct t_opthdr oh; 86613a2f6bSGordon Ross int ival; 87613a2f6bSGordon Ross } opts; 88613a2f6bSGordon Ross 89613a2f6bSGordon Ross /* opt header */ 90613a2f6bSGordon Ross opts.oh.len = sizeof (opts); 91613a2f6bSGordon Ross opts.oh.level = level; 92613a2f6bSGordon Ross opts.oh.name = name; 93613a2f6bSGordon Ross opts.oh.status = 0; 94613a2f6bSGordon Ross opts.ival = val; 95613a2f6bSGordon Ross 96613a2f6bSGordon Ross oreq.flags = T_NEGOTIATE; 97613a2f6bSGordon Ross oreq.opt.buf = (void *)&opts; 98613a2f6bSGordon Ross oreq.opt.len = sizeof (opts); 99613a2f6bSGordon Ross 100613a2f6bSGordon Ross ores.flags = 0; 101613a2f6bSGordon Ross ores.opt.buf = NULL; 102613a2f6bSGordon Ross ores.opt.maxlen = 0; 103613a2f6bSGordon Ross 104613a2f6bSGordon Ross if (t_optmgmt(fd, &oreq, &ores) < 0) { 105613a2f6bSGordon Ross DPRINT("t_opgmgnt, t_errno = %d", t_errno); 106613a2f6bSGordon Ross if (t_errno == TSYSERR) 107613a2f6bSGordon Ross return (errno); 108613a2f6bSGordon Ross return (EPROTO); 109613a2f6bSGordon Ross } 110613a2f6bSGordon Ross if (ores.flags != T_SUCCESS) { 111613a2f6bSGordon Ross DPRINT("flags 0x%x, status 0x%x", 112613a2f6bSGordon Ross (int)ores.flags, (int)opts.oh.status); 113613a2f6bSGordon Ross return (EPROTO); 114613a2f6bSGordon Ross } 115613a2f6bSGordon Ross 116613a2f6bSGordon Ross return (0); 117613a2f6bSGordon Ross } 118613a2f6bSGordon Ross 119613a2f6bSGordon Ross static int 120613a2f6bSGordon Ross smb_setopts(int fd) 121613a2f6bSGordon Ross { 122613a2f6bSGordon Ross int err; 123613a2f6bSGordon Ross 124613a2f6bSGordon Ross /* 125613a2f6bSGordon Ross * Set various socket/TCP options. 126613a2f6bSGordon Ross * Failures here are not fatal - 127613a2f6bSGordon Ross * just log a complaint. 128613a2f6bSGordon Ross * 129613a2f6bSGordon Ross * We don't need these two: 130613a2f6bSGordon Ross * SO_RCVTIMEO, SO_SNDTIMEO 131613a2f6bSGordon Ross */ 132613a2f6bSGordon Ross 133613a2f6bSGordon Ross err = smb_setopt_int(fd, SOL_SOCKET, SO_SNDBUF, smb_tcpsndbuf); 134613a2f6bSGordon Ross if (err) { 135613a2f6bSGordon Ross DPRINT("set SO_SNDBUF, err %d", err); 136613a2f6bSGordon Ross } 137613a2f6bSGordon Ross 138613a2f6bSGordon Ross err = smb_setopt_int(fd, SOL_SOCKET, SO_RCVBUF, smb_tcprcvbuf); 139613a2f6bSGordon Ross if (err) { 140613a2f6bSGordon Ross DPRINT("set SO_RCVBUF, err %d", err); 141613a2f6bSGordon Ross } 142613a2f6bSGordon Ross 143613a2f6bSGordon Ross err = smb_setopt_int(fd, SOL_SOCKET, SO_KEEPALIVE, 1); 144613a2f6bSGordon Ross if (err) { 145613a2f6bSGordon Ross DPRINT("set SO_KEEPALIVE, err %d", err); 146613a2f6bSGordon Ross } 147613a2f6bSGordon Ross 148613a2f6bSGordon Ross err = smb_setopt_int(fd, IPPROTO_TCP, TCP_NODELAY, 1); 149613a2f6bSGordon Ross if (err) { 150613a2f6bSGordon Ross DPRINT("set TCP_NODELAY, err %d", err); 151613a2f6bSGordon Ross } 152613a2f6bSGordon Ross 153613a2f6bSGordon Ross /* Set the connect timeout (in milliseconds). */ 154613a2f6bSGordon Ross err = smb_setopt_int(fd, IPPROTO_TCP, 155613a2f6bSGordon Ross TCP_CONN_ABORT_THRESHOLD, 156613a2f6bSGordon Ross smb_connect_timeout * 1000); 157613a2f6bSGordon Ross if (err) { 158613a2f6bSGordon Ross DPRINT("set connect timeout, err %d", err); 159613a2f6bSGordon Ross } 160613a2f6bSGordon Ross return (0); 161613a2f6bSGordon Ross } 162613a2f6bSGordon Ross 163613a2f6bSGordon Ross 164613a2f6bSGordon Ross int 165613a2f6bSGordon Ross conn_tcp6(struct smb_ctx *ctx, const struct sockaddr *sa, int port) 166613a2f6bSGordon Ross { 167613a2f6bSGordon Ross struct sockaddr_in6 sin6; 168613a2f6bSGordon Ross char *dev = "/dev/tcp6"; 169613a2f6bSGordon Ross char paddrbuf[INET6_ADDRSTRLEN]; 170613a2f6bSGordon Ross struct t_call sndcall; 171613a2f6bSGordon Ross int fd, err; 172613a2f6bSGordon Ross 173613a2f6bSGordon Ross if (sa->sa_family != AF_INET6) { 174613a2f6bSGordon Ross DPRINT("bad af %d", sa->sa_family); 175613a2f6bSGordon Ross return (EINVAL); 176613a2f6bSGordon Ross } 177613a2f6bSGordon Ross bcopy(sa, &sin6, sizeof (sin6)); 178613a2f6bSGordon Ross sin6.sin6_port = htons(port); 179613a2f6bSGordon Ross 180613a2f6bSGordon Ross DPRINT("tcp6: %s (%d)", 181613a2f6bSGordon Ross inet_ntop(AF_INET6, &sin6.sin6_addr, 182613a2f6bSGordon Ross paddrbuf, sizeof (paddrbuf)), port); 183613a2f6bSGordon Ross 184613a2f6bSGordon Ross fd = t_open(dev, O_RDWR, NULL); 185613a2f6bSGordon Ross if (fd < 0) { 186613a2f6bSGordon Ross /* Assume t_errno = TSYSERR */ 187613a2f6bSGordon Ross err = errno; 188613a2f6bSGordon Ross perror(dev); 189613a2f6bSGordon Ross return (err); 190613a2f6bSGordon Ross } 191613a2f6bSGordon Ross if ((err = smb_setopts(fd)) != 0) 192613a2f6bSGordon Ross goto errout; 193613a2f6bSGordon Ross if (t_bind(fd, NULL, NULL) < 0) { 194613a2f6bSGordon Ross DPRINT("t_bind t_errno %d", t_errno); 195613a2f6bSGordon Ross if (t_errno == TSYSERR) 196613a2f6bSGordon Ross err = errno; 197613a2f6bSGordon Ross else 198613a2f6bSGordon Ross err = EPROTO; 199613a2f6bSGordon Ross goto errout; 200613a2f6bSGordon Ross } 201613a2f6bSGordon Ross sndcall.addr.maxlen = sizeof (sin6); 202613a2f6bSGordon Ross sndcall.addr.len = sizeof (sin6); 203613a2f6bSGordon Ross sndcall.addr.buf = (void *) &sin6; 204613a2f6bSGordon Ross sndcall.opt.len = 0; 205613a2f6bSGordon Ross sndcall.udata.len = 0; 206613a2f6bSGordon Ross if (t_connect(fd, &sndcall, NULL) < 0) { 207613a2f6bSGordon Ross err = get_xti_err(fd); 208613a2f6bSGordon Ross DPRINT("connect, err %d", err); 209613a2f6bSGordon Ross goto errout; 210613a2f6bSGordon Ross } 211613a2f6bSGordon Ross 212613a2f6bSGordon Ross DPRINT("tcp6: connected, fd=%d", fd); 213613a2f6bSGordon Ross ctx->ct_tran_fd = fd; 214613a2f6bSGordon Ross return (0); 215613a2f6bSGordon Ross 216613a2f6bSGordon Ross errout: 217613a2f6bSGordon Ross close(fd); 218613a2f6bSGordon Ross return (err); 219613a2f6bSGordon Ross } 220613a2f6bSGordon Ross 221613a2f6bSGordon Ross /* 222613a2f6bSGordon Ross * This is used for both SMB over TCP (port 445) 223613a2f6bSGordon Ross * and NetBIOS - see conn_nbt(). 224613a2f6bSGordon Ross */ 225613a2f6bSGordon Ross int 226613a2f6bSGordon Ross conn_tcp4(struct smb_ctx *ctx, const struct sockaddr *sa, int port) 227613a2f6bSGordon Ross { 228613a2f6bSGordon Ross struct sockaddr_in sin; 229613a2f6bSGordon Ross char *dev = "/dev/tcp"; 230613a2f6bSGordon Ross char paddrbuf[INET_ADDRSTRLEN]; 231613a2f6bSGordon Ross struct t_call sndcall; 232613a2f6bSGordon Ross int fd, err; 233613a2f6bSGordon Ross 234613a2f6bSGordon Ross if (sa->sa_family != AF_INET) { 235613a2f6bSGordon Ross DPRINT("bad af %d", sa->sa_family); 236613a2f6bSGordon Ross return (EINVAL); 237613a2f6bSGordon Ross } 238613a2f6bSGordon Ross bcopy(sa, &sin, sizeof (sin)); 239613a2f6bSGordon Ross sin.sin_port = htons(port); 240613a2f6bSGordon Ross 241613a2f6bSGordon Ross DPRINT("tcp4: %s (%d)", 242613a2f6bSGordon Ross inet_ntop(AF_INET, &sin.sin_addr, 243613a2f6bSGordon Ross paddrbuf, sizeof (paddrbuf)), port); 244613a2f6bSGordon Ross 245613a2f6bSGordon Ross fd = t_open(dev, O_RDWR, NULL); 246613a2f6bSGordon Ross if (fd < 0) { 247613a2f6bSGordon Ross /* Assume t_errno = TSYSERR */ 248613a2f6bSGordon Ross err = errno; 249613a2f6bSGordon Ross perror(dev); 250613a2f6bSGordon Ross return (err); 251613a2f6bSGordon Ross } 252613a2f6bSGordon Ross if ((err = smb_setopts(fd)) != 0) 253613a2f6bSGordon Ross goto errout; 254613a2f6bSGordon Ross if (t_bind(fd, NULL, NULL) < 0) { 255613a2f6bSGordon Ross DPRINT("t_bind t_errno %d", t_errno); 256613a2f6bSGordon Ross if (t_errno == TSYSERR) 257613a2f6bSGordon Ross err = errno; 258613a2f6bSGordon Ross else 259613a2f6bSGordon Ross err = EPROTO; 260613a2f6bSGordon Ross goto errout; 261613a2f6bSGordon Ross } 262613a2f6bSGordon Ross sndcall.addr.maxlen = sizeof (sin); 263613a2f6bSGordon Ross sndcall.addr.len = sizeof (sin); 264613a2f6bSGordon Ross sndcall.addr.buf = (void *) &sin; 265613a2f6bSGordon Ross sndcall.opt.len = 0; 266613a2f6bSGordon Ross sndcall.udata.len = 0; 267613a2f6bSGordon Ross if (t_connect(fd, &sndcall, NULL) < 0) { 268613a2f6bSGordon Ross err = get_xti_err(fd); 269613a2f6bSGordon Ross DPRINT("connect, err %d", err); 270613a2f6bSGordon Ross goto errout; 271613a2f6bSGordon Ross } 272613a2f6bSGordon Ross 273613a2f6bSGordon Ross DPRINT("tcp4: connected, fd=%d", fd); 274613a2f6bSGordon Ross ctx->ct_tran_fd = fd; 275613a2f6bSGordon Ross return (0); 276613a2f6bSGordon Ross 277613a2f6bSGordon Ross errout: 278613a2f6bSGordon Ross close(fd); 279613a2f6bSGordon Ross return (err); 280613a2f6bSGordon Ross } 281613a2f6bSGordon Ross 282613a2f6bSGordon Ross /* 283613a2f6bSGordon Ross * Open a NetBIOS connection (session, port 139) 284613a2f6bSGordon Ross * 285613a2f6bSGordon Ross * The optional name parameter, if passed, means 286613a2f6bSGordon Ross * we found the sockaddr via NetBIOS name lookup, 287613a2f6bSGordon Ross * and can just use that for our session request. 288613a2f6bSGordon Ross * Otherwise (if name is NULL), we're connecting 289613a2f6bSGordon Ross * by IP address, and need to come up with the 290613a2f6bSGordon Ross * NetBIOS name by other means. 291613a2f6bSGordon Ross */ 292613a2f6bSGordon Ross int 293613a2f6bSGordon Ross conn_nbt(struct smb_ctx *ctx, const struct sockaddr *saarg, char *name) 294613a2f6bSGordon Ross { 295613a2f6bSGordon Ross struct sockaddr_in sin; 296613a2f6bSGordon Ross struct sockaddr *sa; 297613a2f6bSGordon Ross char server[NB_NAMELEN]; 298613a2f6bSGordon Ross char workgroup[NB_NAMELEN]; 299613a2f6bSGordon Ross int err, nberr, port; 300613a2f6bSGordon Ross 301613a2f6bSGordon Ross bcopy(saarg, &sin, sizeof (sin)); 302613a2f6bSGordon Ross sa = (struct sockaddr *)&sin; 303613a2f6bSGordon Ross 304613a2f6bSGordon Ross switch (sin.sin_family) { 305613a2f6bSGordon Ross case AF_NETBIOS: /* our fake AF */ 306613a2f6bSGordon Ross sin.sin_family = AF_INET; 307613a2f6bSGordon Ross break; 308613a2f6bSGordon Ross case AF_INET: 309613a2f6bSGordon Ross break; 310613a2f6bSGordon Ross default: 311613a2f6bSGordon Ross DPRINT("bad af %d", sin.sin_family); 312613a2f6bSGordon Ross return (EINVAL); 313613a2f6bSGordon Ross } 314613a2f6bSGordon Ross port = IPPORT_NETBIOS_SSN; 315613a2f6bSGordon Ross 316613a2f6bSGordon Ross /* 317613a2f6bSGordon Ross * If we have a NetBIOS name, just use it. 318613a2f6bSGordon Ross * This is the path taken when we've done a 319613a2f6bSGordon Ross * NetBIOS name lookup on this name to get 320613a2f6bSGordon Ross * the IP address in the passed sa. Otherwise, 321613a2f6bSGordon Ross * we're connecting by IP address, and need to 322613a2f6bSGordon Ross * figure out what NetBIOS name to use. 323613a2f6bSGordon Ross */ 324613a2f6bSGordon Ross if (name) { 325613a2f6bSGordon Ross strlcpy(server, name, sizeof (server)); 326613a2f6bSGordon Ross DPRINT("given name: %s", server); 327613a2f6bSGordon Ross } else { 328613a2f6bSGordon Ross /* 329613a2f6bSGordon Ross * 330613a2f6bSGordon Ross * Try a NetBIOS node status query, 331613a2f6bSGordon Ross * which searches for a type=[20] name. 332613a2f6bSGordon Ross * If that doesn't work, just use the 333613a2f6bSGordon Ross * (fake) "*SMBSERVER" name. 334613a2f6bSGordon Ross */ 335613a2f6bSGordon Ross DPRINT("try node status"); 336613a2f6bSGordon Ross server[0] = '\0'; 337613a2f6bSGordon Ross nberr = nbns_getnodestatus(ctx->ct_nb, 338613a2f6bSGordon Ross &sin.sin_addr, server, workgroup); 339613a2f6bSGordon Ross if (nberr == 0 && server[0] != '\0') { 340613a2f6bSGordon Ross /* Found the name. Save for reconnect. */ 341613a2f6bSGordon Ross DPRINT("found name: %s", server); 342613a2f6bSGordon Ross strlcpy(ctx->ct_srvname, server, 343613a2f6bSGordon Ross sizeof (ctx->ct_srvname)); 344613a2f6bSGordon Ross } else { 345613a2f6bSGordon Ross DPRINT("getnodestatus, nberr %d", nberr); 346613a2f6bSGordon Ross strlcpy(server, "*SMBSERVER", sizeof (server)); 347613a2f6bSGordon Ross } 348613a2f6bSGordon Ross } 349613a2f6bSGordon Ross 350613a2f6bSGordon Ross /* 351613a2f6bSGordon Ross * Establish the TCP connection. 352613a2f6bSGordon Ross * Careful to close it on errors. 353613a2f6bSGordon Ross */ 354613a2f6bSGordon Ross if ((err = conn_tcp4(ctx, sa, port)) != 0) { 355613a2f6bSGordon Ross DPRINT("TCP connect: err=%d", err); 356613a2f6bSGordon Ross goto out; 357613a2f6bSGordon Ross } 358613a2f6bSGordon Ross 359613a2f6bSGordon Ross /* Connected. Do NetBIOS session request. */ 360613a2f6bSGordon Ross err = nb_ssn_request(ctx, server); 361613a2f6bSGordon Ross if (err) 362613a2f6bSGordon Ross DPRINT("ssn_rq, err %d", err); 363613a2f6bSGordon Ross 364613a2f6bSGordon Ross out: 365613a2f6bSGordon Ross if (err) { 366613a2f6bSGordon Ross if (ctx->ct_tran_fd != -1) { 367613a2f6bSGordon Ross close(ctx->ct_tran_fd); 368613a2f6bSGordon Ross ctx->ct_tran_fd = -1; 369613a2f6bSGordon Ross } 370613a2f6bSGordon Ross } 371613a2f6bSGordon Ross return (err); 372613a2f6bSGordon Ross } 373613a2f6bSGordon Ross 374613a2f6bSGordon Ross /* 375613a2f6bSGordon Ross * Make a new connection, or reconnect. 376613a2f6bSGordon Ross */ 377613a2f6bSGordon Ross int 378613a2f6bSGordon Ross smb_iod_connect(smb_ctx_t *ctx) 379613a2f6bSGordon Ross { 380613a2f6bSGordon Ross struct sockaddr *sa; 381613a2f6bSGordon Ross int err, err2; 382613a2f6bSGordon Ross struct mbdata blob; 383613a2f6bSGordon Ross 384613a2f6bSGordon Ross memset(&blob, 0, sizeof (blob)); 385613a2f6bSGordon Ross 386613a2f6bSGordon Ross if (ctx->ct_srvname[0] == '\0') { 387613a2f6bSGordon Ross DPRINT("sername not set!"); 388613a2f6bSGordon Ross return (EINVAL); 389613a2f6bSGordon Ross } 390613a2f6bSGordon Ross DPRINT("server: %s", ctx->ct_srvname); 391613a2f6bSGordon Ross 392613a2f6bSGordon Ross if (smb_debug) 393613a2f6bSGordon Ross dump_ctx("smb_iod_connect", ctx); 394613a2f6bSGordon Ross 395613a2f6bSGordon Ross /* 396613a2f6bSGordon Ross * This may be a reconnect, so 397613a2f6bSGordon Ross * cleanup if necessary. 398613a2f6bSGordon Ross */ 399613a2f6bSGordon Ross if (ctx->ct_tran_fd != -1) { 400613a2f6bSGordon Ross close(ctx->ct_tran_fd); 401613a2f6bSGordon Ross ctx->ct_tran_fd = -1; 402613a2f6bSGordon Ross } 403613a2f6bSGordon Ross 404613a2f6bSGordon Ross /* 405613a2f6bSGordon Ross * Get local machine name. 406613a2f6bSGordon Ross * Full name - not a NetBIOS name. 407613a2f6bSGordon Ross */ 408613a2f6bSGordon Ross if (ctx->ct_locname == NULL) { 409613a2f6bSGordon Ross err = smb_getlocalname(&ctx->ct_locname); 410613a2f6bSGordon Ross if (err) { 411613a2f6bSGordon Ross smb_error(dgettext(TEXT_DOMAIN, 412613a2f6bSGordon Ross "can't get local name"), err); 413613a2f6bSGordon Ross return (err); 414613a2f6bSGordon Ross } 415613a2f6bSGordon Ross } 416613a2f6bSGordon Ross 417613a2f6bSGordon Ross /* 418613a2f6bSGordon Ross * We're called with each IP address 419613a2f6bSGordon Ross * already copied into ct_srvaddr. 420613a2f6bSGordon Ross */ 421613a2f6bSGordon Ross ctx->ct_flags |= SMBCF_RESOLVED; 422613a2f6bSGordon Ross 423613a2f6bSGordon Ross sa = &ctx->ct_srvaddr.sa; 424613a2f6bSGordon Ross switch (sa->sa_family) { 425613a2f6bSGordon Ross 426613a2f6bSGordon Ross case AF_INET6: 427613a2f6bSGordon Ross err = conn_tcp6(ctx, sa, IPPORT_SMB); 428613a2f6bSGordon Ross break; 429613a2f6bSGordon Ross 430613a2f6bSGordon Ross case AF_INET: 431613a2f6bSGordon Ross err = conn_tcp4(ctx, sa, IPPORT_SMB); 432613a2f6bSGordon Ross /* 433613a2f6bSGordon Ross * If port 445 was not listening, try port 139. 434613a2f6bSGordon Ross * Note: Not doing NetBIOS name lookup here. 435613a2f6bSGordon Ross * We already have the IP address. 436613a2f6bSGordon Ross */ 437613a2f6bSGordon Ross switch (err) { 438613a2f6bSGordon Ross case ECONNRESET: 439613a2f6bSGordon Ross case ECONNREFUSED: 440613a2f6bSGordon Ross err2 = conn_nbt(ctx, sa, NULL); 441613a2f6bSGordon Ross if (err2 == 0) 442613a2f6bSGordon Ross err = 0; 443613a2f6bSGordon Ross } 444613a2f6bSGordon Ross break; 445613a2f6bSGordon Ross 446613a2f6bSGordon Ross case AF_NETBIOS: 447613a2f6bSGordon Ross /* Like AF_INET, but use NetBIOS ssn. */ 448613a2f6bSGordon Ross err = conn_nbt(ctx, sa, ctx->ct_srvname); 449613a2f6bSGordon Ross break; 450613a2f6bSGordon Ross 451613a2f6bSGordon Ross default: 452613a2f6bSGordon Ross DPRINT("skipped family %d", sa->sa_family); 453613a2f6bSGordon Ross err = EPROTONOSUPPORT; 454613a2f6bSGordon Ross break; 455613a2f6bSGordon Ross } 456613a2f6bSGordon Ross 457613a2f6bSGordon Ross 458613a2f6bSGordon Ross if (err) { 459613a2f6bSGordon Ross DPRINT("connect, err=%d", err); 460613a2f6bSGordon Ross return (err); 461613a2f6bSGordon Ross } 462613a2f6bSGordon Ross 463613a2f6bSGordon Ross /* 464613a2f6bSGordon Ross * Do SMB Negotiate Protocol. 465613a2f6bSGordon Ross */ 466613a2f6bSGordon Ross err = smb_negprot(ctx, &blob); 467613a2f6bSGordon Ross if (err) 468613a2f6bSGordon Ross goto out; 469613a2f6bSGordon Ross 470613a2f6bSGordon Ross /* 471*85e6b674SGordon Ross * Empty user name means an explicit request for 472*85e6b674SGordon Ross * NULL session setup, which is a special case. 473*85e6b674SGordon Ross * If negotiate determined that we want to do 474*85e6b674SGordon Ross * SMB signing, we have to turn that off for a 475*85e6b674SGordon Ross * NULL session. [MS-SMB 3.3.5.3]. 476*85e6b674SGordon Ross */ 477*85e6b674SGordon Ross if (ctx->ct_user[0] == '\0') { 478*85e6b674SGordon Ross /* Null user should have null domain too. */ 479*85e6b674SGordon Ross ctx->ct_domain[0] = '\0'; 480*85e6b674SGordon Ross ctx->ct_authflags = SMB_AT_ANON; 481*85e6b674SGordon Ross ctx->ct_clnt_caps &= ~SMB_CAP_EXT_SECURITY; 482*85e6b674SGordon Ross ctx->ct_vcflags &= ~SMBV_WILL_SIGN; 483*85e6b674SGordon Ross } 484*85e6b674SGordon Ross 485*85e6b674SGordon Ross /* 486613a2f6bSGordon Ross * Do SMB Session Setup (authenticate) 487613a2f6bSGordon Ross * 488613a2f6bSGordon Ross * If the server negotiated extended security, 489*85e6b674SGordon Ross * run the SPNEGO state machine, otherwise do 490*85e6b674SGordon Ross * one of the old-style variants. 491613a2f6bSGordon Ross */ 492*85e6b674SGordon Ross if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) { 493613a2f6bSGordon Ross err = smb_ssnsetup_spnego(ctx, &blob); 494613a2f6bSGordon Ross } else { 495613a2f6bSGordon Ross /* 496613a2f6bSGordon Ross * Server did NOT negotiate extended security. 497*85e6b674SGordon Ross * Try NTLMv2, NTLMv1, or ANON (if enabled). 498613a2f6bSGordon Ross */ 499*85e6b674SGordon Ross if (ctx->ct_authflags & SMB_AT_NTLM2) { 500*85e6b674SGordon Ross err = smb_ssnsetup_ntlm2(ctx); 501*85e6b674SGordon Ross } else if (ctx->ct_authflags & SMB_AT_NTLM1) { 502*85e6b674SGordon Ross err = smb_ssnsetup_ntlm1(ctx); 503*85e6b674SGordon Ross } else if (ctx->ct_authflags & SMB_AT_ANON) { 504*85e6b674SGordon Ross err = smb_ssnsetup_null(ctx); 505*85e6b674SGordon Ross } else { 506613a2f6bSGordon Ross /* 507*85e6b674SGordon Ross * Don't return EAUTH, because a new 508*85e6b674SGordon Ross * password prompt will not help. 509613a2f6bSGordon Ross */ 510613a2f6bSGordon Ross DPRINT("No NTLM authflags"); 511613a2f6bSGordon Ross err = ENOTSUP; 512613a2f6bSGordon Ross } 513613a2f6bSGordon Ross } 514613a2f6bSGordon Ross 515613a2f6bSGordon Ross out: 516613a2f6bSGordon Ross mb_done(&blob); 517613a2f6bSGordon Ross 518613a2f6bSGordon Ross if (err) { 519613a2f6bSGordon Ross close(ctx->ct_tran_fd); 520613a2f6bSGordon Ross ctx->ct_tran_fd = -1; 521*85e6b674SGordon Ross } else { 522*85e6b674SGordon Ross /* Tell library code we have a session. */ 523*85e6b674SGordon Ross ctx->ct_flags |= SMBCF_SSNACTIVE; 524613a2f6bSGordon Ross DPRINT("tran_fd = %d", ctx->ct_tran_fd); 525*85e6b674SGordon Ross } 526613a2f6bSGordon Ross 527613a2f6bSGordon Ross return (err); 528613a2f6bSGordon Ross } 529