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