5917 User-mode SMB server
[unleashed.git] / usr / src / lib / smbsrv / libsmb / common / smb_nic.c
blob30be231e2f05dce88c5dbf37d343e0d1cd8c001a
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
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>
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>
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49 #include <sys/systeminfo.h>
51 #include <smbsrv/libsmb.h>
52 #include <sqlite-sys/sqlite.h>
54 #define SMB_NIC_DB_NAME "/var/smb/smbhosts.db"
55 #define SMB_NIC_DB_TIMEOUT 3000 /* in millisecond */
56 #define SMB_NIC_DB_VERMAJOR 1
57 #define SMB_NIC_DB_VERMINOR 0
58 #define SMB_NIC_DB_MAGIC 0x484F5354 /* HOST */
60 #define SMB_NIC_DB_ORD 1 /* open read-only */
61 #define SMB_NIC_DB_ORW 2 /* open read/write */
63 #define SMB_NIC_DB_SQL \
64 "CREATE TABLE db_info (" \
65 " ver_major INTEGER," \
66 " ver_minor INTEGER," \
67 " magic INTEGER" \
68 ");" \
69 "" \
70 "CREATE TABLE hosts (" \
71 " hostname TEXT PRIMARY KEY," \
72 " comment TEXT," \
73 " ifnames TEXT" \
74 ");"
76 #define SMB_NIC_HTBL_NCOL 3
77 #define SMB_NIC_HTBL_HOST 0
78 #define SMB_NIC_HTBL_CMNT 1
79 #define SMB_NIC_HTBL_IFS 2
81 #define NULL_MSGCHK(msg) ((msg) ? (msg) : "NULL")
83 #define SMB_NIC_MAXIFS 256
84 #define SMB_NIC_MAXEXCLLIST_LEN 512
86 typedef struct smb_hostifs {
87 list_node_t if_lnd;
88 char if_host[MAXHOSTNAMELEN];
89 char if_cmnt[SMB_PI_MAX_COMMENT];
90 char *if_names[SMB_NIC_MAXIFS];
91 int if_num;
92 } smb_hostifs_t;
94 typedef struct smb_hosts {
95 list_t h_list;
96 int h_num;
97 int h_ifnum;
98 } smb_hosts_t;
100 typedef struct {
101 smb_nic_t *nl_nics;
102 int nl_cnt; /* number of smb_nic_t structures */
103 int nl_hcnt; /* number of host names */
104 long nl_seqnum; /* a random sequence number */
105 rwlock_t nl_rwl;
106 } smb_niclist_t;
108 static int smb_nic_list_create(void);
109 static void smb_nic_list_destroy(void);
111 static int smb_nic_hlist_create(smb_hosts_t *);
112 static void smb_nic_hlist_destroy(smb_hosts_t *);
113 static int smb_nic_hlist_dbget(smb_hosts_t *);
114 static int smb_nic_hlist_sysget(smb_hosts_t *);
116 static void smb_nic_iflist_destroy(smb_hostifs_t *);
117 static smb_hostifs_t *smb_nic_iflist_decode(const char **, int *);
119 static int smb_nic_dbcreate(void);
120 static sqlite *smb_nic_dbopen(int);
121 static void smb_nic_dbclose(sqlite *);
122 static boolean_t smb_nic_dbexists(void);
123 static boolean_t smb_nic_dbvalidate(void);
124 static int smb_nic_dbaddhost(const char *, const char *, char *);
125 static int smb_nic_dbdelhost(const char *);
126 static int smb_nic_dbsetinfo(sqlite *);
128 static int smb_nic_getinfo(char *, smb_nic_t *, int);
129 static boolean_t smb_nic_nbt_exclude(const smb_nic_t *, const char **, int);
130 static int smb_nic_nbt_get_exclude_list(char *, char **, int);
132 static void smb_close_sockets(int, int);
133 static boolean_t smb_duplicate_nic(smb_hostifs_t *iflist, struct lifreq *lifrp);
135 /* This is the list we will monitor */
136 static smb_niclist_t smb_niclist;
139 * smb_nic_init
141 * Initializes the interface list.
144 smb_nic_init(void)
146 int rc;
148 (void) rw_wrlock(&smb_niclist.nl_rwl);
149 smb_nic_list_destroy();
150 rc = smb_nic_list_create();
151 (void) rw_unlock(&smb_niclist.nl_rwl);
153 return (rc);
157 * smb_nic_fini
159 * Destroys the interface list.
161 void
162 smb_nic_fini(void)
164 (void) rw_wrlock(&smb_niclist.nl_rwl);
165 smb_nic_list_destroy();
166 (void) rw_unlock(&smb_niclist.nl_rwl);
170 * smb_nic_getnum
172 * Gets the number of interfaces for the specified host.
173 * if host is NULL then total number of interfaces
174 * is returned. It's assumed that given name is a NetBIOS
175 * encoded name.
178 smb_nic_getnum(char *nb_hostname)
180 int n = 0, i;
182 (void) rw_rdlock(&smb_niclist.nl_rwl);
184 if (nb_hostname != NULL) {
185 for (i = 0; i < smb_niclist.nl_cnt; i++) {
186 /* ignore the suffix */
187 if (strncasecmp(smb_niclist.nl_nics[i].nic_nbname,
188 nb_hostname, NETBIOS_NAME_SZ - 1) == 0)
189 n++;
191 } else {
192 n = smb_niclist.nl_cnt;
195 (void) rw_unlock(&smb_niclist.nl_rwl);
197 return (n);
201 * smb_nic_getfirst
203 * Returns the first NIC in the interface list and
204 * initializes the given iterator. To get the rest of
205 * NICs smb_nic_getnext() must be called.
207 * Returns SMB_NIC_SUCCESS upon success or the following:
208 * SMB_NIC_NOT_FOUND - there's no interface available
209 * SMB_NIC_INVALID_ARG - 'ni' is NULL
212 smb_nic_getfirst(smb_niciter_t *ni)
214 int rc = SMB_NIC_SUCCESS;
216 if (ni == NULL)
217 return (SMB_NIC_INVALID_ARG);
219 (void) rw_rdlock(&smb_niclist.nl_rwl);
221 if (smb_niclist.nl_cnt > 0) {
222 ni->ni_nic = smb_niclist.nl_nics[0];
223 ni->ni_cookie = 1;
224 ni->ni_seqnum = smb_niclist.nl_seqnum;
225 } else {
226 rc = SMB_NIC_NOT_FOUND;
229 (void) rw_unlock(&smb_niclist.nl_rwl);
231 return (rc);
235 * smb_nic_getnext
237 * Returns the next NIC information based on the passed
238 * iterator (ni). The iterator must have previously been
239 * initialized by calling smb_nic_getfirst().
241 * Returns SMB_NIC_SUCCESS upon successfully finding the specified NIC
242 * or the following:
243 * SMB_NIC_INVALID_ARG - the specified iterator is invalid
244 * SMB_NIC_NO_MORE - reaches the end of the NIC list
245 * SMB_NIC_CHANGED - sequence number in the iterator is different from
246 * the sequence number in the NIC list which means
247 * the list has been changed between getfirst/getnext
248 * calls.
251 smb_nic_getnext(smb_niciter_t *ni)
253 int rc = SMB_NIC_SUCCESS;
255 if ((ni == NULL) || (ni->ni_cookie < 1))
256 return (SMB_NIC_INVALID_ARG);
258 (void) rw_rdlock(&smb_niclist.nl_rwl);
260 if ((smb_niclist.nl_cnt > ni->ni_cookie) &&
261 (smb_niclist.nl_seqnum == ni->ni_seqnum)) {
262 ni->ni_nic = smb_niclist.nl_nics[ni->ni_cookie];
263 ni->ni_cookie++;
264 } else {
265 if (smb_niclist.nl_seqnum != ni->ni_seqnum)
266 rc = SMB_NIC_CHANGED;
267 else
268 rc = SMB_NIC_NO_MORE;
271 (void) rw_unlock(&smb_niclist.nl_rwl);
273 return (rc);
276 boolean_t
277 smb_nic_is_local(smb_inaddr_t *ipaddr)
279 smb_nic_t *cfg;
280 int i;
282 (void) rw_rdlock(&smb_niclist.nl_rwl);
284 for (i = 0; i < smb_niclist.nl_cnt; i++) {
285 cfg = &smb_niclist.nl_nics[i];
286 if (smb_inet_equal(ipaddr, &cfg->nic_ip)) {
287 (void) rw_unlock(&smb_niclist.nl_rwl);
288 return (B_TRUE);
291 (void) rw_unlock(&smb_niclist.nl_rwl);
292 return (B_FALSE);
295 boolean_t
296 smb_nic_is_same_subnet(smb_inaddr_t *ipaddr)
298 smb_nic_t *cfg;
299 int i;
301 (void) rw_rdlock(&smb_niclist.nl_rwl);
303 for (i = 0; i < smb_niclist.nl_cnt; i++) {
304 cfg = &smb_niclist.nl_nics[i];
305 if (smb_inet_same_subnet(ipaddr, &cfg->nic_ip, cfg->nic_mask)) {
306 (void) rw_unlock(&smb_niclist.nl_rwl);
307 return (B_TRUE);
310 (void) rw_unlock(&smb_niclist.nl_rwl);
311 return (B_FALSE);
315 * smb_nic_addhost
317 * Adds an association between the given host and the specified interface
318 * list (if_names). This function can be called as many times as needed,
319 * the associations will be stored in /var/smb/smbhosts.db, which is sqlite
320 * database. If this file exists and it's not empty NIC list is generated
321 * based on the information stored in this file.
323 * host: actual system's name (not Netbios name)
324 * cmnt: an optional description for the CIFS server running on
325 * the specified host. Can be NULL.
326 * if_num: number of interface names in if_names arg
327 * if_names: array of interface names in string format
329 * Returns SMB_NIC_SUCCESS upon success, a nonzero value otherwise.
332 smb_nic_addhost(const char *host, const char *cmnt,
333 int if_num, const char **if_names)
335 char *if_list;
336 char *ifname;
337 int buflen = 0;
338 int rc, i;
340 if ((host == NULL) || (if_num <= 0) || (if_names == NULL))
341 return (SMB_NIC_INVALID_ARG);
343 if (!smb_nic_dbexists() || !smb_nic_dbvalidate()) {
344 if ((rc = smb_nic_dbcreate()) != SMB_NIC_SUCCESS)
345 return (rc);
348 for (i = 0; i < if_num; i++) {
349 ifname = (char *)if_names[i];
350 if ((ifname == NULL) || (*ifname == '\0'))
351 return (SMB_NIC_INVALID_ARG);
352 buflen += strlen(ifname) + 1;
355 if ((if_list = malloc(buflen)) == NULL)
356 return (SMB_NIC_NO_MEMORY);
358 ifname = if_list;
359 for (i = 0; i < if_num - 1; i++)
360 ifname += snprintf(ifname, buflen, "%s,", if_names[i]);
362 (void) snprintf(ifname, buflen, "%s", if_names[i]);
364 rc = smb_nic_dbaddhost(host, cmnt, if_list);
365 free(if_list);
367 return (rc);
371 * smb_nic_delhost
373 * Removes the stored interface association for the specified host
376 smb_nic_delhost(const char *host)
378 if ((host == NULL) || (*host == '\0'))
379 return (SMB_NIC_INVALID_ARG);
381 if (!smb_nic_dbexists())
382 return (SMB_NIC_SUCCESS);
384 if (!smb_nic_dbvalidate()) {
385 (void) unlink(SMB_NIC_DB_NAME);
386 return (SMB_NIC_SUCCESS);
389 return (smb_nic_dbdelhost(host));
393 * smb_nic_list_create
395 * Creates a NIC list either based on /var/smb/smbhosts.db or
396 * by getting the information from OS.
398 * Note that the caller of this function should grab the
399 * list lock.
401 static int
402 smb_nic_list_create(void)
404 smb_hosts_t hlist;
405 smb_hostifs_t *iflist;
406 smb_nic_t *nc;
407 char *ifname;
408 char excludestr[SMB_NIC_MAXEXCLLIST_LEN];
409 char *exclude[SMB_PI_MAX_NETWORKS];
410 int nexclude = 0;
411 int i, rc;
413 if ((rc = smb_nic_hlist_create(&hlist)) != SMB_NIC_SUCCESS)
414 return (rc);
416 smb_niclist.nl_cnt = 0;
417 smb_niclist.nl_seqnum = random();
418 smb_niclist.nl_hcnt = hlist.h_num;
420 smb_niclist.nl_nics = calloc(hlist.h_ifnum, sizeof (smb_nic_t));
421 if (smb_niclist.nl_nics == NULL) {
422 smb_nic_hlist_destroy(&hlist);
423 return (SMB_NIC_NO_MEMORY);
426 *excludestr = '\0';
427 (void) smb_config_getstr(SMB_CI_WINS_EXCL,
428 excludestr, sizeof (excludestr));
430 nexclude = smb_nic_nbt_get_exclude_list(excludestr,
431 exclude, SMB_PI_MAX_NETWORKS);
433 nc = smb_niclist.nl_nics;
434 iflist = list_head(&hlist.h_list);
436 do {
437 for (i = 0; i < iflist->if_num; i++) {
438 ifname = iflist->if_names[i];
439 if (smb_nic_getinfo(ifname, nc, AF_INET) !=
440 SMB_NIC_SUCCESS) {
441 if (smb_nic_getinfo(ifname, nc,
442 AF_INET6) != SMB_NIC_SUCCESS) {
443 continue;
447 (void) strlcpy(nc->nic_host, iflist->if_host,
448 sizeof (nc->nic_host));
449 (void) strlcpy(nc->nic_cmnt, iflist->if_cmnt,
450 sizeof (nc->nic_cmnt));
452 smb_tonetbiosname(nc->nic_host, nc->nic_nbname, 0x00);
454 if (strchr(ifname, ':'))
455 nc->nic_smbflags |= SMB_NICF_ALIAS;
457 if (smb_nic_nbt_exclude(nc,
458 (const char **)exclude, nexclude))
459 nc->nic_smbflags |= SMB_NICF_NBEXCL;
461 smb_niclist.nl_cnt++;
462 nc++;
464 } while ((iflist = list_next(&hlist.h_list, iflist)) != NULL);
466 smb_nic_hlist_destroy(&hlist);
468 return (SMB_NIC_SUCCESS);
471 static void
472 smb_nic_list_destroy(void)
474 free(smb_niclist.nl_nics);
475 smb_niclist.nl_nics = NULL;
476 smb_niclist.nl_cnt = 0;
479 static int
480 smb_nic_getinfo(char *interface, smb_nic_t *nc, int family)
482 struct lifreq lifrr;
483 int s;
484 boolean_t isv6;
485 struct sockaddr_in6 *sin6;
486 struct sockaddr_in *sin;
488 if ((s = socket(family, SOCK_DGRAM, IPPROTO_IP)) < 0) {
489 return (SMB_NIC_SOCK);
492 (void) strlcpy(lifrr.lifr_name, interface, sizeof (lifrr.lifr_name));
493 if (ioctl(s, SIOCGLIFADDR, &lifrr) < 0) {
494 (void) close(s);
495 return (SMB_NIC_IOCTL);
497 isv6 = (lifrr.lifr_addr.ss_family == AF_INET6);
498 if (isv6) {
499 sin6 = (struct sockaddr_in6 *)(&lifrr.lifr_addr);
500 nc->nic_ip.a_ipv6 = sin6->sin6_addr;
501 nc->nic_ip.a_family = AF_INET6;
502 } else {
503 sin = (struct sockaddr_in *)(&lifrr.lifr_addr);
504 nc->nic_ip.a_ipv4 = (in_addr_t)(sin->sin_addr.s_addr);
505 nc->nic_ip.a_family = AF_INET;
507 if (smb_inet_iszero(&nc->nic_ip)) {
508 (void) close(s);
509 return (SMB_NIC_BAD_DATA);
511 /* there is no broadcast or netmask for v6 */
512 if (!isv6) {
513 if (ioctl(s, SIOCGLIFBRDADDR, &lifrr) < 0) {
514 (void) close(s);
515 return (SMB_NIC_IOCTL);
517 sin = (struct sockaddr_in *)&lifrr.lifr_broadaddr;
518 nc->nic_bcast = (uint32_t)sin->sin_addr.s_addr;
520 if (ioctl(s, SIOCGLIFNETMASK, &lifrr) < 0) {
521 (void) close(s);
522 return (SMB_NIC_IOCTL);
524 sin = (struct sockaddr_in *)&lifrr.lifr_addr;
525 nc->nic_mask = (uint32_t)sin->sin_addr.s_addr;
527 if (ioctl(s, SIOCGLIFFLAGS, &lifrr) < 0) {
528 (void) close(s);
529 return (SMB_NIC_IOCTL);
531 nc->nic_sysflags = lifrr.lifr_flags;
533 (void) strlcpy(nc->nic_ifname, interface, sizeof (nc->nic_ifname));
535 (void) close(s);
536 return (SMB_NIC_SUCCESS);
540 * smb_nic_hlist_create
542 * Creates a list of hosts and their associated interfaces.
543 * If host database exists the information is retrieved from
544 * the database, otherwise it's retrieved from OS.
546 * The allocated memories for the returned list should be freed
547 * by calling smb_nic_hlist_destroy()
549 static int
550 smb_nic_hlist_create(smb_hosts_t *hlist)
552 int rc;
554 list_create(&hlist->h_list, sizeof (smb_hostifs_t),
555 offsetof(smb_hostifs_t, if_lnd));
556 hlist->h_num = 0;
557 hlist->h_ifnum = 0;
559 if (smb_nic_dbexists() && smb_nic_dbvalidate()) {
560 rc = smb_nic_hlist_dbget(hlist);
561 errno = EBADF;
562 } else {
563 rc = smb_nic_hlist_sysget(hlist);
566 if (rc != SMB_NIC_SUCCESS)
567 smb_nic_hlist_destroy(hlist);
569 return (rc);
572 static void
573 smb_nic_hlist_destroy(smb_hosts_t *hlist)
575 smb_hostifs_t *iflist;
577 if (hlist == NULL)
578 return;
580 while ((iflist = list_head(&hlist->h_list)) != NULL) {
581 list_remove(&hlist->h_list, iflist);
582 smb_nic_iflist_destroy(iflist);
585 list_destroy(&hlist->h_list);
588 static void
589 smb_close_sockets(int s4, int s6)
591 if (s4)
592 (void) close(s4);
593 if (s6)
594 (void) close(s6);
598 * smb_nic_hlist_sysget
600 * Get the list of currently plumbed and up interface names. The loopback (lo0)
601 * port is ignored
603 static int
604 smb_nic_hlist_sysget(smb_hosts_t *hlist)
606 smb_hostifs_t *iflist;
607 struct lifconf lifc;
608 struct lifreq lifrl;
609 struct lifreq *lifrp;
610 char *ifname;
611 int ifnum;
612 int i;
613 int s4, s6;
614 struct lifnum lifn;
616 iflist = malloc(sizeof (smb_hostifs_t));
617 if (iflist == NULL)
618 return (SMB_NIC_NO_MEMORY);
620 bzero(iflist, sizeof (smb_hostifs_t));
622 if (smb_gethostname(iflist->if_host, sizeof (iflist->if_host),
623 SMB_CASE_PRESERVE) < 0) {
624 free(iflist);
625 return (SMB_NIC_NO_HOST);
628 (void) smb_config_getstr(SMB_CI_SYS_CMNT, iflist->if_cmnt,
629 sizeof (iflist->if_cmnt));
631 if ((s4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
632 free(iflist);
633 return (SMB_NIC_SOCK);
635 s6 = socket(AF_INET6, SOCK_DGRAM, 0);
637 lifn.lifn_family = AF_UNSPEC;
638 lifn.lifn_flags = 0;
639 if (ioctl(s4, SIOCGLIFNUM, (char *)&lifn) < 0) {
640 smb_close_sockets(s4, s6);
641 free(iflist);
642 syslog(LOG_ERR, "hlist_sysget: SIOCGLIFNUM errno=%d", errno);
643 return (SMB_NIC_IOCTL);
646 lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq);
647 lifc.lifc_buf = malloc(lifc.lifc_len);
648 if (lifc.lifc_buf == NULL) {
649 smb_close_sockets(s4, s6);
650 free(iflist);
651 return (SMB_NIC_NO_MEMORY);
653 bzero(lifc.lifc_buf, lifc.lifc_len);
654 lifc.lifc_family = AF_UNSPEC;
655 lifc.lifc_flags = 0;
657 if (ioctl(s4, SIOCGLIFCONF, (char *)&lifc) < 0) {
658 smb_close_sockets(s4, s6);
659 free(iflist);
660 free(lifc.lifc_buf);
661 return (SMB_NIC_IOCTL);
664 lifrp = lifc.lifc_req;
665 ifnum = lifc.lifc_len / sizeof (struct lifreq);
666 hlist->h_num = 0;
667 for (i = 0; i < ifnum; i++, lifrp++) {
669 if ((iflist->if_num > 0) && smb_duplicate_nic(iflist, lifrp))
670 continue;
672 * Get the flags so that we can skip the loopback interface
674 (void) memset(&lifrl, 0, sizeof (lifrl));
675 (void) strlcpy(lifrl.lifr_name, lifrp->lifr_name,
676 sizeof (lifrl.lifr_name));
678 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) {
679 if ((s6 < 0) ||
680 (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)) {
681 smb_close_sockets(s4, s6);
682 free(lifc.lifc_buf);
683 smb_nic_iflist_destroy(iflist);
684 return (SMB_NIC_IOCTL);
687 if (lifrl.lifr_flags & IFF_LOOPBACK) {
688 continue;
691 if ((lifrl.lifr_flags & IFF_UP) == 0) {
692 continue;
694 ifname = strdup(lifrp->lifr_name);
695 if (ifname == NULL) {
696 smb_close_sockets(s4, s6);
697 free(lifc.lifc_buf);
698 smb_nic_iflist_destroy(iflist);
699 return (SMB_NIC_NO_MEMORY);
701 iflist->if_names[iflist->if_num++] = ifname;
703 hlist->h_ifnum = iflist->if_num;
704 hlist->h_num = 1;
705 smb_close_sockets(s4, s6);
706 free(lifc.lifc_buf);
707 list_insert_tail(&hlist->h_list, iflist);
709 return (SMB_NIC_SUCCESS);
712 static boolean_t
713 smb_duplicate_nic(smb_hostifs_t *iflist, struct lifreq *lifrp)
715 int j;
717 * throw out duplicate names
719 for (j = 0; j < iflist->if_num; j++) {
720 if (strcmp(iflist->if_names[j],
721 lifrp->lifr_name) == 0)
722 return (B_TRUE);
724 return (B_FALSE);
727 static int
728 smb_nic_hlist_dbget(smb_hosts_t *hlist)
730 smb_hostifs_t *iflist;
731 sqlite *db;
732 sqlite_vm *vm;
733 int err = SMB_NIC_SUCCESS;
734 const char **values;
735 char *sql;
736 char *errmsg = NULL;
737 int ncol, rc;
739 sql = sqlite_mprintf("SELECT * FROM hosts");
740 if (sql == NULL)
741 return (SMB_NIC_NO_MEMORY);
743 db = smb_nic_dbopen(SMB_NIC_DB_ORD);
744 if (db == NULL) {
745 sqlite_freemem(sql);
746 return (SMB_NIC_DBOPEN_FAILED);
749 rc = sqlite_compile(db, sql, NULL, &vm, &errmsg);
750 sqlite_freemem(sql);
752 if (rc != SQLITE_OK) {
753 smb_nic_dbclose(db);
754 syslog(LOG_ERR, "Failed to query hosts info from host " \
755 "database. Unable to create virtual machine (%s).",
756 NULL_MSGCHK(errmsg));
757 return (SMB_NIC_DB_ERROR);
760 do {
761 rc = sqlite_step(vm, &ncol, &values, NULL);
762 if (rc == SQLITE_ROW) {
763 if (ncol != SMB_NIC_HTBL_NCOL) {
764 err = SMB_NIC_DB_ERROR;
765 break;
768 if ((iflist = smb_nic_iflist_decode(values, &err)) ==
769 NULL) {
770 break;
773 list_insert_tail(&hlist->h_list, iflist);
774 hlist->h_num++;
775 hlist->h_ifnum += iflist->if_num;
777 } while (rc == SQLITE_ROW);
779 if (rc != SQLITE_DONE && err == SMB_NIC_SUCCESS) {
780 /* set this error if no previous error */
781 err = SMB_LGRP_DBEXEC_FAILED;
784 rc = sqlite_finalize(vm, &errmsg);
785 if (rc != SQLITE_OK) {
786 syslog(LOG_ERR, "Failed to query hosts info from host " \
787 "database. Unable to destroy virtual machine (%s).",
788 NULL_MSGCHK(errmsg));
789 if (err == SMB_NIC_SUCCESS) {
790 /* set this error if no previous error */
791 err = SMB_NIC_DB_ERROR;
795 smb_nic_dbclose(db);
797 return (err);
800 static smb_hostifs_t *
801 smb_nic_iflist_decode(const char **values, int *err)
803 smb_hostifs_t *iflist;
804 char *host;
805 char *cmnt;
806 char *ifnames;
807 char *lasts;
808 char *ifname;
809 int if_num = 0;
811 host = (char *)values[SMB_NIC_HTBL_HOST];
812 cmnt = (char *)values[SMB_NIC_HTBL_CMNT];
813 ifnames = (char *)values[SMB_NIC_HTBL_IFS];
815 if ((host == NULL) || (ifnames == NULL)) {
816 *err = SMB_NIC_INVALID_ARG;
817 return (NULL);
820 iflist = malloc(sizeof (smb_hostifs_t));
821 if (iflist == NULL) {
822 *err = SMB_NIC_NO_MEMORY;
823 return (NULL);
826 bzero(iflist, sizeof (smb_hostifs_t));
828 (void) strlcpy(iflist->if_host, host, sizeof (iflist->if_host));
829 (void) strlcpy(iflist->if_cmnt, (cmnt) ? cmnt : "",
830 sizeof (iflist->if_cmnt));
832 if ((ifname = strtok_r(ifnames, ",", &lasts)) == NULL) {
833 *err = SMB_NIC_BAD_DATA;
834 return (NULL);
837 iflist->if_names[if_num++] = strdup(ifname);
839 while ((ifname = strtok_r(NULL, ",", &lasts)) != NULL)
840 iflist->if_names[if_num++] = strdup(ifname);
842 iflist->if_num = if_num;
844 for (if_num = 0; if_num < iflist->if_num; if_num++) {
845 if (iflist->if_names[if_num] == NULL) {
846 smb_nic_iflist_destroy(iflist);
847 *err = SMB_NIC_NO_MEMORY;
848 return (NULL);
852 *err = SMB_NIC_SUCCESS;
853 return (iflist);
857 * smb_nic_iflist_destroy
859 * Frees allocated memory for the given IF names lists.
861 static void
862 smb_nic_iflist_destroy(smb_hostifs_t *iflist)
864 int i;
866 if (iflist == NULL)
867 return;
869 for (i = 0; i < iflist->if_num; i++)
870 free(iflist->if_names[i]);
872 free(iflist);
876 * Functions to manage host/interface database
878 * Each entry in the hosts table associates a hostname with a
879 * list of interface names. The host/interface association could
880 * be added by calling smb_nic_addhost() and could be removed by
881 * calling smb_nic_delhost(). If the database exists and it contains
882 * valid information then the inteface list wouldn't be obtained
883 * from system using ioctl.
887 * smb_nic_dbcreate
889 * Creates the host database based on the defined SQL statement.
890 * It also initializes db_info table.
892 static int
893 smb_nic_dbcreate(void)
895 sqlite *db = NULL;
896 char *errmsg = NULL;
897 int rc, err = SMB_NIC_SUCCESS;
899 (void) unlink(SMB_NIC_DB_NAME);
901 db = sqlite_open(SMB_NIC_DB_NAME, 0600, &errmsg);
902 if (db == NULL) {
903 syslog(LOG_ERR, "Failed to create host database (%s).",
904 NULL_MSGCHK(errmsg));
905 sqlite_freemem(errmsg);
906 return (SMB_NIC_DBOPEN_FAILED);
909 sqlite_busy_timeout(db, SMB_NIC_DB_TIMEOUT);
910 rc = sqlite_exec(db, "BEGIN TRANSACTION", NULL, NULL, &errmsg);
911 if (rc != SQLITE_OK) {
912 syslog(LOG_ERR, "Failed to create host database. Unable to " \
913 "begin database transaction (%s).", NULL_MSGCHK(errmsg));
914 sqlite_freemem(errmsg);
915 sqlite_close(db);
916 return (SMB_NIC_DBEXEC_FAILED);
919 if (sqlite_exec(db, SMB_NIC_DB_SQL, NULL, NULL, &errmsg) == SQLITE_OK) {
920 rc = sqlite_exec(db, "COMMIT TRANSACTION", NULL, NULL,
921 &errmsg);
922 if (rc == SQLITE_OK)
923 err = smb_nic_dbsetinfo(db);
924 if (err != SMB_NIC_SUCCESS)
925 rc = sqlite_exec(db, "ROLLBACK TRANSACTION", NULL, NULL,
926 &errmsg);
927 } else {
928 syslog(LOG_ERR, "Failed to create host database. Unable to " \
929 "initialize host database (%s).", NULL_MSGCHK(errmsg));
930 sqlite_freemem(errmsg);
931 rc = sqlite_exec(db, "ROLLBACK TRANSACTION", NULL, NULL,
932 &errmsg);
935 if (rc != SQLITE_OK) {
936 /* this is bad - database may be left in a locked state */
937 syslog(LOG_ERR, "Failed to create host database. Unable to " \
938 "close a transaction (%s).", NULL_MSGCHK(errmsg));
939 sqlite_freemem(errmsg);
940 err = SMB_NIC_DBINIT_FAILED;
943 (void) sqlite_close(db);
944 return (err);
948 * smb_nic_dbopen
950 * Opens host database with the given mode.
952 static sqlite *
953 smb_nic_dbopen(int mode)
955 sqlite *db;
956 char *errmsg = NULL;
958 db = sqlite_open(SMB_NIC_DB_NAME, mode, &errmsg);
959 if (db == NULL) {
960 syslog(LOG_ERR, "Failed to open host database: %s (%s).",
961 SMB_NIC_DB_NAME, NULL_MSGCHK(errmsg));
962 sqlite_freemem(errmsg);
965 return (db);
969 * smb_nic_dbclose
971 * Closes the given database handle
973 static void
974 smb_nic_dbclose(sqlite *db)
976 if (db) {
977 sqlite_close(db);
981 static boolean_t
982 smb_nic_dbexists(void)
984 return (access(SMB_NIC_DB_NAME, F_OK) == 0);
987 static boolean_t
988 smb_nic_dbvalidate(void)
990 sqlite *db;
991 char *errmsg = NULL;
992 char *sql;
993 char **result;
994 int nrow, ncol;
995 boolean_t check = B_TRUE;
996 int rc;
998 sql = sqlite_mprintf("SELECT * FROM db_info");
999 if (sql == NULL)
1000 return (B_FALSE);
1002 db = smb_nic_dbopen(SMB_NIC_DB_ORW);
1003 if (db == NULL) {
1004 sqlite_freemem(sql);
1005 return (B_FALSE);
1008 rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg);
1009 sqlite_freemem(sql);
1011 if (rc != SQLITE_OK) {
1012 syslog(LOG_ERR, "Failed to validate host database. Unable " \
1013 "to get database information (%s).", NULL_MSGCHK(errmsg));
1014 sqlite_freemem(errmsg);
1015 smb_nic_dbclose(db);
1016 return (B_FALSE);
1019 if (nrow != 1 || ncol != 3) {
1020 syslog(LOG_ERR, "Failed to validate host database: bad " \
1021 "db_info table.");
1022 sqlite_free_table(result);
1023 smb_nic_dbclose(db);
1024 return (B_FALSE);
1027 if ((atoi(result[3]) != SMB_NIC_DB_VERMAJOR) ||
1028 (atoi(result[4]) != SMB_NIC_DB_VERMINOR) ||
1029 (atoi(result[5]) != SMB_NIC_DB_MAGIC)) {
1030 syslog(LOG_ERR, "Failed to validate host database: bad " \
1031 "db_info content.");
1032 sqlite_free_table(result);
1033 smb_nic_dbclose(db);
1034 return (B_FALSE);
1036 sqlite_free_table(result);
1038 sql = sqlite_mprintf("SELECT hostname FROM hosts");
1039 if (sql == NULL) {
1040 smb_nic_dbclose(db);
1041 return (B_FALSE);
1044 rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg);
1045 sqlite_freemem(sql);
1047 if (rc != SQLITE_OK) {
1048 syslog(LOG_ERR, "Failed to validate host database. Unable " \
1049 "to query for host (%s).", NULL_MSGCHK(errmsg));
1050 sqlite_freemem(errmsg);
1051 smb_nic_dbclose(db);
1052 return (B_FALSE);
1055 sqlite_free_table(result);
1057 if (nrow == 0)
1058 /* No hosts in the database */
1059 check = B_FALSE;
1061 smb_nic_dbclose(db);
1062 return (check);
1065 static int
1066 smb_nic_dbaddhost(const char *host, const char *cmnt, char *if_list)
1068 sqlite *db;
1069 char *sql;
1070 char *errmsg;
1071 int rc, err = SMB_NIC_SUCCESS;
1073 sql = sqlite_mprintf("REPLACE INTO hosts (hostname, comment, ifnames)"
1074 "VALUES ('%s', '%q', '%s')", host, (cmnt) ? cmnt : "", if_list);
1075 if (sql == NULL)
1076 return (SMB_NIC_NO_MEMORY);
1078 db = smb_nic_dbopen(SMB_NIC_DB_ORW);
1079 if (db == NULL) {
1080 sqlite_freemem(sql);
1081 return (SMB_NIC_DBOPEN_FAILED);
1084 rc = sqlite_exec(db, sql, NULL, NULL, &errmsg);
1085 sqlite_freemem(sql);
1086 smb_nic_dbclose(db);
1088 if (rc != SQLITE_OK) {
1089 syslog(LOG_ERR, "Failed to add host %s to host database (%s).",
1090 host, NULL_MSGCHK(errmsg));
1091 sqlite_freemem(errmsg);
1092 err = SMB_NIC_INSERT_FAILED;
1095 return (err);
1098 static int
1099 smb_nic_dbdelhost(const char *host)
1101 sqlite *db;
1102 char *sql;
1103 char *errmsg;
1104 int rc, err = SMB_NIC_SUCCESS;
1106 sql = sqlite_mprintf("DELETE FROM hosts WHERE hostname = '%s'", host);
1107 if (sql == NULL)
1108 return (SMB_NIC_NO_MEMORY);
1110 db = smb_nic_dbopen(SMB_NIC_DB_ORW);
1111 if (db == NULL) {
1112 sqlite_freemem(sql);
1113 return (SMB_NIC_DBOPEN_FAILED);
1116 rc = sqlite_exec(db, sql, NULL, NULL, &errmsg);
1117 sqlite_freemem(sql);
1118 smb_nic_dbclose(db);
1120 if (rc != SQLITE_OK) {
1121 syslog(LOG_ERR, "Failed to delete host %s from host " \
1122 "database (%s).", host, NULL_MSGCHK(errmsg));
1123 sqlite_freemem(errmsg);
1124 err = SMB_NIC_DELETE_FAILED;
1127 return (err);
1131 * smb_nic_dbsetinfo
1133 * Initializes the db_info table upon database creation.
1135 static int
1136 smb_nic_dbsetinfo(sqlite *db)
1138 char *errmsg = NULL;
1139 char *sql;
1140 int rc, err = SMB_NIC_SUCCESS;
1142 sql = sqlite_mprintf("INSERT INTO db_info (ver_major, ver_minor,"
1143 " magic) VALUES (%d, %d, %d)", SMB_NIC_DB_VERMAJOR,
1144 SMB_NIC_DB_VERMINOR, SMB_NIC_DB_MAGIC);
1146 if (sql == NULL)
1147 return (SMB_NIC_NO_MEMORY);
1149 rc = sqlite_exec(db, sql, NULL, NULL, &errmsg);
1150 sqlite_freemem(sql);
1151 if (rc != SQLITE_OK) {
1152 syslog(LOG_ERR, "Failed to add database information to " \
1153 "host database (%s).", NULL_MSGCHK(errmsg));
1154 sqlite_freemem(errmsg);
1155 err = SMB_NIC_DBINIT_ERROR;
1158 return (err);
1162 * smb_nic_nbt_get_exclude_list
1164 * Construct an array containing list of i/f names on which NetBIOS traffic is
1165 * to be disabled, from a string containing a list of comma separated i/f names.
1167 * Returns the number of i/f on which NetBIOS traffic is to be disabled.
1169 static int
1170 smb_nic_nbt_get_exclude_list(char *excludestr, char **iflist, int max_nifs)
1172 int n = 0;
1173 char *entry;
1175 bzero(iflist, SMB_PI_MAX_NETWORKS * sizeof (char *));
1177 (void) trim_whitespace(excludestr);
1178 (void) strcanon(excludestr, ",");
1180 if (*excludestr == '\0')
1181 return (0);
1183 while (((iflist[n] = strsep(&excludestr, ",")) != NULL) &&
1184 (n < max_nifs)) {
1185 entry = iflist[n];
1186 if (*entry == '\0')
1187 continue;
1188 n++;
1191 return (n);
1195 * smb_nic_nbt_exclude
1197 * Check to see if the given interface name should send NetBIOS traffic or not.
1199 * Returns TRUE if NetBIOS traffic is disabled on an interface name.
1200 * Returns FALSE otherwise.
1202 static boolean_t
1203 smb_nic_nbt_exclude(const smb_nic_t *nc, const char **exclude_list,
1204 int nexclude)
1206 char buf[INET6_ADDRSTRLEN];
1207 const char *ifname = nc->nic_ifname;
1208 int i;
1210 if (inet_ntop(AF_INET, &nc->nic_ip, buf, INET6_ADDRSTRLEN) == NULL)
1211 buf[0] = '\0';
1213 for (i = 0; i < nexclude; i++) {
1214 if (strcmp(ifname, exclude_list[i]) == 0)
1215 return (B_TRUE);
1217 if ((buf[0] != '\0') && (strcmp(buf, exclude_list[i]) == 0))
1218 return (B_TRUE);
1221 return (B_FALSE);