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 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 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 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 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 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 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