/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <libintl.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <synch.h>
#include <stropts.h>
#include <errno.h>
#include <pthread.h>
#include <netdb.h>
#include <sqlite3.h>
#include <sys/systeminfo.h>
#define SMB_NIC_DB_VERMINOR 0
#define SMB_NIC_DB_SQL \
"CREATE TABLE db_info (" \
" ver_major INTEGER," \
" ver_minor INTEGER," \
" magic INTEGER" \
");" \
"" \
"CREATE TABLE hosts (" \
" hostname TEXT PRIMARY KEY," \
" comment TEXT," \
" ifnames TEXT" \
");"
#define SMB_NIC_HTBL_HOST 0
typedef struct smb_hostifs {
char **if_names;
int if_num;
typedef struct smb_hosts {
int h_num;
int h_ifnum;
} smb_hosts_t;
typedef struct {
static int smb_nic_list_create(void);
static void smb_nic_list_destroy(void);
static int smb_nic_hlist_create(smb_hosts_t *);
static void smb_nic_hlist_destroy(smb_hosts_t *);
static int smb_nic_hlist_dbget(smb_hosts_t *);
static int smb_nic_hlist_sysget(smb_hosts_t *);
static smb_hostifs_t *smb_nic_iflist_create(const char *, const char *, int);
static void smb_nic_iflist_destroy(smb_hostifs_t *);
static int smb_nic_dbcreate(void);
static sqlite3 *smb_nic_dbopen(int);
static void smb_nic_dbclose(sqlite3 *);
static boolean_t smb_nic_dbexists(void);
static boolean_t smb_nic_dbvalidate(void);
static int smb_nic_dbaddhost(const char *, const char *, char *);
static int smb_nic_dbdelhost(const char *);
static int smb_nic_dbsetinfo(sqlite3 *);
static int smb_nic_getinfo(char *, smb_nic_t *, int);
static int smb_nic_nbt_get_exclude_list(char *, char **, int);
static void smb_close_sockets(int, int);
/* This is the list we will monitor */
/*
* smb_nic_init
*
* Initializes the interface list.
*/
int
smb_nic_init(void)
{
int rc;
rc = smb_nic_list_create();
return (rc);
}
/*
* smb_nic_fini
*
* Destroys the interface list.
*/
void
smb_nic_fini(void)
{
}
/*
* smb_nic_getnum
*
* Gets the number of interfaces for the specified host.
* if host is NULL then total number of interfaces
* is returned. It's assumed that given name is a NetBIOS
* encoded name.
*/
int
{
int n = 0, i;
if (nb_hostname != NULL) {
for (i = 0; i < smb_niclist.nl_cnt; i++) {
/* ignore the suffix */
n++;
}
} else {
n = smb_niclist.nl_cnt;
}
return (n);
}
/*
* smb_nic_getfirst
*
* Returns the first NIC in the interface list and
* initializes the given iterator. To get the rest of
* NICs smb_nic_getnext() must be called.
*
* Returns SMB_NIC_SUCCESS upon success or the following:
* SMB_NIC_NOT_FOUND - there's no interface available
* SMB_NIC_INVALID_ARG - 'ni' is NULL
*/
int
{
return (SMB_NIC_INVALID_ARG);
if (smb_niclist.nl_cnt > 0) {
} else {
}
return (rc);
}
/*
* smb_nic_getnext
*
* Returns the next NIC information based on the passed
* iterator (ni). The iterator must have previously been
* initialized by calling smb_nic_getfirst().
*
* Returns SMB_NIC_SUCCESS upon successfully finding the specified NIC
* or the following:
* SMB_NIC_INVALID_ARG - the specified iterator is invalid
* SMB_NIC_NO_MORE - reaches the end of the NIC list
* SMB_NIC_CHANGED - sequence number in the iterator is different from
* the sequence number in the NIC list which means
* calls.
*/
int
{
return (SMB_NIC_INVALID_ARG);
} else {
else
}
return (rc);
}
{
int i;
for (i = 0; i < smb_niclist.nl_cnt; i++) {
return (B_TRUE);
}
}
return (B_FALSE);
}
{
int i;
for (i = 0; i < smb_niclist.nl_cnt; i++) {
return (B_TRUE);
}
}
return (B_FALSE);
}
/*
* smb_nic_addhost
*
* Adds an association between the given host and the specified interface
* list (if_names). This function can be called as many times as needed,
* the associations will be stored in /var/smb/smbhosts_v3.db, which is sqlite
* database. If this file exists and it's not empty NIC list is generated
* based on the information stored in this file.
*
* host: actual system's name (not Netbios name)
* cmnt: an optional description for the server running on
* the specified host. Can be NULL.
* if_num: number of interface names in if_names arg
* if_names: array of interface names in string format
*
* Returns SMB_NIC_SUCCESS upon success, a nonzero value otherwise.
*/
int
{
char *if_list;
char *ifname;
int buflen = 0;
int rc, i;
return (SMB_NIC_INVALID_ARG);
if (!smb_nic_dbexists() || !smb_nic_dbvalidate()) {
return (rc);
}
for (i = 0; i < if_num; i++) {
return (SMB_NIC_INVALID_ARG);
}
return (SMB_NIC_NO_MEMORY);
for (i = 0; i < if_num - 1; i++)
return (rc);
}
/*
* smb_nic_delhost
*
* Removes the stored interface association for the specified host
*/
int
{
return (SMB_NIC_INVALID_ARG);
if (!smb_nic_dbexists())
return (SMB_NIC_SUCCESS);
if (!smb_nic_dbvalidate()) {
(void) unlink(SMB_NIC_DB_NAME);
return (SMB_NIC_SUCCESS);
}
return (smb_nic_dbdelhost(host));
}
/*
* smb_nic_list_create
*
* Creates a NIC list either based on /var/smb/smbhosts_v3.db or
* by getting the information from OS.
*
* Note that the caller of this function should grab the
* list lock.
*/
static int
smb_nic_list_create(void)
{
char *ifname;
int nexclude = 0;
int i, rc;
return (rc);
smb_niclist.nl_cnt = 0;
return (SMB_NIC_NO_MEMORY);
}
*excludestr = '\0';
(void) smb_config_getstr(SMB_CI_WINS_EXCL,
excludestr, sizeof (excludestr));
do {
AF_INET6) != SMB_NIC_SUCCESS) {
continue;
}
}
if (smb_nic_nbt_exclude(nc,
nc++;
}
return (SMB_NIC_SUCCESS);
}
static void
smb_nic_list_destroy(void)
{
smb_niclist.nl_cnt = 0;
}
static int
{
int s;
return (SMB_NIC_SOCK);
}
(void) close(s);
return (SMB_NIC_IOCTL);
}
if (isv6) {
} else {
}
(void) close(s);
return (SMB_NIC_BAD_DATA);
}
/* there is no broadcast or netmask for v6 */
if (!isv6) {
(void) close(s);
return (SMB_NIC_IOCTL);
}
(void) close(s);
return (SMB_NIC_IOCTL);
}
}
(void) close(s);
return (SMB_NIC_IOCTL);
}
(void) close(s);
return (SMB_NIC_SUCCESS);
}
/*
* smb_nic_hlist_create
*
* Creates a list of hosts and their associated interfaces.
* If host database exists the information is retrieved from
* the database, otherwise it's retrieved from OS.
*
* The allocated memories for the returned list should be freed
* by calling smb_nic_hlist_destroy()
*/
static int
{
int rc;
if (smb_nic_dbexists() && smb_nic_dbvalidate()) {
} else {
}
if (rc != SMB_NIC_SUCCESS)
return (rc);
}
static void
{
return;
}
}
static void
{
if (s4)
if (s6)
}
/*
* smb_nic_hlist_sysget
*
* Get the list of currently plumbed and up interface names. The loopback (lo0)
* port is ignored
*/
static int
{
char *ifname;
int ifnum;
return (SMB_NIC_SOCK);
lifn.lifn_flags = 0;
return (SMB_NIC_IOCTL);
}
return (SMB_NIC_NO_MEMORY);
}
lifc.lifc_flags = 0;
return (SMB_NIC_IOCTL);
}
return (SMB_NIC_NO_HOST);
}
return (SMB_NIC_NO_MEMORY);
}
continue;
/* Skip loopback and down interfaces */
continue;
return (SMB_NIC_NO_MEMORY);
}
}
return (SMB_NIC_SUCCESS);
}
/*
* Returns B_TRUE if the specified interface (lifrp) is in the
* given list (iflist)
*/
static boolean_t
{
int j;
return (B_TRUE);
return (B_FALSE);
}
/*
* Returns the flags for the specified interface
*/
static uint64_t
{
if (s6 < 0)
return (0);
return (0);
}
return (lifrl.lifr_flags);
}
static int
{
char *sql;
return (SMB_NIC_NO_MEMORY);
return (SMB_NIC_DBOPEN_FAILED);
}
"database. Unable to create prepared statement (%s).",
return (SMB_NIC_DB_ERROR);
}
do {
if (rc == SQLITE_ROW) {
if (ncol != SMB_NIC_HTBL_NCOL) {
break;
}
break;
}
} while (rc == SQLITE_ROW);
/* set this error if no previous error */
}
"database. Unable to destroy virtual machine (%s).",
if (err == SMB_NIC_SUCCESS) {
/* set this error if no previous error */
}
}
return (err);
}
/*
* Host database record contains a hostname, a comment and a
* comma separated list of interface names.
*/
static smb_hostifs_t *
{
const char *host;
const char *cmnt;
const char *ifnames;
char *ifname;
int if_num;
return (NULL);
}
/* # interfaces = # commas + 1 */
if (*ifnames == ',')
if_num++;
*err = SMB_NIC_NO_MEMORY;
return (NULL);
}
}
*err = SMB_NIC_NO_MEMORY;
return (NULL);
}
}
*err = SMB_NIC_SUCCESS;
return (iflist);
}
/*
* Allocates and initializes a smb_hostifs_t structure.
* An array of "char *" is allocated for the given number (if_num)
* of interface names. This array may end up having less interfaces
* than 'if_num'. iflist->if_num indicates the actual number of interfaces
* in iflist->if_names array so it's initialized to 0.
*/
static smb_hostifs_t *
{
return (NULL);
return (NULL);
}
return (iflist);
}
/*
* smb_nic_iflist_destroy
*
* Frees allocated memory for the given IF names lists.
*/
static void
{
int i;
return;
}
}
/*
*
* Each entry in the hosts table associates a hostname with a
* be added by calling smb_nic_addhost() and could be removed by
* calling smb_nic_delhost(). If the database exists and it contains
* valid information then the inteface list wouldn't be obtained
* from system using ioctl.
*/
/*
* smb_nic_dbcreate
*
* Creates the host database based on the defined SQL statement.
* It also initializes db_info table.
*/
static int
smb_nic_dbcreate(void)
{
int ret;
(void) unlink(SMB_NIC_DB_NAME);
(void) sqlite3_close(db);
return (SMB_NIC_DBOPEN_FAILED);
}
(void) sqlite3_close(db);
return (SMB_NIC_DBEXEC_FAILED);
}
&errmsg);
if (err != SMB_NIC_SUCCESS)
} else {
&errmsg);
}
/* this is bad - database may be left in a locked state */
}
(void) sqlite3_close(db);
return (err);
}
/*
* smb_nic_dbopen
*
* Opens host database with the given mode.
*/
static sqlite3 *
{
int err;
(void) sqlite3_close(db);
}
return (db);
}
/*
* smb_nic_dbclose
*
* Closes the given database handle
*/
static void
{
if (db) {
(void) sqlite3_close(db);
}
}
static boolean_t
smb_nic_dbexists(void)
{
}
static boolean_t
smb_nic_dbvalidate(void)
{
char *sql;
char **result;
int rc;
return (B_FALSE);
return (B_FALSE);
}
return (B_FALSE);
}
"db_info table.");
return (B_FALSE);
}
"db_info content.");
return (B_FALSE);
}
return (B_FALSE);
}
return (B_FALSE);
}
if (nrow == 0)
/* No hosts in the database */
return (check);
}
static int
{
char *sql;
char *errmsg;
return (SMB_NIC_NO_MEMORY);
return (SMB_NIC_DBOPEN_FAILED);
}
}
return (err);
}
static int
{
char *sql;
char *errmsg;
return (SMB_NIC_NO_MEMORY);
return (SMB_NIC_DBOPEN_FAILED);
}
}
return (err);
}
/*
* smb_nic_dbsetinfo
*
* Initializes the db_info table upon database creation.
*/
static int
{
char *sql;
" magic) VALUES (%d, %d, %d)", SMB_NIC_DB_VERMAJOR,
return (SMB_NIC_NO_MEMORY);
}
return (err);
}
/*
* smb_nic_nbt_get_exclude_list
*
* Construct an array containing list of i/f names on which NetBIOS traffic is
* to be disabled, from a string containing a list of comma separated i/f names.
*
* Returns the number of i/f on which NetBIOS traffic is to be disabled.
*/
static int
{
int n = 0;
char *entry;
(void) trim_whitespace(excludestr);
if (*excludestr == '\0')
return (0);
(n < max_nifs)) {
if (*entry == '\0')
continue;
n++;
}
return (n);
}
/*
* smb_nic_nbt_exclude
*
* Check to see if the given interface name should send NetBIOS traffic or not.
*
* Returns TRUE if NetBIOS traffic is disabled on an interface name.
* Returns FALSE otherwise.
*/
static boolean_t
int nexclude)
{
int i;
buf[0] = '\0';
for (i = 0; i < nexclude; i++) {
return (B_TRUE);
return (B_TRUE);
}
return (B_FALSE);
}