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]
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.
42 #include <netinet/in.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," \
70 "CREATE TABLE hosts (" \
71 " hostname TEXT PRIMARY KEY," \
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
{
88 char if_host
[MAXHOSTNAMELEN
];
89 char if_cmnt
[SMB_PI_MAX_COMMENT
];
90 char *if_names
[SMB_NIC_MAXIFS
];
94 typedef struct smb_hosts
{
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 */
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
;
141 * Initializes the interface list.
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
);
159 * Destroys the interface list.
164 (void) rw_wrlock(&smb_niclist
.nl_rwl
);
165 smb_nic_list_destroy();
166 (void) rw_unlock(&smb_niclist
.nl_rwl
);
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
178 smb_nic_getnum(char *nb_hostname
)
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)
192 n
= smb_niclist
.nl_cnt
;
195 (void) rw_unlock(&smb_niclist
.nl_rwl
);
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
;
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];
224 ni
->ni_seqnum
= smb_niclist
.nl_seqnum
;
226 rc
= SMB_NIC_NOT_FOUND
;
229 (void) rw_unlock(&smb_niclist
.nl_rwl
);
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
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
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
];
265 if (smb_niclist
.nl_seqnum
!= ni
->ni_seqnum
)
266 rc
= SMB_NIC_CHANGED
;
268 rc
= SMB_NIC_NO_MORE
;
271 (void) rw_unlock(&smb_niclist
.nl_rwl
);
277 smb_nic_is_local(smb_inaddr_t
*ipaddr
)
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
);
291 (void) rw_unlock(&smb_niclist
.nl_rwl
);
296 smb_nic_is_same_subnet(smb_inaddr_t
*ipaddr
)
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
);
310 (void) rw_unlock(&smb_niclist
.nl_rwl
);
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
)
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
)
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
);
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
);
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
402 smb_nic_list_create(void)
405 smb_hostifs_t
*iflist
;
408 char excludestr
[SMB_NIC_MAXEXCLLIST_LEN
];
409 char *exclude
[SMB_PI_MAX_NETWORKS
];
413 if ((rc
= smb_nic_hlist_create(&hlist
)) != SMB_NIC_SUCCESS
)
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
);
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
);
437 for (i
= 0; i
< iflist
->if_num
; i
++) {
438 ifname
= iflist
->if_names
[i
];
439 if (smb_nic_getinfo(ifname
, nc
, AF_INET
) !=
441 if (smb_nic_getinfo(ifname
, nc
,
442 AF_INET6
) != SMB_NIC_SUCCESS
) {
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
++;
464 } while ((iflist
= list_next(&hlist
.h_list
, iflist
)) != NULL
);
466 smb_nic_hlist_destroy(&hlist
);
468 return (SMB_NIC_SUCCESS
);
472 smb_nic_list_destroy(void)
474 free(smb_niclist
.nl_nics
);
475 smb_niclist
.nl_nics
= NULL
;
476 smb_niclist
.nl_cnt
= 0;
480 smb_nic_getinfo(char *interface
, smb_nic_t
*nc
, int family
)
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) {
495 return (SMB_NIC_IOCTL
);
497 isv6
= (lifrr
.lifr_addr
.ss_family
== AF_INET6
);
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
;
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
)) {
509 return (SMB_NIC_BAD_DATA
);
511 /* there is no broadcast or netmask for v6 */
513 if (ioctl(s
, SIOCGLIFBRDADDR
, &lifrr
) < 0) {
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) {
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) {
529 return (SMB_NIC_IOCTL
);
531 nc
->nic_sysflags
= lifrr
.lifr_flags
;
533 (void) strlcpy(nc
->nic_ifname
, interface
, sizeof (nc
->nic_ifname
));
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()
550 smb_nic_hlist_create(smb_hosts_t
*hlist
)
554 list_create(&hlist
->h_list
, sizeof (smb_hostifs_t
),
555 offsetof(smb_hostifs_t
, if_lnd
));
559 if (smb_nic_dbexists() && smb_nic_dbvalidate()) {
560 rc
= smb_nic_hlist_dbget(hlist
);
563 rc
= smb_nic_hlist_sysget(hlist
);
566 if (rc
!= SMB_NIC_SUCCESS
)
567 smb_nic_hlist_destroy(hlist
);
573 smb_nic_hlist_destroy(smb_hosts_t
*hlist
)
575 smb_hostifs_t
*iflist
;
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
);
589 smb_close_sockets(int s4
, int s6
)
598 * smb_nic_hlist_sysget
600 * Get the list of currently plumbed and up interface names. The loopback (lo0)
604 smb_nic_hlist_sysget(smb_hosts_t
*hlist
)
606 smb_hostifs_t
*iflist
;
609 struct lifreq
*lifrp
;
616 iflist
= malloc(sizeof (smb_hostifs_t
));
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) {
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) {
633 return (SMB_NIC_SOCK
);
635 s6
= socket(AF_INET6
, SOCK_DGRAM
, 0);
637 lifn
.lifn_family
= AF_UNSPEC
;
639 if (ioctl(s4
, SIOCGLIFNUM
, (char *)&lifn
) < 0) {
640 smb_close_sockets(s4
, s6
);
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
);
651 return (SMB_NIC_NO_MEMORY
);
653 bzero(lifc
.lifc_buf
, lifc
.lifc_len
);
654 lifc
.lifc_family
= AF_UNSPEC
;
657 if (ioctl(s4
, SIOCGLIFCONF
, (char *)&lifc
) < 0) {
658 smb_close_sockets(s4
, s6
);
661 return (SMB_NIC_IOCTL
);
664 lifrp
= lifc
.lifc_req
;
665 ifnum
= lifc
.lifc_len
/ sizeof (struct lifreq
);
667 for (i
= 0; i
< ifnum
; i
++, lifrp
++) {
669 if ((iflist
->if_num
> 0) && smb_duplicate_nic(iflist
, lifrp
))
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) {
680 (ioctl(s6
, SIOCGLIFFLAGS
, (caddr_t
)&lifrl
) < 0)) {
681 smb_close_sockets(s4
, s6
);
683 smb_nic_iflist_destroy(iflist
);
684 return (SMB_NIC_IOCTL
);
687 if (lifrl
.lifr_flags
& IFF_LOOPBACK
) {
691 if ((lifrl
.lifr_flags
& IFF_UP
) == 0) {
694 ifname
= strdup(lifrp
->lifr_name
);
695 if (ifname
== NULL
) {
696 smb_close_sockets(s4
, s6
);
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
;
705 smb_close_sockets(s4
, s6
);
707 list_insert_tail(&hlist
->h_list
, iflist
);
709 return (SMB_NIC_SUCCESS
);
713 smb_duplicate_nic(smb_hostifs_t
*iflist
, struct lifreq
*lifrp
)
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)
728 smb_nic_hlist_dbget(smb_hosts_t
*hlist
)
730 smb_hostifs_t
*iflist
;
733 int err
= SMB_NIC_SUCCESS
;
739 sql
= sqlite_mprintf("SELECT * FROM hosts");
741 return (SMB_NIC_NO_MEMORY
);
743 db
= smb_nic_dbopen(SMB_NIC_DB_ORD
);
746 return (SMB_NIC_DBOPEN_FAILED
);
749 rc
= sqlite_compile(db
, sql
, NULL
, &vm
, &errmsg
);
752 if (rc
!= SQLITE_OK
) {
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
);
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
;
768 if ((iflist
= smb_nic_iflist_decode(values
, &err
)) ==
773 list_insert_tail(&hlist
->h_list
, iflist
);
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
;
800 static smb_hostifs_t
*
801 smb_nic_iflist_decode(const char **values
, int *err
)
803 smb_hostifs_t
*iflist
;
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
;
820 iflist
= malloc(sizeof (smb_hostifs_t
));
821 if (iflist
== NULL
) {
822 *err
= SMB_NIC_NO_MEMORY
;
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
;
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
;
852 *err
= SMB_NIC_SUCCESS
;
857 * smb_nic_iflist_destroy
859 * Frees allocated memory for the given IF names lists.
862 smb_nic_iflist_destroy(smb_hostifs_t
*iflist
)
869 for (i
= 0; i
< iflist
->if_num
; i
++)
870 free(iflist
->if_names
[i
]);
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.
889 * Creates the host database based on the defined SQL statement.
890 * It also initializes db_info table.
893 smb_nic_dbcreate(void)
897 int rc
, err
= SMB_NIC_SUCCESS
;
899 (void) unlink(SMB_NIC_DB_NAME
);
901 db
= sqlite_open(SMB_NIC_DB_NAME
, 0600, &errmsg
);
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
);
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
,
923 err
= smb_nic_dbsetinfo(db
);
924 if (err
!= SMB_NIC_SUCCESS
)
925 rc
= sqlite_exec(db
, "ROLLBACK TRANSACTION", NULL
, NULL
,
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
,
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
);
950 * Opens host database with the given mode.
953 smb_nic_dbopen(int mode
)
958 db
= sqlite_open(SMB_NIC_DB_NAME
, mode
, &errmsg
);
960 syslog(LOG_ERR
, "Failed to open host database: %s (%s).",
961 SMB_NIC_DB_NAME
, NULL_MSGCHK(errmsg
));
962 sqlite_freemem(errmsg
);
971 * Closes the given database handle
974 smb_nic_dbclose(sqlite
*db
)
982 smb_nic_dbexists(void)
984 return (access(SMB_NIC_DB_NAME
, F_OK
) == 0);
988 smb_nic_dbvalidate(void)
995 boolean_t check
= B_TRUE
;
998 sql
= sqlite_mprintf("SELECT * FROM db_info");
1002 db
= smb_nic_dbopen(SMB_NIC_DB_ORW
);
1004 sqlite_freemem(sql
);
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
);
1019 if (nrow
!= 1 || ncol
!= 3) {
1020 syslog(LOG_ERR
, "Failed to validate host database: bad " \
1022 sqlite_free_table(result
);
1023 smb_nic_dbclose(db
);
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
);
1036 sqlite_free_table(result
);
1038 sql
= sqlite_mprintf("SELECT hostname FROM hosts");
1040 smb_nic_dbclose(db
);
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
);
1055 sqlite_free_table(result
);
1058 /* No hosts in the database */
1061 smb_nic_dbclose(db
);
1066 smb_nic_dbaddhost(const char *host
, const char *cmnt
, char *if_list
)
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
);
1076 return (SMB_NIC_NO_MEMORY
);
1078 db
= smb_nic_dbopen(SMB_NIC_DB_ORW
);
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
;
1099 smb_nic_dbdelhost(const char *host
)
1104 int rc
, err
= SMB_NIC_SUCCESS
;
1106 sql
= sqlite_mprintf("DELETE FROM hosts WHERE hostname = '%s'", host
);
1108 return (SMB_NIC_NO_MEMORY
);
1110 db
= smb_nic_dbopen(SMB_NIC_DB_ORW
);
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
;
1133 * Initializes the db_info table upon database creation.
1136 smb_nic_dbsetinfo(sqlite
*db
)
1138 char *errmsg
= NULL
;
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
);
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
;
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.
1170 smb_nic_nbt_get_exclude_list(char *excludestr
, char **iflist
, int max_nifs
)
1175 bzero(iflist
, SMB_PI_MAX_NETWORKS
* sizeof (char *));
1177 (void) trim_whitespace(excludestr
);
1178 (void) strcanon(excludestr
, ",");
1180 if (*excludestr
== '\0')
1183 while (((iflist
[n
] = strsep(&excludestr
, ",")) != NULL
) &&
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.
1203 smb_nic_nbt_exclude(const smb_nic_t
*nc
, const char **exclude_list
,
1206 char buf
[INET6_ADDRSTRLEN
];
1207 const char *ifname
= nc
->nic_ifname
;
1210 if (inet_ntop(AF_INET
, &nc
->nic_ip
, buf
, INET6_ADDRSTRLEN
) == NULL
)
1213 for (i
= 0; i
< nexclude
; i
++) {
1214 if (strcmp(ifname
, exclude_list
[i
]) == 0)
1217 if ((buf
[0] != '\0') && (strcmp(buf
, exclude_list
[i
]) == 0))