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 */
26
27 /*
28 * Functions to setup connections (TCP and/or NetBIOS)
29 * This has the fall-back logic for IP6, IP4, NBT
30 */
31
32 #include <errno.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <netdb.h>
39 #include <libintl.h>
40 #include <xti.h>
41 #include <assert.h>
42
43 #include <sys/types.h>
44 #include <sys/time.h>
45 #include <sys/byteorder.h>
46 #include <sys/socket.h>
47 #include <sys/fcntl.h>
48
49 #include <netinet/in.h>
50 #include <netinet/tcp.h>
51 #include <arpa/inet.h>
52
53 #include <netsmb/smb.h>
54 #include <netsmb/smb_lib.h>
55 #include <netsmb/netbios.h>
56 #include <netsmb/nb_lib.h>
57 #include <netsmb/smb_dev.h>
58
59 #include "charsets.h"
60 #include "private.h"
61
62 /*
63 * SMB messages are up to 64K.
64 * Let's leave room for two.
65 */
66 static int smb_tcpsndbuf = 0x20000;
67 static int smb_tcprcvbuf = 0x20000;
68 static int smb_connect_timeout = 30; /* seconds */
69 int smb_recv_timeout = 30; /* seconds */
70
71 int conn_tcp6(struct smb_ctx *, const struct sockaddr *, int);
72 int conn_tcp4(struct smb_ctx *, const struct sockaddr *, int);
73 int conn_nbt(struct smb_ctx *, const struct sockaddr *, char *);
74
75 /*
76 * Internal set sockopt for int-sized options.
77 * Borrowed from: libnsl/rpc/ti_opts.c
78 */
79 static int
smb_setopt_int(int fd,int level,int name,int val)80 smb_setopt_int(int fd, int level, int name, int val)
81 {
82 struct t_optmgmt oreq, ores;
83 struct {
84 struct t_opthdr oh;
85 int ival;
86 } opts;
87
88 /* opt header */
89 opts.oh.len = sizeof (opts);
90 opts.oh.level = level;
91 opts.oh.name = name;
92 opts.oh.status = 0;
93 opts.ival = val;
94
95 oreq.flags = T_NEGOTIATE;
96 oreq.opt.buf = (void *)&opts;
97 oreq.opt.len = sizeof (opts);
98
99 ores.flags = 0;
100 ores.opt.buf = NULL;
101 ores.opt.maxlen = 0;
102
103 if (t_optmgmt(fd, &oreq, &ores) < 0) {
104 DPRINT("t_opgmgnt, t_errno = %d", t_errno);
105 if (t_errno == TSYSERR)
106 return (errno);
107 return (EPROTO);
108 }
109 if (ores.flags != T_SUCCESS) {
110 DPRINT("flags 0x%x, status 0x%x",
111 (int)ores.flags, (int)opts.oh.status);
112 return (EPROTO);
113 }
114
115 return (0);
116 }
117
118 static int
smb_setopts(int fd)119 smb_setopts(int fd)
120 {
121 int err;
122
123 /*
124 * Set various socket/TCP options.
125 * Failures here are not fatal -
126 * just log a complaint.
127 *
128 * We don't need these two:
129 * SO_RCVTIMEO, SO_SNDTIMEO
130 */
131
132 err = smb_setopt_int(fd, SOL_SOCKET, SO_SNDBUF, smb_tcpsndbuf);
133 if (err) {
134 DPRINT("set SO_SNDBUF, err %d", err);
135 }
136
137 err = smb_setopt_int(fd, SOL_SOCKET, SO_RCVBUF, smb_tcprcvbuf);
138 if (err) {
139 DPRINT("set SO_RCVBUF, err %d", err);
140 }
141
142 err = smb_setopt_int(fd, SOL_SOCKET, SO_KEEPALIVE, 1);
143 if (err) {
144 DPRINT("set SO_KEEPALIVE, err %d", err);
145 }
146
147 err = smb_setopt_int(fd, IPPROTO_TCP, TCP_NODELAY, 1);
148 if (err) {
149 DPRINT("set TCP_NODELAY, err %d", err);
150 }
151
152 /* Set the connect timeout (in milliseconds). */
153 err = smb_setopt_int(fd, IPPROTO_TCP,
154 TCP_CONN_ABORT_THRESHOLD,
155 smb_connect_timeout * 1000);
156 if (err) {
157 DPRINT("set connect timeout, err %d", err);
158 }
159 return (0);
160 }
161
162
163 int
conn_tcp6(struct smb_ctx * ctx,const struct sockaddr * sa,int port)164 conn_tcp6(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
165 {
166 struct sockaddr_in6 sin6;
167 char *dev = "/dev/tcp6";
168 char paddrbuf[INET6_ADDRSTRLEN];
169 struct t_call sndcall;
170 int fd, err;
171
172 if (sa->sa_family != AF_INET6) {
173 DPRINT("bad af %d", sa->sa_family);
174 return (EINVAL);
175 }
176 bcopy(sa, &sin6, sizeof (sin6));
177 sin6.sin6_port = htons(port);
178
179 DPRINT("tcp6: %s (%d)",
180 inet_ntop(AF_INET6, &sin6.sin6_addr,
181 paddrbuf, sizeof (paddrbuf)), port);
182
183 fd = t_open(dev, O_RDWR, NULL);
184 if (fd < 0) {
185 /* Assume t_errno = TSYSERR */
186 err = errno;
187 perror(dev);
188 return (err);
189 }
190 if ((err = smb_setopts(fd)) != 0)
191 goto errout;
192 if (t_bind(fd, NULL, NULL) < 0) {
193 DPRINT("t_bind t_errno %d", t_errno);
194 if (t_errno == TSYSERR)
195 err = errno;
196 else
197 err = EPROTO;
198 goto errout;
199 }
200 sndcall.addr.maxlen = sizeof (sin6);
201 sndcall.addr.len = sizeof (sin6);
202 sndcall.addr.buf = (void *) &sin6;
203 sndcall.opt.len = 0;
204 sndcall.udata.len = 0;
205 if (t_connect(fd, &sndcall, NULL) < 0) {
206 err = get_xti_err(fd);
207 DPRINT("connect, err %d", err);
208 goto errout;
209 }
210
211 DPRINT("tcp6: connected, fd=%d", fd);
212 ctx->ct_tran_fd = fd;
213 return (0);
214
215 errout:
216 close(fd);
217 return (err);
218 }
219
220 /*
221 * This is used for both SMB over TCP (port 445)
222 * and NetBIOS - see conn_nbt().
223 */
224 int
conn_tcp4(struct smb_ctx * ctx,const struct sockaddr * sa,int port)225 conn_tcp4(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
226 {
227 struct sockaddr_in sin;
228 char *dev = "/dev/tcp";
229 char paddrbuf[INET_ADDRSTRLEN];
230 struct t_call sndcall;
231 int fd, err;
232
233 if (sa->sa_family != AF_INET) {
234 DPRINT("bad af %d", sa->sa_family);
235 return (EINVAL);
236 }
237 bcopy(sa, &sin, sizeof (sin));
238 sin.sin_port = htons(port);
239
240 DPRINT("tcp4: %s (%d)",
241 inet_ntop(AF_INET, &sin.sin_addr,
242 paddrbuf, sizeof (paddrbuf)), port);
243
244 fd = t_open(dev, O_RDWR, NULL);
245 if (fd < 0) {
246 /* Assume t_errno = TSYSERR */
247 err = errno;
248 perror(dev);
249 return (err);
250 }
251 if ((err = smb_setopts(fd)) != 0)
252 goto errout;
253 if (t_bind(fd, NULL, NULL) < 0) {
254 DPRINT("t_bind t_errno %d", t_errno);
255 if (t_errno == TSYSERR)
256 err = errno;
257 else
258 err = EPROTO;
259 goto errout;
260 }
261 sndcall.addr.maxlen = sizeof (sin);
262 sndcall.addr.len = sizeof (sin);
263 sndcall.addr.buf = (void *) &sin;
264 sndcall.opt.len = 0;
265 sndcall.udata.len = 0;
266 if (t_connect(fd, &sndcall, NULL) < 0) {
267 err = get_xti_err(fd);
268 DPRINT("connect, err %d", err);
269 goto errout;
270 }
271
272 DPRINT("tcp4: connected, fd=%d", fd);
273 ctx->ct_tran_fd = fd;
274 return (0);
275
276 errout:
277 close(fd);
278 return (err);
279 }
280
281 /*
282 * Open a NetBIOS connection (session, port 139)
283 *
284 * The optional name parameter, if passed, means
285 * we found the sockaddr via NetBIOS name lookup,
286 * and can just use that for our session request.
287 * Otherwise (if name is NULL), we're connecting
288 * by IP address, and need to come up with the
289 * NetBIOS name by other means.
290 */
291 int
conn_nbt(struct smb_ctx * ctx,const struct sockaddr * saarg,char * name)292 conn_nbt(struct smb_ctx *ctx, const struct sockaddr *saarg, char *name)
293 {
294 struct sockaddr_in sin;
295 struct sockaddr *sa;
296 char server[NB_NAMELEN];
297 char workgroup[NB_NAMELEN];
298 int err, nberr, port;
299
300 bcopy(saarg, &sin, sizeof (sin));
301 sa = (struct sockaddr *)&sin;
302
303 switch (sin.sin_family) {
304 case AF_NETBIOS: /* our fake AF */
305 sin.sin_family = AF_INET;
306 break;
307 case AF_INET:
308 break;
309 default:
310 DPRINT("bad af %d", sin.sin_family);
311 return (EINVAL);
312 }
313 port = IPPORT_NETBIOS_SSN;
314
315 /*
316 * If we have a NetBIOS name, just use it.
317 * This is the path taken when we've done a
318 * NetBIOS name lookup on this name to get
319 * the IP address in the passed sa. Otherwise,
320 * we're connecting by IP address, and need to
321 * figure out what NetBIOS name to use.
322 */
323 if (name) {
324 strlcpy(server, name, sizeof (server));
325 DPRINT("given name: %s", server);
326 } else {
327 /*
328 *
329 * Try a NetBIOS node status query,
330 * which searches for a type=[20] name.
331 * If that doesn't work, just use the
332 * (fake) "*SMBSERVER" name.
333 */
334 DPRINT("try node status");
335 server[0] = '\0';
336 nberr = nbns_getnodestatus(ctx->ct_nb,
337 &sin.sin_addr, server, workgroup);
338 if (nberr == 0 && server[0] != '\0') {
339 /* Found the name. Save for reconnect. */
340 DPRINT("found name: %s", server);
341 strlcpy(ctx->ct_srvname, server,
342 sizeof (ctx->ct_srvname));
343 } else {
344 DPRINT("getnodestatus, nberr %d", nberr);
345 strlcpy(server, "*SMBSERVER", sizeof (server));
346 }
347 }
348
349 /*
350 * Establish the TCP connection.
351 * Careful to close it on errors.
352 */
353 if ((err = conn_tcp4(ctx, sa, port)) != 0) {
354 DPRINT("TCP connect: err=%d", err);
355 goto out;
356 }
357
358 /* Connected. Do NetBIOS session request. */
359 err = nb_ssn_request(ctx, server);
360 if (err)
361 DPRINT("ssn_rq, err %d", err);
362
363 out:
364 if (err) {
365 if (ctx->ct_tran_fd != -1) {
366 close(ctx->ct_tran_fd);
367 ctx->ct_tran_fd = -1;
368 }
369 }
370 return (err);
371 }
372
373 /*
374 * Make a new connection, or reconnect.
375 */
376 int
smb_iod_connect(smb_ctx_t * ctx)377 smb_iod_connect(smb_ctx_t *ctx)
378 {
379 struct sockaddr *sa;
380 int err, err2;
381 struct mbdata blob;
382
383 memset(&blob, 0, sizeof (blob));
384
385 if (ctx->ct_srvname[0] == '\0') {
386 DPRINT("sername not set!");
387 return (EINVAL);
388 }
389 DPRINT("server: %s", ctx->ct_srvname);
390
391 if (smb_debug)
392 dump_ctx("smb_iod_connect", ctx);
393
394 /*
395 * This may be a reconnect, so
396 * cleanup if necessary.
397 */
398 if (ctx->ct_tran_fd != -1) {
399 close(ctx->ct_tran_fd);
400 ctx->ct_tran_fd = -1;
401 }
402
403 /*
404 * Get local machine name.
405 * Full name - not a NetBIOS name.
406 */
407 if (ctx->ct_locname == NULL) {
408 err = smb_getlocalname(&ctx->ct_locname);
409 if (err) {
410 smb_error(dgettext(TEXT_DOMAIN,
411 "can't get local name"), err);
412 return (err);
413 }
414 }
415
416 /*
417 * We're called with each IP address
418 * already copied into ct_srvaddr.
419 */
420 ctx->ct_flags |= SMBCF_RESOLVED;
421
422 sa = &ctx->ct_srvaddr.sa;
423 switch (sa->sa_family) {
424
425 case AF_INET6:
426 err = conn_tcp6(ctx, sa, IPPORT_SMB);
427 break;
428
429 case AF_INET:
430 err = conn_tcp4(ctx, sa, IPPORT_SMB);
431 /*
432 * If port 445 was not listening, try port 139.
433 * Note: Not doing NetBIOS name lookup here.
434 * We already have the IP address.
435 */
436 switch (err) {
437 case ECONNRESET:
438 case ECONNREFUSED:
439 err2 = conn_nbt(ctx, sa, NULL);
440 if (err2 == 0)
441 err = 0;
442 }
443 break;
444
445 case AF_NETBIOS:
446 /* Like AF_INET, but use NetBIOS ssn. */
447 err = conn_nbt(ctx, sa, ctx->ct_srvname);
448 break;
449
450 default:
451 DPRINT("skipped family %d", sa->sa_family);
452 err = EPROTONOSUPPORT;
453 break;
454 }
455
456
457 if (err) {
458 DPRINT("connect, err=%d", err);
459 return (err);
460 }
461
462 /*
463 * SMB Negotiate Protocol and
464 * SMB Session Setup, one of 3 ways:
465 * NULL session
466 * Extended security,
467 * NTLM (v2, v1)
468 *
469 * Empty user name means an explicit request for
470 * NULL session setup. No fall-back logic here.
471 *
472 * For NULL session, don't offer extended security.
473 * That's a lot simpler than dealing with NTLMSSP.
474 */
475 if (ctx->ct_user[0] == '\0') {
476 ctx->ct_vopt &= ~SMBVOPT_EXT_SEC;
477 err = smb_negprot(ctx, &blob);
478 if (err)
479 goto out;
480 err = smb_ssnsetup_null(ctx);
481 } else {
482 /*
483 * Do SMB Negotiate Protocol.
484 */
485 err = smb_negprot(ctx, &blob);
486 if (err)
487 goto out;
488
489 /*
490 * Do SMB Session Setup (authenticate)
491 *
492 * If the server negotiated extended security,
493 * run the SPNEGO state machine.
494 */
495 if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
496 err = smb_ssnsetup_spnego(ctx, &blob);
497 } else {
498 /*
499 * Server did NOT negotiate extended security.
500 * Try NTLMv2, NTLMv1 (if enabled).
501 */
502 if ((ctx->ct_authflags &
503 (SMB_AT_NTLM2 | SMB_AT_NTLM1)) == 0) {
504 /*
505 * Don't return EAUTH, because a
506 * new password will not help.
507 */
508 DPRINT("No NTLM authflags");
509 err = ENOTSUP;
510 goto out;
511 }
512 if (ctx->ct_authflags & SMB_AT_NTLM2)
513 err = smb_ssnsetup_ntlm2(ctx);
514 else
515 err = EAUTH;
516 if (err == EAUTH && 0 !=
517 (ctx->ct_authflags & SMB_AT_NTLM1))
518 err = smb_ssnsetup_ntlm1(ctx);
519 }
520 }
521
522 /* Tell library code we have a session. */
523 ctx->ct_flags |= SMBCF_RESOLVED | SMBCF_SSNACTIVE;
524
525 out:
526 mb_done(&blob);
527
528 if (err) {
529 close(ctx->ct_tran_fd);
530 ctx->ct_tran_fd = -1;
531 } else
532 DPRINT("tran_fd = %d", ctx->ct_tran_fd);
533
534 return (err);
535 }
536