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