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