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.
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.
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]
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.
29 * Functions to setup connections (TCP and/or NetBIOS)
30 * This has the fall-back logic for IP6, IP4, NBT
44 #include <sys/types.h>
46 #include <sys/byteorder.h>
47 #include <sys/socket.h>
48 #include <sys/fcntl.h>
50 #include <netinet/in.h>
51 #include <netinet/tcp.h>
52 #include <arpa/inet.h>
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>
64 * SMB messages are up to 64K.
65 * Let's leave room for two.
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 */
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 *);
77 * Internal set sockopt for int-sized options.
78 * Borrowed from: libnsl/rpc/ti_opts.c
81 smb_setopt_int(int fd
, int level
, int name
, int val
)
83 struct t_optmgmt oreq
, ores
;
90 opts
.oh
.len
= sizeof (opts
);
91 opts
.oh
.level
= level
;
96 oreq
.flags
= T_NEGOTIATE
;
97 oreq
.opt
.buf
= (void *)&opts
;
98 oreq
.opt
.len
= sizeof (opts
);
104 if (t_optmgmt(fd
, &oreq
, &ores
) < 0) {
105 DPRINT("t_opgmgnt, t_errno = %d", t_errno
);
106 if (t_errno
== TSYSERR
)
110 if (ores
.flags
!= T_SUCCESS
) {
111 DPRINT("flags 0x%x, status 0x%x",
112 (int)ores
.flags
, (int)opts
.oh
.status
);
125 * Set various socket/TCP options.
126 * Failures here are not fatal -
127 * just log a complaint.
129 * We don't need these two:
130 * SO_RCVTIMEO, SO_SNDTIMEO
133 err
= smb_setopt_int(fd
, SOL_SOCKET
, SO_SNDBUF
, smb_tcpsndbuf
);
135 DPRINT("set SO_SNDBUF, err %d", err
);
138 err
= smb_setopt_int(fd
, SOL_SOCKET
, SO_RCVBUF
, smb_tcprcvbuf
);
140 DPRINT("set SO_RCVBUF, err %d", err
);
143 err
= smb_setopt_int(fd
, SOL_SOCKET
, SO_KEEPALIVE
, 1);
145 DPRINT("set SO_KEEPALIVE, err %d", err
);
148 err
= smb_setopt_int(fd
, IPPROTO_TCP
, TCP_NODELAY
, 1);
150 DPRINT("set TCP_NODELAY, err %d", err
);
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);
158 DPRINT("set connect timeout, err %d", err
);
165 conn_tcp6(struct smb_ctx
*ctx
, const struct sockaddr
*sa
, int port
)
167 struct sockaddr_in6 sin6
;
168 char *dev
= "/dev/tcp6";
169 char paddrbuf
[INET6_ADDRSTRLEN
];
170 struct t_call sndcall
;
173 if (sa
->sa_family
!= AF_INET6
) {
174 DPRINT("bad af %d", sa
->sa_family
);
177 bcopy(sa
, &sin6
, sizeof (sin6
));
178 sin6
.sin6_port
= htons(port
);
180 DPRINT("tcp6: %s (%d)",
181 inet_ntop(AF_INET6
, &sin6
.sin6_addr
,
182 paddrbuf
, sizeof (paddrbuf
)), port
);
184 fd
= t_open(dev
, O_RDWR
, NULL
);
186 /* Assume t_errno = TSYSERR */
191 if ((err
= smb_setopts(fd
)) != 0)
193 if (t_bind(fd
, NULL
, NULL
) < 0) {
194 DPRINT("t_bind t_errno %d", t_errno
);
195 if (t_errno
== TSYSERR
)
201 sndcall
.addr
.maxlen
= sizeof (sin6
);
202 sndcall
.addr
.len
= sizeof (sin6
);
203 sndcall
.addr
.buf
= (void *) &sin6
;
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
);
212 DPRINT("tcp6: connected, fd=%d", fd
);
213 ctx
->ct_tran_fd
= fd
;
222 * This is used for both SMB over TCP (port 445)
223 * and NetBIOS - see conn_nbt().
226 conn_tcp4(struct smb_ctx
*ctx
, const struct sockaddr
*sa
, int port
)
228 struct sockaddr_in sin
;
229 char *dev
= "/dev/tcp";
230 char paddrbuf
[INET_ADDRSTRLEN
];
231 struct t_call sndcall
;
234 if (sa
->sa_family
!= AF_INET
) {
235 DPRINT("bad af %d", sa
->sa_family
);
238 bcopy(sa
, &sin
, sizeof (sin
));
239 sin
.sin_port
= htons(port
);
241 DPRINT("tcp4: %s (%d)",
242 inet_ntop(AF_INET
, &sin
.sin_addr
,
243 paddrbuf
, sizeof (paddrbuf
)), port
);
245 fd
= t_open(dev
, O_RDWR
, NULL
);
247 /* Assume t_errno = TSYSERR */
252 if ((err
= smb_setopts(fd
)) != 0)
254 if (t_bind(fd
, NULL
, NULL
) < 0) {
255 DPRINT("t_bind t_errno %d", t_errno
);
256 if (t_errno
== TSYSERR
)
262 sndcall
.addr
.maxlen
= sizeof (sin
);
263 sndcall
.addr
.len
= sizeof (sin
);
264 sndcall
.addr
.buf
= (void *) &sin
;
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
);
273 DPRINT("tcp4: connected, fd=%d", fd
);
274 ctx
->ct_tran_fd
= fd
;
283 * Open a NetBIOS connection (session, port 139)
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.
293 conn_nbt(struct smb_ctx
*ctx
, const struct sockaddr
*saarg
, char *name
)
295 struct sockaddr_in sin
;
297 char server
[NB_NAMELEN
];
298 char workgroup
[NB_NAMELEN
];
299 int err
, nberr
, port
;
301 bcopy(saarg
, &sin
, sizeof (sin
));
302 sa
= (struct sockaddr
*)&sin
;
304 switch (sin
.sin_family
) {
305 case AF_NETBIOS
: /* our fake AF */
306 sin
.sin_family
= AF_INET
;
311 DPRINT("bad af %d", sin
.sin_family
);
314 port
= IPPORT_NETBIOS_SSN
;
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.
325 strlcpy(server
, name
, sizeof (server
));
326 DPRINT("given name: %s", server
);
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.
335 DPRINT("try node status");
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
));
345 DPRINT("getnodestatus, nberr %d", nberr
);
346 strlcpy(server
, "*SMBSERVER", sizeof (server
));
351 * Establish the TCP connection.
352 * Careful to close it on errors.
354 if ((err
= conn_tcp4(ctx
, sa
, port
)) != 0) {
355 DPRINT("TCP connect: err=%d", err
);
359 /* Connected. Do NetBIOS session request. */
360 err
= nb_ssn_request(ctx
, server
);
362 DPRINT("ssn_rq, err %d", err
);
366 if (ctx
->ct_tran_fd
!= -1) {
367 close(ctx
->ct_tran_fd
);
368 ctx
->ct_tran_fd
= -1;
375 * Make a new connection, or reconnect.
378 smb_iod_connect(smb_ctx_t
*ctx
)
384 memset(&blob
, 0, sizeof (blob
));
386 if (ctx
->ct_srvname
[0] == '\0') {
387 DPRINT("sername not set!");
390 DPRINT("server: %s", ctx
->ct_srvname
);
393 dump_ctx("smb_iod_connect", ctx
);
396 * This may be a reconnect, so
397 * cleanup if necessary.
399 if (ctx
->ct_tran_fd
!= -1) {
400 close(ctx
->ct_tran_fd
);
401 ctx
->ct_tran_fd
= -1;
405 * Get local machine name.
406 * Full name - not a NetBIOS name.
408 if (ctx
->ct_locname
== NULL
) {
409 err
= smb_getlocalname(&ctx
->ct_locname
);
411 smb_error(dgettext(TEXT_DOMAIN
,
412 "can't get local name"), err
);
418 * We're called with each IP address
419 * already copied into ct_srvaddr.
421 ctx
->ct_flags
|= SMBCF_RESOLVED
;
423 sa
= &ctx
->ct_srvaddr
.sa
;
424 switch (sa
->sa_family
) {
427 err
= conn_tcp6(ctx
, sa
, IPPORT_SMB
);
431 err
= conn_tcp4(ctx
, sa
, IPPORT_SMB
);
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.
440 err2
= conn_nbt(ctx
, sa
, NULL
);
447 /* Like AF_INET, but use NetBIOS ssn. */
448 err
= conn_nbt(ctx
, sa
, ctx
->ct_srvname
);
452 DPRINT("skipped family %d", sa
->sa_family
);
453 err
= EPROTONOSUPPORT
;
459 DPRINT("connect, err=%d", err
);
464 * Do SMB Negotiate Protocol.
466 err
= smb_negprot(ctx
, &blob
);
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].
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
;
486 * Do SMB Session Setup (authenticate)
488 * If the server negotiated extended security,
489 * run the SPNEGO state machine, otherwise do
490 * one of the old-style variants.
492 if (ctx
->ct_clnt_caps
& SMB_CAP_EXT_SECURITY
) {
493 err
= smb_ssnsetup_spnego(ctx
, &blob
);
496 * Server did NOT negotiate extended security.
497 * Try NTLMv2, NTLMv1, or ANON (if enabled).
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
);
507 * Don't return EAUTH, because a new
508 * password prompt will not help.
510 DPRINT("No NTLM authflags");
519 close(ctx
->ct_tran_fd
);
520 ctx
->ct_tran_fd
= -1;
522 /* Tell library code we have a session. */
523 ctx
->ct_flags
|= SMBCF_SSNACTIVE
;
524 DPRINT("tran_fd = %d", ctx
->ct_tran_fd
);