xref: /titanic_44/usr/src/lib/libsmbfs/smb/connect.c (revision 85e6b6747d07050e01ec91acef2453655821f9ab)
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
smb_setopt_int(int fd,int level,int name,int val)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
smb_setopts(int fd)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
conn_tcp6(struct smb_ctx * ctx,const struct sockaddr * sa,int port)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
conn_tcp4(struct smb_ctx * ctx,const struct sockaddr * sa,int port)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
conn_nbt(struct smb_ctx * ctx,const struct sockaddr * saarg,char * name)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
smb_iod_connect(smb_ctx_t * ctx)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