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