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 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 26 */ 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <syslog.h> 31 #include <libintl.h> 32 #include <strings.h> 33 #include <string.h> 34 #include <unistd.h> 35 #include <synch.h> 36 #include <stropts.h> 37 #include <errno.h> 38 #include <pthread.h> 39 40 #include <inet/ip.h> 41 #include <net/if.h> 42 #include <netinet/in.h> 43 #include <netdb.h> 44 #include <net/route.h> 45 #include <arpa/inet.h> 46 47 #include <sys/socket.h> 48 #include <sys/sockio.h> 49 #include <sys/systeminfo.h> 50 51 #include <smbsrv/libsmb.h> 52 #include <sqlite-sys/sqlite.h> 53 54 #define SMB_NIC_DB_NAME "/var/smb/smbhosts.db" 55 #define SMB_NIC_DB_TIMEOUT 3000 /* in millisecond */ 56 #define SMB_NIC_DB_VERMAJOR 1 57 #define SMB_NIC_DB_VERMINOR 0 58 #define SMB_NIC_DB_MAGIC 0x484F5354 /* HOST */ 59 60 #define SMB_NIC_DB_ORD 1 /* open read-only */ 61 #define SMB_NIC_DB_ORW 2 /* open read/write */ 62 63 #define SMB_NIC_DB_SQL \ 64 "CREATE TABLE db_info (" \ 65 " ver_major INTEGER," \ 66 " ver_minor INTEGER," \ 67 " magic INTEGER" \ 68 ");" \ 69 "" \ 70 "CREATE TABLE hosts (" \ 71 " hostname TEXT PRIMARY KEY," \ 72 " comment TEXT," \ 73 " ifnames TEXT" \ 74 ");" 75 76 #define SMB_NIC_HTBL_NCOL 3 77 #define SMB_NIC_HTBL_HOST 0 78 #define SMB_NIC_HTBL_CMNT 1 79 #define SMB_NIC_HTBL_IFS 2 80 81 #define NULL_MSGCHK(msg) ((msg) ? (msg) : "NULL") 82 83 #define SMB_NIC_MAXIFS 256 84 #define SMB_NIC_MAXEXCLLIST_LEN 512 85 86 typedef struct smb_hostifs { 87 list_node_t if_lnd; 88 char if_host[MAXHOSTNAMELEN]; 89 char if_cmnt[SMB_PI_MAX_COMMENT]; 90 char *if_names[SMB_NIC_MAXIFS]; 91 int if_num; 92 } smb_hostifs_t; 93 94 typedef struct smb_hosts { 95 list_t h_list; 96 int h_num; 97 int h_ifnum; 98 } smb_hosts_t; 99 100 typedef struct { 101 smb_nic_t *nl_nics; 102 int nl_cnt; /* number of smb_nic_t structures */ 103 int nl_hcnt; /* number of host names */ 104 long nl_seqnum; /* a random sequence number */ 105 rwlock_t nl_rwl; 106 } smb_niclist_t; 107 108 static int smb_nic_list_create(void); 109 static void smb_nic_list_destroy(void); 110 111 static int smb_nic_hlist_create(smb_hosts_t *); 112 static void smb_nic_hlist_destroy(smb_hosts_t *); 113 static int smb_nic_hlist_dbget(smb_hosts_t *); 114 static int smb_nic_hlist_sysget(smb_hosts_t *); 115 116 static void smb_nic_iflist_destroy(smb_hostifs_t *); 117 static smb_hostifs_t *smb_nic_iflist_decode(const char **, int *); 118 119 static int smb_nic_dbcreate(void); 120 static sqlite *smb_nic_dbopen(int); 121 static void smb_nic_dbclose(sqlite *); 122 static boolean_t smb_nic_dbexists(void); 123 static boolean_t smb_nic_dbvalidate(void); 124 static int smb_nic_dbaddhost(const char *, const char *, char *); 125 static int smb_nic_dbdelhost(const char *); 126 static int smb_nic_dbsetinfo(sqlite *); 127 128 static int smb_nic_getinfo(char *, smb_nic_t *, int); 129 static boolean_t smb_nic_nbt_exclude(const smb_nic_t *, const char **, int); 130 static int smb_nic_nbt_get_exclude_list(char *, char **, int); 131 132 static void smb_close_sockets(int, int); 133 static boolean_t smb_duplicate_nic(smb_hostifs_t *iflist, struct lifreq *lifrp); 134 135 /* This is the list we will monitor */ 136 static smb_niclist_t smb_niclist; 137 138 /* 139 * smb_nic_init 140 * 141 * Initializes the interface list. 142 */ 143 int 144 smb_nic_init(void) 145 { 146 int rc; 147 148 (void) rw_wrlock(&smb_niclist.nl_rwl); 149 smb_nic_list_destroy(); 150 rc = smb_nic_list_create(); 151 (void) rw_unlock(&smb_niclist.nl_rwl); 152 153 return (rc); 154 } 155 156 /* 157 * smb_nic_fini 158 * 159 * Destroys the interface list. 160 */ 161 void 162 smb_nic_fini(void) 163 { 164 (void) rw_wrlock(&smb_niclist.nl_rwl); 165 smb_nic_list_destroy(); 166 (void) rw_unlock(&smb_niclist.nl_rwl); 167 } 168 169 /* 170 * smb_nic_getnum 171 * 172 * Gets the number of interfaces for the specified host. 173 * if host is NULL then total number of interfaces 174 * is returned. It's assumed that given name is a NetBIOS 175 * encoded name. 176 */ 177 int 178 smb_nic_getnum(char *nb_hostname) 179 { 180 int n = 0, i; 181 182 (void) rw_rdlock(&smb_niclist.nl_rwl); 183 184 if (nb_hostname != NULL) { 185 for (i = 0; i < smb_niclist.nl_cnt; i++) { 186 /* ignore the suffix */ 187 if (strncasecmp(smb_niclist.nl_nics[i].nic_nbname, 188 nb_hostname, NETBIOS_NAME_SZ - 1) == 0) 189 n++; 190 } 191 } else { 192 n = smb_niclist.nl_cnt; 193 } 194 195 (void) rw_unlock(&smb_niclist.nl_rwl); 196 197 return (n); 198 } 199 200 /* 201 * smb_nic_getfirst 202 * 203 * Returns the first NIC in the interface list and 204 * initializes the given iterator. To get the rest of 205 * NICs smb_nic_getnext() must be called. 206 * 207 * Returns SMB_NIC_SUCCESS upon success or the following: 208 * SMB_NIC_NOT_FOUND - there's no interface available 209 * SMB_NIC_INVALID_ARG - 'ni' is NULL 210 */ 211 int 212 smb_nic_getfirst(smb_niciter_t *ni) 213 { 214 int rc = SMB_NIC_SUCCESS; 215 216 if (ni == NULL) 217 return (SMB_NIC_INVALID_ARG); 218 219 (void) rw_rdlock(&smb_niclist.nl_rwl); 220 221 if (smb_niclist.nl_cnt > 0) { 222 ni->ni_nic = smb_niclist.nl_nics[0]; 223 ni->ni_cookie = 1; 224 ni->ni_seqnum = smb_niclist.nl_seqnum; 225 } else { 226 rc = SMB_NIC_NOT_FOUND; 227 } 228 229 (void) rw_unlock(&smb_niclist.nl_rwl); 230 231 return (rc); 232 } 233 234 /* 235 * smb_nic_getnext 236 * 237 * Returns the next NIC information based on the passed 238 * iterator (ni). The iterator must have previously been 239 * initialized by calling smb_nic_getfirst(). 240 * 241 * Returns SMB_NIC_SUCCESS upon successfully finding the specified NIC 242 * or the following: 243 * SMB_NIC_INVALID_ARG - the specified iterator is invalid 244 * SMB_NIC_NO_MORE - reaches the end of the NIC list 245 * SMB_NIC_CHANGED - sequence number in the iterator is different from 246 * the sequence number in the NIC list which means 247 * the list has been changed between getfirst/getnext 248 * calls. 249 */ 250 int 251 smb_nic_getnext(smb_niciter_t *ni) 252 { 253 int rc = SMB_NIC_SUCCESS; 254 255 if ((ni == NULL) || (ni->ni_cookie < 1)) 256 return (SMB_NIC_INVALID_ARG); 257 258 (void) rw_rdlock(&smb_niclist.nl_rwl); 259 260 if ((smb_niclist.nl_cnt > ni->ni_cookie) && 261 (smb_niclist.nl_seqnum == ni->ni_seqnum)) { 262 ni->ni_nic = smb_niclist.nl_nics[ni->ni_cookie]; 263 ni->ni_cookie++; 264 } else { 265 if (smb_niclist.nl_seqnum != ni->ni_seqnum) 266 rc = SMB_NIC_CHANGED; 267 else 268 rc = SMB_NIC_NO_MORE; 269 } 270 271 (void) rw_unlock(&smb_niclist.nl_rwl); 272 273 return (rc); 274 } 275 276 boolean_t 277 smb_nic_is_local(smb_inaddr_t *ipaddr) 278 { 279 smb_nic_t *cfg; 280 int i; 281 282 (void) rw_rdlock(&smb_niclist.nl_rwl); 283 284 for (i = 0; i < smb_niclist.nl_cnt; i++) { 285 cfg = &smb_niclist.nl_nics[i]; 286 if (smb_inet_equal(ipaddr, &cfg->nic_ip)) { 287 (void) rw_unlock(&smb_niclist.nl_rwl); 288 return (B_TRUE); 289 } 290 } 291 (void) rw_unlock(&smb_niclist.nl_rwl); 292 return (B_FALSE); 293 } 294 295 boolean_t 296 smb_nic_is_same_subnet(smb_inaddr_t *ipaddr) 297 { 298 smb_nic_t *cfg; 299 int i; 300 301 (void) rw_rdlock(&smb_niclist.nl_rwl); 302 303 for (i = 0; i < smb_niclist.nl_cnt; i++) { 304 cfg = &smb_niclist.nl_nics[i]; 305 if (smb_inet_same_subnet(ipaddr, &cfg->nic_ip, cfg->nic_mask)) { 306 (void) rw_unlock(&smb_niclist.nl_rwl); 307 return (B_TRUE); 308 } 309 } 310 (void) rw_unlock(&smb_niclist.nl_rwl); 311 return (B_FALSE); 312 } 313 314 /* 315 * smb_nic_addhost 316 * 317 * Adds an association between the given host and the specified interface 318 * list (if_names). This function can be called as many times as needed, 319 * the associations will be stored in /var/smb/smbhosts.db, which is sqlite 320 * database. If this file exists and it's not empty NIC list is generated 321 * based on the information stored in this file. 322 * 323 * host: actual system's name (not Netbios name) 324 * cmnt: an optional description for the CIFS server running on 325 * the specified host. Can be NULL. 326 * if_num: number of interface names in if_names arg 327 * if_names: array of interface names in string format 328 * 329 * Returns SMB_NIC_SUCCESS upon success, a nonzero value otherwise. 330 */ 331 int 332 smb_nic_addhost(const char *host, const char *cmnt, 333 int if_num, const char **if_names) 334 { 335 char *if_list; 336 char *ifname; 337 int buflen = 0; 338 int rc, i; 339 340 if ((host == NULL) || (if_num <= 0) || (if_names == NULL)) 341 return (SMB_NIC_INVALID_ARG); 342 343 if (!smb_nic_dbexists() || !smb_nic_dbvalidate()) { 344 if ((rc = smb_nic_dbcreate()) != SMB_NIC_SUCCESS) 345 return (rc); 346 } 347 348 for (i = 0; i < if_num; i++) { 349 ifname = (char *)if_names[i]; 350 if ((ifname == NULL) || (*ifname == '\0')) 351 return (SMB_NIC_INVALID_ARG); 352 buflen += strlen(ifname) + 1; 353 } 354 355 if ((if_list = malloc(buflen)) == NULL) 356 return (SMB_NIC_NO_MEMORY); 357 358 ifname = if_list; 359 for (i = 0; i < if_num - 1; i++) 360 ifname += snprintf(ifname, buflen, "%s,", if_names[i]); 361 362 (void) snprintf(ifname, buflen, "%s", if_names[i]); 363 364 rc = smb_nic_dbaddhost(host, cmnt, if_list); 365 free(if_list); 366 367 return (rc); 368 } 369 370 /* 371 * smb_nic_delhost 372 * 373 * Removes the stored interface association for the specified host 374 */ 375 int 376 smb_nic_delhost(const char *host) 377 { 378 if ((host == NULL) || (*host == '\0')) 379 return (SMB_NIC_INVALID_ARG); 380 381 if (!smb_nic_dbexists()) 382 return (SMB_NIC_SUCCESS); 383 384 if (!smb_nic_dbvalidate()) { 385 (void) unlink(SMB_NIC_DB_NAME); 386 return (SMB_NIC_SUCCESS); 387 } 388 389 return (smb_nic_dbdelhost(host)); 390 } 391 392 /* 393 * smb_nic_list_create 394 * 395 * Creates a NIC list either based on /var/smb/smbhosts.db or 396 * by getting the information from OS. 397 * 398 * Note that the caller of this function should grab the 399 * list lock. 400 */ 401 static int 402 smb_nic_list_create(void) 403 { 404 smb_hosts_t hlist; 405 smb_hostifs_t *iflist; 406 smb_nic_t *nc; 407 char *ifname; 408 char excludestr[SMB_NIC_MAXEXCLLIST_LEN]; 409 char *exclude[SMB_PI_MAX_NETWORKS]; 410 int nexclude = 0; 411 int i, rc; 412 413 if ((rc = smb_nic_hlist_create(&hlist)) != SMB_NIC_SUCCESS) 414 return (rc); 415 416 smb_niclist.nl_cnt = 0; 417 smb_niclist.nl_seqnum = random(); 418 smb_niclist.nl_hcnt = hlist.h_num; 419 420 smb_niclist.nl_nics = calloc(hlist.h_ifnum, sizeof (smb_nic_t)); 421 if (smb_niclist.nl_nics == NULL) { 422 smb_nic_hlist_destroy(&hlist); 423 return (SMB_NIC_NO_MEMORY); 424 } 425 426 *excludestr = '\0'; 427 (void) smb_config_getstr(SMB_CI_WINS_EXCL, 428 excludestr, sizeof (excludestr)); 429 430 nexclude = smb_nic_nbt_get_exclude_list(excludestr, 431 exclude, SMB_PI_MAX_NETWORKS); 432 433 nc = smb_niclist.nl_nics; 434 iflist = list_head(&hlist.h_list); 435 436 do { 437 for (i = 0; i < iflist->if_num; i++) { 438 ifname = iflist->if_names[i]; 439 if (smb_nic_getinfo(ifname, nc, AF_INET) != 440 SMB_NIC_SUCCESS) { 441 if (smb_nic_getinfo(ifname, nc, 442 AF_INET6) != SMB_NIC_SUCCESS) { 443 continue; 444 } 445 } 446 447 (void) strlcpy(nc->nic_host, iflist->if_host, 448 sizeof (nc->nic_host)); 449 (void) strlcpy(nc->nic_cmnt, iflist->if_cmnt, 450 sizeof (nc->nic_cmnt)); 451 452 smb_tonetbiosname(nc->nic_host, nc->nic_nbname, 0x00); 453 454 if (strchr(ifname, ':')) 455 nc->nic_smbflags |= SMB_NICF_ALIAS; 456 457 if (smb_nic_nbt_exclude(nc, 458 (const char **)exclude, nexclude)) 459 nc->nic_smbflags |= SMB_NICF_NBEXCL; 460 461 smb_niclist.nl_cnt++; 462 nc++; 463 } 464 } while ((iflist = list_next(&hlist.h_list, iflist)) != NULL); 465 466 smb_nic_hlist_destroy(&hlist); 467 468 return (SMB_NIC_SUCCESS); 469 } 470 471 static void 472 smb_nic_list_destroy(void) 473 { 474 free(smb_niclist.nl_nics); 475 smb_niclist.nl_nics = NULL; 476 smb_niclist.nl_cnt = 0; 477 } 478 479 static int 480 smb_nic_getinfo(char *interface, smb_nic_t *nc, int family) 481 { 482 struct lifreq lifrr; 483 int s; 484 boolean_t isv6; 485 struct sockaddr_in6 *sin6; 486 struct sockaddr_in *sin; 487 488 if ((s = socket(family, SOCK_DGRAM, IPPROTO_IP)) < 0) { 489 return (SMB_NIC_SOCK); 490 } 491 492 (void) strlcpy(lifrr.lifr_name, interface, sizeof (lifrr.lifr_name)); 493 if (ioctl(s, SIOCGLIFADDR, &lifrr) < 0) { 494 (void) close(s); 495 return (SMB_NIC_IOCTL); 496 } 497 isv6 = (lifrr.lifr_addr.ss_family == AF_INET6); 498 if (isv6) { 499 sin6 = (struct sockaddr_in6 *)(&lifrr.lifr_addr); 500 nc->nic_ip.a_ipv6 = sin6->sin6_addr; 501 nc->nic_ip.a_family = AF_INET6; 502 } else { 503 sin = (struct sockaddr_in *)(&lifrr.lifr_addr); 504 nc->nic_ip.a_ipv4 = (in_addr_t)(sin->sin_addr.s_addr); 505 nc->nic_ip.a_family = AF_INET; 506 } 507 if (smb_inet_iszero(&nc->nic_ip)) { 508 (void) close(s); 509 return (SMB_NIC_BAD_DATA); 510 } 511 /* there is no broadcast or netmask for v6 */ 512 if (!isv6) { 513 if (ioctl(s, SIOCGLIFBRDADDR, &lifrr) < 0) { 514 (void) close(s); 515 return (SMB_NIC_IOCTL); 516 } 517 sin = (struct sockaddr_in *)&lifrr.lifr_broadaddr; 518 nc->nic_bcast = (uint32_t)sin->sin_addr.s_addr; 519 520 if (ioctl(s, SIOCGLIFNETMASK, &lifrr) < 0) { 521 (void) close(s); 522 return (SMB_NIC_IOCTL); 523 } 524 sin = (struct sockaddr_in *)&lifrr.lifr_addr; 525 nc->nic_mask = (uint32_t)sin->sin_addr.s_addr; 526 } 527 if (ioctl(s, SIOCGLIFFLAGS, &lifrr) < 0) { 528 (void) close(s); 529 return (SMB_NIC_IOCTL); 530 } 531 nc->nic_sysflags = lifrr.lifr_flags; 532 533 (void) strlcpy(nc->nic_ifname, interface, sizeof (nc->nic_ifname)); 534 535 (void) close(s); 536 return (SMB_NIC_SUCCESS); 537 } 538 539 /* 540 * smb_nic_hlist_create 541 * 542 * Creates a list of hosts and their associated interfaces. 543 * If host database exists the information is retrieved from 544 * the database, otherwise it's retrieved from OS. 545 * 546 * The allocated memories for the returned list should be freed 547 * by calling smb_nic_hlist_destroy() 548 */ 549 static int 550 smb_nic_hlist_create(smb_hosts_t *hlist) 551 { 552 int rc; 553 554 list_create(&hlist->h_list, sizeof (smb_hostifs_t), 555 offsetof(smb_hostifs_t, if_lnd)); 556 hlist->h_num = 0; 557 hlist->h_ifnum = 0; 558 559 if (smb_nic_dbexists() && smb_nic_dbvalidate()) { 560 rc = smb_nic_hlist_dbget(hlist); 561 errno = EBADF; 562 } else { 563 rc = smb_nic_hlist_sysget(hlist); 564 } 565 566 if (rc != SMB_NIC_SUCCESS) 567 smb_nic_hlist_destroy(hlist); 568 569 return (rc); 570 } 571 572 static void 573 smb_nic_hlist_destroy(smb_hosts_t *hlist) 574 { 575 smb_hostifs_t *iflist; 576 577 if (hlist == NULL) 578 return; 579 580 while ((iflist = list_head(&hlist->h_list)) != NULL) { 581 list_remove(&hlist->h_list, iflist); 582 smb_nic_iflist_destroy(iflist); 583 } 584 585 list_destroy(&hlist->h_list); 586 } 587 588 static void 589 smb_close_sockets(int s4, int s6) 590 { 591 if (s4) 592 (void) close(s4); 593 if (s6) 594 (void) close(s6); 595 } 596 597 /* 598 * smb_nic_hlist_sysget 599 * 600 * Get the list of currently plumbed and up interface names. The loopback (lo0) 601 * port is ignored 602 */ 603 static int 604 smb_nic_hlist_sysget(smb_hosts_t *hlist) 605 { 606 smb_hostifs_t *iflist; 607 struct lifconf lifc; 608 struct lifreq lifrl; 609 struct lifreq *lifrp; 610 char *ifname; 611 int ifnum; 612 int i; 613 int s4, s6; 614 struct lifnum lifn; 615 616 iflist = malloc(sizeof (smb_hostifs_t)); 617 if (iflist == NULL) 618 return (SMB_NIC_NO_MEMORY); 619 620 bzero(iflist, sizeof (smb_hostifs_t)); 621 622 if (smb_gethostname(iflist->if_host, sizeof (iflist->if_host), 623 SMB_CASE_PRESERVE) < 0) { 624 free(iflist); 625 return (SMB_NIC_NO_HOST); 626 } 627 628 (void) smb_config_getstr(SMB_CI_SYS_CMNT, iflist->if_cmnt, 629 sizeof (iflist->if_cmnt)); 630 631 if ((s4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 632 free(iflist); 633 return (SMB_NIC_SOCK); 634 } 635 s6 = socket(AF_INET6, SOCK_DGRAM, 0); 636 637 lifn.lifn_family = AF_UNSPEC; 638 lifn.lifn_flags = 0; 639 if (ioctl(s4, SIOCGLIFNUM, (char *)&lifn) < 0) { 640 smb_close_sockets(s4, s6); 641 free(iflist); 642 syslog(LOG_ERR, "hlist_sysget: SIOCGLIFNUM errno=%d", errno); 643 return (SMB_NIC_IOCTL); 644 } 645 646 lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq); 647 lifc.lifc_buf = malloc(lifc.lifc_len); 648 if (lifc.lifc_buf == NULL) { 649 smb_close_sockets(s4, s6); 650 free(iflist); 651 return (SMB_NIC_NO_MEMORY); 652 } 653 bzero(lifc.lifc_buf, lifc.lifc_len); 654 lifc.lifc_family = AF_UNSPEC; 655 lifc.lifc_flags = 0; 656 657 if (ioctl(s4, SIOCGLIFCONF, (char *)&lifc) < 0) { 658 smb_close_sockets(s4, s6); 659 free(iflist); 660 free(lifc.lifc_buf); 661 return (SMB_NIC_IOCTL); 662 } 663 664 lifrp = lifc.lifc_req; 665 ifnum = lifc.lifc_len / sizeof (struct lifreq); 666 hlist->h_num = 0; 667 for (i = 0; i < ifnum; i++, lifrp++) { 668 669 if ((iflist->if_num > 0) && smb_duplicate_nic(iflist, lifrp)) 670 continue; 671 /* 672 * Get the flags so that we can skip the loopback interface 673 */ 674 (void) memset(&lifrl, 0, sizeof (lifrl)); 675 (void) strlcpy(lifrl.lifr_name, lifrp->lifr_name, 676 sizeof (lifrl.lifr_name)); 677 678 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) { 679 if ((s6 < 0) || 680 (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)) { 681 smb_close_sockets(s4, s6); 682 free(lifc.lifc_buf); 683 smb_nic_iflist_destroy(iflist); 684 return (SMB_NIC_IOCTL); 685 } 686 } 687 if (lifrl.lifr_flags & IFF_LOOPBACK) { 688 continue; 689 } 690 691 if ((lifrl.lifr_flags & IFF_UP) == 0) { 692 continue; 693 } 694 ifname = strdup(lifrp->lifr_name); 695 if (ifname == NULL) { 696 smb_close_sockets(s4, s6); 697 free(lifc.lifc_buf); 698 smb_nic_iflist_destroy(iflist); 699 return (SMB_NIC_NO_MEMORY); 700 } 701 iflist->if_names[iflist->if_num++] = ifname; 702 } 703 hlist->h_ifnum = iflist->if_num; 704 hlist->h_num = 1; 705 smb_close_sockets(s4, s6); 706 free(lifc.lifc_buf); 707 list_insert_tail(&hlist->h_list, iflist); 708 709 return (SMB_NIC_SUCCESS); 710 } 711 712 static boolean_t 713 smb_duplicate_nic(smb_hostifs_t *iflist, struct lifreq *lifrp) 714 { 715 int j; 716 /* 717 * throw out duplicate names 718 */ 719 for (j = 0; j < iflist->if_num; j++) { 720 if (strcmp(iflist->if_names[j], 721 lifrp->lifr_name) == 0) 722 return (B_TRUE); 723 } 724 return (B_FALSE); 725 } 726 727 static int 728 smb_nic_hlist_dbget(smb_hosts_t *hlist) 729 { 730 smb_hostifs_t *iflist; 731 sqlite *db; 732 sqlite_vm *vm; 733 int err = SMB_NIC_SUCCESS; 734 const char **values; 735 char *sql; 736 char *errmsg = NULL; 737 int ncol, rc; 738 739 sql = sqlite_mprintf("SELECT * FROM hosts"); 740 if (sql == NULL) 741 return (SMB_NIC_NO_MEMORY); 742 743 db = smb_nic_dbopen(SMB_NIC_DB_ORD); 744 if (db == NULL) { 745 sqlite_freemem(sql); 746 return (SMB_NIC_DBOPEN_FAILED); 747 } 748 749 rc = sqlite_compile(db, sql, NULL, &vm, &errmsg); 750 sqlite_freemem(sql); 751 752 if (rc != SQLITE_OK) { 753 smb_nic_dbclose(db); 754 syslog(LOG_ERR, "Failed to query hosts info from host " \ 755 "database. Unable to create virtual machine (%s).", 756 NULL_MSGCHK(errmsg)); 757 return (SMB_NIC_DB_ERROR); 758 } 759 760 do { 761 rc = sqlite_step(vm, &ncol, &values, NULL); 762 if (rc == SQLITE_ROW) { 763 if (ncol != SMB_NIC_HTBL_NCOL) { 764 err = SMB_NIC_DB_ERROR; 765 break; 766 } 767 768 if ((iflist = smb_nic_iflist_decode(values, &err)) == 769 NULL) { 770 break; 771 } 772 773 list_insert_tail(&hlist->h_list, iflist); 774 hlist->h_num++; 775 hlist->h_ifnum += iflist->if_num; 776 } 777 } while (rc == SQLITE_ROW); 778 779 if (rc != SQLITE_DONE && err == SMB_NIC_SUCCESS) { 780 /* set this error if no previous error */ 781 err = SMB_LGRP_DBEXEC_FAILED; 782 } 783 784 rc = sqlite_finalize(vm, &errmsg); 785 if (rc != SQLITE_OK) { 786 syslog(LOG_ERR, "Failed to query hosts info from host " \ 787 "database. Unable to destroy virtual machine (%s).", 788 NULL_MSGCHK(errmsg)); 789 if (err == SMB_NIC_SUCCESS) { 790 /* set this error if no previous error */ 791 err = SMB_NIC_DB_ERROR; 792 } 793 } 794 795 smb_nic_dbclose(db); 796 797 return (err); 798 } 799 800 static smb_hostifs_t * 801 smb_nic_iflist_decode(const char **values, int *err) 802 { 803 smb_hostifs_t *iflist; 804 char *host; 805 char *cmnt; 806 char *ifnames; 807 char *lasts; 808 char *ifname; 809 int if_num = 0; 810 811 host = (char *)values[SMB_NIC_HTBL_HOST]; 812 cmnt = (char *)values[SMB_NIC_HTBL_CMNT]; 813 ifnames = (char *)values[SMB_NIC_HTBL_IFS]; 814 815 if ((host == NULL) || (ifnames == NULL)) { 816 *err = SMB_NIC_INVALID_ARG; 817 return (NULL); 818 } 819 820 iflist = malloc(sizeof (smb_hostifs_t)); 821 if (iflist == NULL) { 822 *err = SMB_NIC_NO_MEMORY; 823 return (NULL); 824 } 825 826 bzero(iflist, sizeof (smb_hostifs_t)); 827 828 (void) strlcpy(iflist->if_host, host, sizeof (iflist->if_host)); 829 (void) strlcpy(iflist->if_cmnt, (cmnt) ? cmnt : "", 830 sizeof (iflist->if_cmnt)); 831 832 if ((ifname = strtok_r(ifnames, ",", &lasts)) == NULL) { 833 *err = SMB_NIC_BAD_DATA; 834 return (NULL); 835 } 836 837 iflist->if_names[if_num++] = strdup(ifname); 838 839 while ((ifname = strtok_r(NULL, ",", &lasts)) != NULL) 840 iflist->if_names[if_num++] = strdup(ifname); 841 842 iflist->if_num = if_num; 843 844 for (if_num = 0; if_num < iflist->if_num; if_num++) { 845 if (iflist->if_names[if_num] == NULL) { 846 smb_nic_iflist_destroy(iflist); 847 *err = SMB_NIC_NO_MEMORY; 848 return (NULL); 849 } 850 } 851 852 *err = SMB_NIC_SUCCESS; 853 return (iflist); 854 } 855 856 /* 857 * smb_nic_iflist_destroy 858 * 859 * Frees allocated memory for the given IF names lists. 860 */ 861 static void 862 smb_nic_iflist_destroy(smb_hostifs_t *iflist) 863 { 864 int i; 865 866 if (iflist == NULL) 867 return; 868 869 for (i = 0; i < iflist->if_num; i++) 870 free(iflist->if_names[i]); 871 872 free(iflist); 873 } 874 875 /* 876 * Functions to manage host/interface database 877 * 878 * Each entry in the hosts table associates a hostname with a 879 * list of interface names. The host/interface association could 880 * be added by calling smb_nic_addhost() and could be removed by 881 * calling smb_nic_delhost(). If the database exists and it contains 882 * valid information then the inteface list wouldn't be obtained 883 * from system using ioctl. 884 */ 885 886 /* 887 * smb_nic_dbcreate 888 * 889 * Creates the host database based on the defined SQL statement. 890 * It also initializes db_info table. 891 */ 892 static int 893 smb_nic_dbcreate(void) 894 { 895 sqlite *db = NULL; 896 char *errmsg = NULL; 897 int rc, err = SMB_NIC_SUCCESS; 898 899 (void) unlink(SMB_NIC_DB_NAME); 900 901 db = sqlite_open(SMB_NIC_DB_NAME, 0600, &errmsg); 902 if (db == NULL) { 903 syslog(LOG_ERR, "Failed to create host database (%s).", 904 NULL_MSGCHK(errmsg)); 905 sqlite_freemem(errmsg); 906 return (SMB_NIC_DBOPEN_FAILED); 907 } 908 909 sqlite_busy_timeout(db, SMB_NIC_DB_TIMEOUT); 910 rc = sqlite_exec(db, "BEGIN TRANSACTION", NULL, NULL, &errmsg); 911 if (rc != SQLITE_OK) { 912 syslog(LOG_ERR, "Failed to create host database. Unable to " \ 913 "begin database transaction (%s).", NULL_MSGCHK(errmsg)); 914 sqlite_freemem(errmsg); 915 sqlite_close(db); 916 return (SMB_NIC_DBEXEC_FAILED); 917 } 918 919 if (sqlite_exec(db, SMB_NIC_DB_SQL, NULL, NULL, &errmsg) == SQLITE_OK) { 920 rc = sqlite_exec(db, "COMMIT TRANSACTION", NULL, NULL, 921 &errmsg); 922 if (rc == SQLITE_OK) 923 err = smb_nic_dbsetinfo(db); 924 if (err != SMB_NIC_SUCCESS) 925 rc = sqlite_exec(db, "ROLLBACK TRANSACTION", NULL, NULL, 926 &errmsg); 927 } else { 928 syslog(LOG_ERR, "Failed to create host database. Unable to " \ 929 "initialize host database (%s).", NULL_MSGCHK(errmsg)); 930 sqlite_freemem(errmsg); 931 rc = sqlite_exec(db, "ROLLBACK TRANSACTION", NULL, NULL, 932 &errmsg); 933 } 934 935 if (rc != SQLITE_OK) { 936 /* this is bad - database may be left in a locked state */ 937 syslog(LOG_ERR, "Failed to create host database. Unable to " \ 938 "close a transaction (%s).", NULL_MSGCHK(errmsg)); 939 sqlite_freemem(errmsg); 940 err = SMB_NIC_DBINIT_FAILED; 941 } 942 943 (void) sqlite_close(db); 944 return (err); 945 } 946 947 /* 948 * smb_nic_dbopen 949 * 950 * Opens host database with the given mode. 951 */ 952 static sqlite * 953 smb_nic_dbopen(int mode) 954 { 955 sqlite *db; 956 char *errmsg = NULL; 957 958 db = sqlite_open(SMB_NIC_DB_NAME, mode, &errmsg); 959 if (db == NULL) { 960 syslog(LOG_ERR, "Failed to open host database: %s (%s).", 961 SMB_NIC_DB_NAME, NULL_MSGCHK(errmsg)); 962 sqlite_freemem(errmsg); 963 } 964 965 return (db); 966 } 967 968 /* 969 * smb_nic_dbclose 970 * 971 * Closes the given database handle 972 */ 973 static void 974 smb_nic_dbclose(sqlite *db) 975 { 976 if (db) { 977 sqlite_close(db); 978 } 979 } 980 981 static boolean_t 982 smb_nic_dbexists(void) 983 { 984 return (access(SMB_NIC_DB_NAME, F_OK) == 0); 985 } 986 987 static boolean_t 988 smb_nic_dbvalidate(void) 989 { 990 sqlite *db; 991 char *errmsg = NULL; 992 char *sql; 993 char **result; 994 int nrow, ncol; 995 boolean_t check = B_TRUE; 996 int rc; 997 998 sql = sqlite_mprintf("SELECT * FROM db_info"); 999 if (sql == NULL) 1000 return (B_FALSE); 1001 1002 db = smb_nic_dbopen(SMB_NIC_DB_ORW); 1003 if (db == NULL) { 1004 sqlite_freemem(sql); 1005 return (B_FALSE); 1006 } 1007 1008 rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg); 1009 sqlite_freemem(sql); 1010 1011 if (rc != SQLITE_OK) { 1012 syslog(LOG_ERR, "Failed to validate host database. Unable " \ 1013 "to get database information (%s).", NULL_MSGCHK(errmsg)); 1014 sqlite_freemem(errmsg); 1015 smb_nic_dbclose(db); 1016 return (B_FALSE); 1017 } 1018 1019 if (nrow != 1 || ncol != 3) { 1020 syslog(LOG_ERR, "Failed to validate host database: bad " \ 1021 "db_info table."); 1022 sqlite_free_table(result); 1023 smb_nic_dbclose(db); 1024 return (B_FALSE); 1025 } 1026 1027 if ((atoi(result[3]) != SMB_NIC_DB_VERMAJOR) || 1028 (atoi(result[4]) != SMB_NIC_DB_VERMINOR) || 1029 (atoi(result[5]) != SMB_NIC_DB_MAGIC)) { 1030 syslog(LOG_ERR, "Failed to validate host database: bad " \ 1031 "db_info content."); 1032 sqlite_free_table(result); 1033 smb_nic_dbclose(db); 1034 return (B_FALSE); 1035 } 1036 sqlite_free_table(result); 1037 1038 sql = sqlite_mprintf("SELECT hostname FROM hosts"); 1039 if (sql == NULL) { 1040 smb_nic_dbclose(db); 1041 return (B_FALSE); 1042 } 1043 1044 rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg); 1045 sqlite_freemem(sql); 1046 1047 if (rc != SQLITE_OK) { 1048 syslog(LOG_ERR, "Failed to validate host database. Unable " \ 1049 "to query for host (%s).", NULL_MSGCHK(errmsg)); 1050 sqlite_freemem(errmsg); 1051 smb_nic_dbclose(db); 1052 return (B_FALSE); 1053 } 1054 1055 sqlite_free_table(result); 1056 1057 if (nrow == 0) 1058 /* No hosts in the database */ 1059 check = B_FALSE; 1060 1061 smb_nic_dbclose(db); 1062 return (check); 1063 } 1064 1065 static int 1066 smb_nic_dbaddhost(const char *host, const char *cmnt, char *if_list) 1067 { 1068 sqlite *db; 1069 char *sql; 1070 char *errmsg; 1071 int rc, err = SMB_NIC_SUCCESS; 1072 1073 sql = sqlite_mprintf("REPLACE INTO hosts (hostname, comment, ifnames)" 1074 "VALUES ('%s', '%q', '%s')", host, (cmnt) ? cmnt : "", if_list); 1075 if (sql == NULL) 1076 return (SMB_NIC_NO_MEMORY); 1077 1078 db = smb_nic_dbopen(SMB_NIC_DB_ORW); 1079 if (db == NULL) { 1080 sqlite_freemem(sql); 1081 return (SMB_NIC_DBOPEN_FAILED); 1082 } 1083 1084 rc = sqlite_exec(db, sql, NULL, NULL, &errmsg); 1085 sqlite_freemem(sql); 1086 smb_nic_dbclose(db); 1087 1088 if (rc != SQLITE_OK) { 1089 syslog(LOG_ERR, "Failed to add host %s to host database (%s).", 1090 host, NULL_MSGCHK(errmsg)); 1091 sqlite_freemem(errmsg); 1092 err = SMB_NIC_INSERT_FAILED; 1093 } 1094 1095 return (err); 1096 } 1097 1098 static int 1099 smb_nic_dbdelhost(const char *host) 1100 { 1101 sqlite *db; 1102 char *sql; 1103 char *errmsg; 1104 int rc, err = SMB_NIC_SUCCESS; 1105 1106 sql = sqlite_mprintf("DELETE FROM hosts WHERE hostname = '%s'", host); 1107 if (sql == NULL) 1108 return (SMB_NIC_NO_MEMORY); 1109 1110 db = smb_nic_dbopen(SMB_NIC_DB_ORW); 1111 if (db == NULL) { 1112 sqlite_freemem(sql); 1113 return (SMB_NIC_DBOPEN_FAILED); 1114 } 1115 1116 rc = sqlite_exec(db, sql, NULL, NULL, &errmsg); 1117 sqlite_freemem(sql); 1118 smb_nic_dbclose(db); 1119 1120 if (rc != SQLITE_OK) { 1121 syslog(LOG_ERR, "Failed to delete host %s from host " \ 1122 "database (%s).", host, NULL_MSGCHK(errmsg)); 1123 sqlite_freemem(errmsg); 1124 err = SMB_NIC_DELETE_FAILED; 1125 } 1126 1127 return (err); 1128 } 1129 1130 /* 1131 * smb_nic_dbsetinfo 1132 * 1133 * Initializes the db_info table upon database creation. 1134 */ 1135 static int 1136 smb_nic_dbsetinfo(sqlite *db) 1137 { 1138 char *errmsg = NULL; 1139 char *sql; 1140 int rc, err = SMB_NIC_SUCCESS; 1141 1142 sql = sqlite_mprintf("INSERT INTO db_info (ver_major, ver_minor," 1143 " magic) VALUES (%d, %d, %d)", SMB_NIC_DB_VERMAJOR, 1144 SMB_NIC_DB_VERMINOR, SMB_NIC_DB_MAGIC); 1145 1146 if (sql == NULL) 1147 return (SMB_NIC_NO_MEMORY); 1148 1149 rc = sqlite_exec(db, sql, NULL, NULL, &errmsg); 1150 sqlite_freemem(sql); 1151 if (rc != SQLITE_OK) { 1152 syslog(LOG_ERR, "Failed to add database information to " \ 1153 "host database (%s).", NULL_MSGCHK(errmsg)); 1154 sqlite_freemem(errmsg); 1155 err = SMB_NIC_DBINIT_ERROR; 1156 } 1157 1158 return (err); 1159 } 1160 1161 /* 1162 * smb_nic_nbt_get_exclude_list 1163 * 1164 * Construct an array containing list of i/f names on which NetBIOS traffic is 1165 * to be disabled, from a string containing a list of comma separated i/f names. 1166 * 1167 * Returns the number of i/f on which NetBIOS traffic is to be disabled. 1168 */ 1169 static int 1170 smb_nic_nbt_get_exclude_list(char *excludestr, char **iflist, int max_nifs) 1171 { 1172 int n = 0; 1173 char *entry; 1174 1175 bzero(iflist, SMB_PI_MAX_NETWORKS * sizeof (char *)); 1176 1177 (void) trim_whitespace(excludestr); 1178 (void) strcanon(excludestr, ","); 1179 1180 if (*excludestr == '\0') 1181 return (0); 1182 1183 while (((iflist[n] = strsep(&excludestr, ",")) != NULL) && 1184 (n < max_nifs)) { 1185 entry = iflist[n]; 1186 if (*entry == '\0') 1187 continue; 1188 n++; 1189 } 1190 1191 return (n); 1192 } 1193 1194 /* 1195 * smb_nic_nbt_exclude 1196 * 1197 * Check to see if the given interface name should send NetBIOS traffic or not. 1198 * 1199 * Returns TRUE if NetBIOS traffic is disabled on an interface name. 1200 * Returns FALSE otherwise. 1201 */ 1202 static boolean_t 1203 smb_nic_nbt_exclude(const smb_nic_t *nc, const char **exclude_list, 1204 int nexclude) 1205 { 1206 char buf[INET6_ADDRSTRLEN]; 1207 const char *ifname = nc->nic_ifname; 1208 int i; 1209 1210 if (inet_ntop(AF_INET, &nc->nic_ip, buf, INET6_ADDRSTRLEN) == NULL) 1211 buf[0] = '\0'; 1212 1213 for (i = 0; i < nexclude; i++) { 1214 if (strcmp(ifname, exclude_list[i]) == 0) 1215 return (B_TRUE); 1216 1217 if ((buf[0] != '\0') && (strcmp(buf, exclude_list[i]) == 0)) 1218 return (B_TRUE); 1219 } 1220 1221 return (B_FALSE); 1222 } 1223