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