xref: /onnv-gate/usr/src/lib/smbsrv/libsmb/common/smb_util.c (revision 12508:edb7861a1533)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
22*12508Samw@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
235331Samw  */
245331Samw 
255331Samw #include <ctype.h>
265331Samw #include <stdio.h>
27*12508Samw@Sun.COM #include <stdarg.h>
28*12508Samw@Sun.COM #include <unistd.h>
29*12508Samw@Sun.COM #include <sys/fcntl.h>
305331Samw #include <string.h>
3110122SJordan.Brown@Sun.COM #include <strings.h>
325331Samw #include <stdlib.h>
335331Samw #include <pthread.h>
345331Samw #include <sys/varargs.h>
355331Samw #include <sys/types.h>
368871Samw@Sun.COM #include <sys/mnttab.h>
377961SNatalie.Li@Sun.COM #include <tiuser.h>
387961SNatalie.Li@Sun.COM #include <netconfig.h>
397961SNatalie.Li@Sun.COM #include <netdir.h>
407961SNatalie.Li@Sun.COM #include <sys/systeminfo.h>
417961SNatalie.Li@Sun.COM #include <sys/utsname.h>
428871Samw@Sun.COM #include <libzfs.h>
4310122SJordan.Brown@Sun.COM #include <dlfcn.h>
44*12508Samw@Sun.COM #include <time.h>
45*12508Samw@Sun.COM #include <syslog.h>
468871Samw@Sun.COM #include <smbsrv/string.h>
478871Samw@Sun.COM #include <smbsrv/libsmb.h>
487961SNatalie.Li@Sun.COM 
4910122SJordan.Brown@Sun.COM #define	SMB_LIB_ALT	"/usr/lib/smbsrv/libsmbex.so"
5010122SJordan.Brown@Sun.COM 
51*12508Samw@Sun.COM #define	SMB_TIMEBUF_SZ		16
52*12508Samw@Sun.COM #define	SMB_TRACEBUF_SZ		200
53*12508Samw@Sun.COM 
54*12508Samw@Sun.COM #define	SMB_LOG_FILE_FMT	"/var/smb/%s_log.txt"
55*12508Samw@Sun.COM 
56*12508Samw@Sun.COM typedef struct smb_log_pri {
57*12508Samw@Sun.COM 	char	*lp_name;
58*12508Samw@Sun.COM 	int	lp_value;
59*12508Samw@Sun.COM } smb_log_pri_t;
60*12508Samw@Sun.COM 
61*12508Samw@Sun.COM static smb_log_pri_t smb_log_pri[] = {
62*12508Samw@Sun.COM 	"panic",	LOG_EMERG,
63*12508Samw@Sun.COM 	"emerg",	LOG_EMERG,
64*12508Samw@Sun.COM 	"alert",	LOG_ALERT,
65*12508Samw@Sun.COM 	"crit",		LOG_CRIT,
66*12508Samw@Sun.COM 	"error",	LOG_ERR,
67*12508Samw@Sun.COM 	"err",		LOG_ERR,
68*12508Samw@Sun.COM 	"warn",		LOG_WARNING,
69*12508Samw@Sun.COM 	"warning",	LOG_WARNING,
70*12508Samw@Sun.COM 	"notice",	LOG_NOTICE,
71*12508Samw@Sun.COM 	"info",		LOG_INFO,
72*12508Samw@Sun.COM 	"debug",	LOG_DEBUG
73*12508Samw@Sun.COM };
74*12508Samw@Sun.COM 
75*12508Samw@Sun.COM static void smb_log_trace(int, const char *);
76*12508Samw@Sun.COM static smb_log_t *smb_log_get(smb_log_hdl_t);
77*12508Samw@Sun.COM static void smb_log_dump(smb_log_t *);
78*12508Samw@Sun.COM 
797961SNatalie.Li@Sun.COM static uint_t smb_make_mask(char *, uint_t);
807961SNatalie.Li@Sun.COM static boolean_t smb_netmatch(struct netbuf *, char *);
817961SNatalie.Li@Sun.COM static boolean_t smb_netgroup_match(struct nd_hostservlist *, char *, int);
827961SNatalie.Li@Sun.COM 
837961SNatalie.Li@Sun.COM extern  int __multi_innetgr();
847961SNatalie.Li@Sun.COM extern int __netdir_getbyaddr_nosrv(struct netconfig *,
857961SNatalie.Li@Sun.COM     struct nd_hostservlist **, struct netbuf *);
865331Samw 
87*12508Samw@Sun.COM static smb_loglist_t smb_loglist;
88*12508Samw@Sun.COM 
895331Samw #define	C2H(c)		"0123456789ABCDEF"[(c)]
905331Samw #define	H2C(c)    (((c) >= '0' && (c) <= '9') ? ((c) - '0') :     \
915331Samw 	((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) :         \
925331Samw 	((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) :         \
935331Samw 	'\0')
945331Samw #define	DEFAULT_SBOX_SIZE		256
955331Samw 
965331Samw /*
975331Samw  *
985331Samw  * hexdump
995331Samw  *
1005331Samw  * Simple hex dump display function. Displays nbytes of buffer in hex and
1015331Samw  * printable format. Non-printing characters are shown as '.'. It is safe
1025331Samw  * to pass a null pointer. Each line begins with the offset. If nbytes is
1035331Samw  * 0, the line will be blank except for the offset. Example output:
1045331Samw  *
1055331Samw  * 00000000  54 68 69 73 20 69 73 20 61 20 70 72 6F 67 72 61  This is a progra
1065331Samw  * 00000010  6D 20 74 65 73 74 2E 00                          m test..
1075331Samw  *
1085331Samw  */
1095331Samw void
hexdump_offset(unsigned char * buffer,int nbytes,unsigned long * start)1105772Sas200622 hexdump_offset(unsigned char *buffer, int nbytes, unsigned long *start)
1115331Samw {
1125331Samw 	static char *hex = "0123456789ABCDEF";
1135331Samw 	int i, count;
1145331Samw 	int offset;
1155331Samw 	unsigned char *p;
1165331Samw 	char ascbuf[64];
1175331Samw 	char hexbuf[64];
1185331Samw 	char *ap = ascbuf;
1195331Samw 	char *hp = hexbuf;
1205331Samw 
1215772Sas200622 	if ((p = buffer) == NULL)
1225331Samw 		return;
1235331Samw 
1245331Samw 	offset = *start;
1255331Samw 
1265331Samw 	*ap = '\0';
1275331Samw 	*hp = '\0';
1285331Samw 	count = 0;
1295331Samw 
1305331Samw 	for (i = 0; i < nbytes; ++i) {
1315331Samw 		if (i && (i % 16) == 0) {
1325772Sas200622 			smb_tracef("%06X %s  %s", offset, hexbuf, ascbuf);
1335331Samw 			ap = ascbuf;
1345331Samw 			hp = hexbuf;
1355331Samw 			count = 0;
1365331Samw 			offset += 16;
1375331Samw 		}
1385331Samw 
1395331Samw 		ap += sprintf(ap, "%c",
1405331Samw 		    (*p >= 0x20 && *p < 0x7F) ? *p : '.');
1415331Samw 		hp += sprintf(hp, " %c%c",
1425331Samw 		    hex[(*p >> 4) & 0x0F], hex[(*p & 0x0F)]);
1435331Samw 		++p;
1445331Samw 		++count;
1455331Samw 	}
1465331Samw 
1475331Samw 	if (count) {
1485772Sas200622 		smb_tracef("%06X %-48s  %s", offset, hexbuf, ascbuf);
1495331Samw 		offset += count;
1505331Samw 	}
1515331Samw 
1525331Samw 	*start = offset;
1535331Samw }
1545331Samw 
1555331Samw void
hexdump(unsigned char * buffer,int nbytes)1565331Samw hexdump(unsigned char *buffer, int nbytes)
1575331Samw {
1585331Samw 	unsigned long start = 0;
1595331Samw 
1605772Sas200622 	hexdump_offset(buffer, nbytes, &start);
1615331Samw }
1625331Samw 
1635331Samw /*
1645331Samw  * bintohex
1655331Samw  *
1665331Samw  * Converts the given binary data (srcbuf) to
1675331Samw  * its equivalent hex chars (hexbuf).
1685331Samw  *
1695331Samw  * hexlen should be at least twice as srclen.
1705331Samw  * if hexbuf is not big enough returns 0.
1715331Samw  * otherwise returns number of valid chars in
1725331Samw  * hexbuf which is srclen * 2.
1735331Samw  */
1745331Samw size_t
bintohex(const char * srcbuf,size_t srclen,char * hexbuf,size_t hexlen)1755331Samw bintohex(const char *srcbuf, size_t srclen,
1765331Samw     char *hexbuf, size_t hexlen)
1775331Samw {
1785331Samw 	size_t outlen;
1795331Samw 	char c;
1805331Samw 
1815331Samw 	outlen = srclen << 1;
1825331Samw 
1835331Samw 	if (hexlen < outlen)
1845331Samw 		return (0);
1855331Samw 
1865331Samw 	while (srclen-- > 0) {
1875331Samw 		c = *srcbuf++;
1885331Samw 		*hexbuf++ = C2H(c & 0xF);
1895331Samw 		*hexbuf++ = C2H((c >> 4) & 0xF);
1905331Samw 	}
1915331Samw 
1925331Samw 	return (outlen);
1935331Samw }
1945331Samw 
1955331Samw /*
1965331Samw  * hextobin
1975331Samw  *
1985331Samw  * Converts hex to binary.
1995331Samw  *
2005331Samw  * Assuming hexbuf only contains hex digits (chars)
2015331Samw  * this function convert every two bytes of hexbuf
2025331Samw  * to one byte and put it in dstbuf.
2035331Samw  *
2045331Samw  * hexlen should be an even number.
2055331Samw  * dstlen should be at least half of hexlen.
2065331Samw  *
2075331Samw  * Returns 0 if sizes are not correct, otherwise
2085331Samw  * returns the number of converted bytes in dstbuf
2095331Samw  * which is half of hexlen.
2105331Samw  */
2115331Samw size_t
hextobin(const char * hexbuf,size_t hexlen,char * dstbuf,size_t dstlen)2125331Samw hextobin(const char *hexbuf, size_t hexlen,
2135331Samw     char *dstbuf, size_t dstlen)
2145331Samw {
2155331Samw 	size_t outlen;
2165331Samw 
2175331Samw 	if ((hexlen % 2) != 0)
2185331Samw 		return (0);
2195331Samw 
2205331Samw 	outlen = hexlen >> 1;
2215331Samw 	if (dstlen < outlen)
2225331Samw 		return (0);
2235331Samw 
2245331Samw 	while (hexlen > 0) {
2255331Samw 		*dstbuf = H2C(*hexbuf) & 0x0F;
2265331Samw 		hexbuf++;
2275331Samw 		*dstbuf++ |= (H2C(*hexbuf) << 4) & 0xF0;
2285331Samw 		hexbuf++;
2295331Samw 
2305331Samw 		hexlen -= 2;
2315331Samw 	}
2325331Samw 
2335331Samw 	return (outlen);
2345331Samw }
2355331Samw 
2365331Samw /*
2378334SJose.Borrego@Sun.COM  * Trim leading and trailing characters in the set defined by class
2388334SJose.Borrego@Sun.COM  * from a buffer containing a null-terminated string.
2398334SJose.Borrego@Sun.COM  * For example, if the input buffer contained "ABtext23" and class
2408334SJose.Borrego@Sun.COM  * contains "ABC123", the buffer will contain "text" on return.
2418334SJose.Borrego@Sun.COM  *
2428334SJose.Borrego@Sun.COM  * This function modifies the contents of buf in place and returns
2438334SJose.Borrego@Sun.COM  * a pointer to buf.
2448334SJose.Borrego@Sun.COM  */
2458334SJose.Borrego@Sun.COM char *
strtrim(char * buf,const char * class)2468334SJose.Borrego@Sun.COM strtrim(char *buf, const char *class)
2478334SJose.Borrego@Sun.COM {
2488334SJose.Borrego@Sun.COM 	char *p = buf;
2498334SJose.Borrego@Sun.COM 	char *q = buf;
2508334SJose.Borrego@Sun.COM 
2518334SJose.Borrego@Sun.COM 	if (buf == NULL)
2528334SJose.Borrego@Sun.COM 		return (NULL);
2538334SJose.Borrego@Sun.COM 
2548334SJose.Borrego@Sun.COM 	p += strspn(p, class);
2558334SJose.Borrego@Sun.COM 
2568334SJose.Borrego@Sun.COM 	if (p != buf) {
2578334SJose.Borrego@Sun.COM 		while ((*q = *p++) != '\0')
2588334SJose.Borrego@Sun.COM 			++q;
2598334SJose.Borrego@Sun.COM 	}
2608334SJose.Borrego@Sun.COM 
2618334SJose.Borrego@Sun.COM 	while (q != buf) {
2628334SJose.Borrego@Sun.COM 		--q;
2638334SJose.Borrego@Sun.COM 		if (strspn(q, class) == 0)
2648334SJose.Borrego@Sun.COM 			return (buf);
2658334SJose.Borrego@Sun.COM 		*q = '\0';
2668334SJose.Borrego@Sun.COM 	}
2678334SJose.Borrego@Sun.COM 
2688334SJose.Borrego@Sun.COM 	return (buf);
2698334SJose.Borrego@Sun.COM }
2708334SJose.Borrego@Sun.COM 
2718334SJose.Borrego@Sun.COM /*
2728334SJose.Borrego@Sun.COM  * Strip the characters in the set defined by class from a buffer
2738334SJose.Borrego@Sun.COM  * containing a null-terminated string.
2748334SJose.Borrego@Sun.COM  * For example, if the input buffer contained "XYA 1textZ string3"
2758334SJose.Borrego@Sun.COM  * and class contains "123XYZ", the buffer will contain "A text string"
2768334SJose.Borrego@Sun.COM  * on return.
2778334SJose.Borrego@Sun.COM  *
2788334SJose.Borrego@Sun.COM  * This function modifies the contents of buf in place and returns
2798334SJose.Borrego@Sun.COM  * a pointer to buf.
2808334SJose.Borrego@Sun.COM  */
2818334SJose.Borrego@Sun.COM char *
strstrip(char * buf,const char * class)2828334SJose.Borrego@Sun.COM strstrip(char *buf, const char *class)
2838334SJose.Borrego@Sun.COM {
2848334SJose.Borrego@Sun.COM 	char *p = buf;
2858334SJose.Borrego@Sun.COM 	char *q = buf;
2868334SJose.Borrego@Sun.COM 
2878334SJose.Borrego@Sun.COM 	if (buf == NULL)
2888334SJose.Borrego@Sun.COM 		return (NULL);
2898334SJose.Borrego@Sun.COM 
2908334SJose.Borrego@Sun.COM 	while (*p) {
2918334SJose.Borrego@Sun.COM 		p += strspn(p, class);
2928334SJose.Borrego@Sun.COM 		*q++ = *p++;
2938334SJose.Borrego@Sun.COM 	}
2948334SJose.Borrego@Sun.COM 
2958334SJose.Borrego@Sun.COM 	*q = '\0';
2968334SJose.Borrego@Sun.COM 	return (buf);
2978334SJose.Borrego@Sun.COM }
2988334SJose.Borrego@Sun.COM 
2998334SJose.Borrego@Sun.COM /*
3005331Samw  * trim_whitespace
3015331Samw  *
3025331Samw  * Trim leading and trailing whitespace chars (as defined by isspace)
3035331Samw  * from a buffer. Example; if the input buffer contained "  text  ",
3045331Samw  * it will contain "text", when we return. We assume that the buffer
3055331Samw  * contains a null terminated string. A pointer to the buffer is
3065331Samw  * returned.
3075331Samw  */
3085331Samw char *
trim_whitespace(char * buf)3095331Samw trim_whitespace(char *buf)
3105331Samw {
3115331Samw 	char *p = buf;
3125331Samw 	char *q = buf;
3135331Samw 
3145772Sas200622 	if (buf == NULL)
3155772Sas200622 		return (NULL);
3165331Samw 
3175331Samw 	while (*p && isspace(*p))
3185331Samw 		++p;
3195331Samw 
3205331Samw 	while ((*q = *p++) != 0)
3215331Samw 		++q;
3225331Samw 
3235331Samw 	if (q != buf) {
3245331Samw 		while ((--q, isspace(*q)) != 0)
3255331Samw 			*q = '\0';
3265331Samw 	}
3275331Samw 
3285331Samw 	return (buf);
3295331Samw }
3305331Samw 
3315331Samw /*
3325331Samw  * randomize
3335331Samw  *
3345331Samw  * Randomize the contents of the specified buffer.
3355331Samw  */
3365331Samw void
randomize(char * data,unsigned len)3375331Samw randomize(char *data, unsigned len)
3385331Samw {
3395331Samw 	unsigned dwlen = len / 4;
3405331Samw 	unsigned remlen = len % 4;
3415331Samw 	unsigned tmp;
3425331Samw 	unsigned i; /*LINTED E_BAD_PTR_CAST_ALIGN*/
3435331Samw 	unsigned *p = (unsigned *)data;
3445331Samw 
3455331Samw 	for (i = 0; i < dwlen; ++i)
3465331Samw 		*p++ = random();
3475331Samw 
3485331Samw 	if (remlen) {
3495331Samw 		tmp = random();
3505331Samw 		(void) memcpy(p, &tmp, remlen);
3515331Samw 	}
3525331Samw }
3535331Samw 
3545331Samw /*
3555331Samw  * This is the hash mechanism used to encrypt passwords for commands like
3565331Samw  * SamrSetUserInformation. It uses a 256 byte s-box.
3575331Samw  */
3585331Samw void
rand_hash(unsigned char * data,size_t datalen,unsigned char * key,size_t keylen)3595331Samw rand_hash(
3605331Samw     unsigned char *data,
3615331Samw     size_t datalen,
3625331Samw     unsigned char *key,
3635331Samw     size_t keylen)
3645331Samw {
3655331Samw 	unsigned char sbox[DEFAULT_SBOX_SIZE];
3665331Samw 	unsigned char tmp;
3675331Samw 	unsigned char index_i = 0;
3685331Samw 	unsigned char index_j = 0;
3695331Samw 	unsigned char j = 0;
3705331Samw 	int i;
3715331Samw 
3725331Samw 	for (i = 0; i < DEFAULT_SBOX_SIZE; ++i)
3735331Samw 		sbox[i] = (unsigned char)i;
3745331Samw 
3755331Samw 	for (i = 0; i < DEFAULT_SBOX_SIZE; ++i) {
3765331Samw 		j += (sbox[i] + key[i % keylen]);
3775331Samw 
3785331Samw 		tmp = sbox[i];
3795331Samw 		sbox[i] = sbox[j];
3805331Samw 		sbox[j] = tmp;
3815331Samw 	}
3825331Samw 
3835331Samw 	for (i = 0; i < datalen; ++i) {
3845331Samw 		index_i++;
3855331Samw 		index_j += sbox[index_i];
3865331Samw 
3875331Samw 		tmp = sbox[index_i];
3885331Samw 		sbox[index_i] = sbox[index_j];
3895331Samw 		sbox[index_j] = tmp;
3905331Samw 
3915331Samw 		tmp = sbox[index_i] + sbox[index_j];
3925331Samw 		data[i] = data[i] ^ sbox[tmp];
3935331Samw 	}
3945331Samw }
3957961SNatalie.Li@Sun.COM 
3967961SNatalie.Li@Sun.COM /*
3977961SNatalie.Li@Sun.COM  * smb_chk_hostaccess
3987961SNatalie.Li@Sun.COM  *
399*12508Samw@Sun.COM  * Determines whether the specified host is in the given access list.
400*12508Samw@Sun.COM  *
4017961SNatalie.Li@Sun.COM  * We match on aliases of the hostname as well as on the canonical name.
4027961SNatalie.Li@Sun.COM  * Names in the access list may be either hosts or netgroups;  they're
4037961SNatalie.Li@Sun.COM  * not distinguished syntactically.  We check for hosts first because
4047961SNatalie.Li@Sun.COM  * it's cheaper (just M*N strcmp()s), then try netgroups.
4057961SNatalie.Li@Sun.COM  *
4067961SNatalie.Li@Sun.COM  * Function returns:
407*12508Samw@Sun.COM  *	-1 for "all" (list is empty "" or "*")
408*12508Samw@Sun.COM  *	0 not found  (host is not in the list or list is NULL)
4097961SNatalie.Li@Sun.COM  *	1 found
4108670SJose.Borrego@Sun.COM  *
4117961SNatalie.Li@Sun.COM  */
4127961SNatalie.Li@Sun.COM int
smb_chk_hostaccess(smb_inaddr_t * ipaddr,char * access_list)4138670SJose.Borrego@Sun.COM smb_chk_hostaccess(smb_inaddr_t *ipaddr, char *access_list)
4147961SNatalie.Li@Sun.COM {
4157961SNatalie.Li@Sun.COM 	int nentries;
4167961SNatalie.Li@Sun.COM 	char *gr;
4177961SNatalie.Li@Sun.COM 	char *lasts;
4187961SNatalie.Li@Sun.COM 	char *host;
4197961SNatalie.Li@Sun.COM 	int off;
4207961SNatalie.Li@Sun.COM 	int i;
4217961SNatalie.Li@Sun.COM 	int netgroup_match;
4227961SNatalie.Li@Sun.COM 	int response;
4237961SNatalie.Li@Sun.COM 	struct nd_hostservlist *clnames;
4247961SNatalie.Li@Sun.COM 	struct in_addr inaddr;
4257961SNatalie.Li@Sun.COM 	struct sockaddr_in sa;
4267961SNatalie.Li@Sun.COM 	struct netbuf buf;
4277961SNatalie.Li@Sun.COM 	struct netconfig *config;
4287961SNatalie.Li@Sun.COM 
429*12508Samw@Sun.COM 	if (access_list == NULL)
430*12508Samw@Sun.COM 		return (0);
4318670SJose.Borrego@Sun.COM 
4328670SJose.Borrego@Sun.COM 	inaddr.s_addr = ipaddr->a_ipv4;
4337961SNatalie.Li@Sun.COM 
4347961SNatalie.Li@Sun.COM 	/*
435*12508Samw@Sun.COM 	 * If access list is empty or "*" - then it's "all"
4367961SNatalie.Li@Sun.COM 	 */
437*12508Samw@Sun.COM 	if (*access_list == '\0' || strcmp(access_list, "*") == 0)
4387961SNatalie.Li@Sun.COM 		return (-1);
4397961SNatalie.Li@Sun.COM 
4407961SNatalie.Li@Sun.COM 	nentries = 0;
4417961SNatalie.Li@Sun.COM 
4427961SNatalie.Li@Sun.COM 	sa.sin_family = AF_INET;
4437961SNatalie.Li@Sun.COM 	sa.sin_port = 0;
4447961SNatalie.Li@Sun.COM 	sa.sin_addr = inaddr;
4457961SNatalie.Li@Sun.COM 
4467961SNatalie.Li@Sun.COM 	buf.len = buf.maxlen = sizeof (sa);
4477961SNatalie.Li@Sun.COM 	buf.buf = (char *)&sa;
4487961SNatalie.Li@Sun.COM 
4497961SNatalie.Li@Sun.COM 	config = getnetconfigent("tcp");
4507961SNatalie.Li@Sun.COM 	if (config == NULL)
4517961SNatalie.Li@Sun.COM 		return (1);
4527961SNatalie.Li@Sun.COM 
4537961SNatalie.Li@Sun.COM 	if (__netdir_getbyaddr_nosrv(config, &clnames, &buf)) {
4547961SNatalie.Li@Sun.COM 		freenetconfigent(config);
4557961SNatalie.Li@Sun.COM 		return (0);
4567961SNatalie.Li@Sun.COM 	}
4577961SNatalie.Li@Sun.COM 	freenetconfigent(config);
4587961SNatalie.Li@Sun.COM 
4597961SNatalie.Li@Sun.COM 	for (gr = strtok_r(access_list, ":", &lasts);
4607961SNatalie.Li@Sun.COM 	    gr != NULL; gr = strtok_r(NULL, ":", &lasts)) {
4617961SNatalie.Li@Sun.COM 
4627961SNatalie.Li@Sun.COM 		/*
4637961SNatalie.Li@Sun.COM 		 * If the list name has a '-' prepended
4647961SNatalie.Li@Sun.COM 		 * then a match of the following name
4657961SNatalie.Li@Sun.COM 		 * implies failure instead of success.
4667961SNatalie.Li@Sun.COM 		 */
4677961SNatalie.Li@Sun.COM 		if (*gr == '-') {
4687961SNatalie.Li@Sun.COM 			response = 0;
4697961SNatalie.Li@Sun.COM 			gr++;
4707961SNatalie.Li@Sun.COM 		} else {
4717961SNatalie.Li@Sun.COM 			response = 1;
4727961SNatalie.Li@Sun.COM 		}
4737961SNatalie.Li@Sun.COM 
4747961SNatalie.Li@Sun.COM 		/*
4757961SNatalie.Li@Sun.COM 		 * The following loops through all the
4767961SNatalie.Li@Sun.COM 		 * client's aliases.  Usually it's just one name.
4777961SNatalie.Li@Sun.COM 		 */
4787961SNatalie.Li@Sun.COM 		for (i = 0; i < clnames->h_cnt; i++) {
4797961SNatalie.Li@Sun.COM 			host = clnames->h_hostservs[i].h_host;
4807961SNatalie.Li@Sun.COM 			/*
4817961SNatalie.Li@Sun.COM 			 * If the list name begins with a dot then
4827961SNatalie.Li@Sun.COM 			 * do a domain name suffix comparison.
4837961SNatalie.Li@Sun.COM 			 * A single dot matches any name with no
4847961SNatalie.Li@Sun.COM 			 * suffix.
4857961SNatalie.Li@Sun.COM 			 */
4867961SNatalie.Li@Sun.COM 			if (*gr == '.') {
4877961SNatalie.Li@Sun.COM 				if (*(gr + 1) == '\0') {  /* single dot */
4887961SNatalie.Li@Sun.COM 					if (strchr(host, '.') == NULL)
4897961SNatalie.Li@Sun.COM 						return (response);
4907961SNatalie.Li@Sun.COM 				} else {
4917961SNatalie.Li@Sun.COM 					off = strlen(host) - strlen(gr);
4927961SNatalie.Li@Sun.COM 					if (off > 0 &&
4937961SNatalie.Li@Sun.COM 					    strcasecmp(host + off, gr) == 0) {
4947961SNatalie.Li@Sun.COM 						return (response);
4957961SNatalie.Li@Sun.COM 					}
4967961SNatalie.Li@Sun.COM 				}
4977961SNatalie.Li@Sun.COM 			} else {
4987961SNatalie.Li@Sun.COM 
4997961SNatalie.Li@Sun.COM 				/*
5007961SNatalie.Li@Sun.COM 				 * If the list name begins with an at
5017961SNatalie.Li@Sun.COM 				 * sign then do a network comparison.
5027961SNatalie.Li@Sun.COM 				 */
5037961SNatalie.Li@Sun.COM 				if (*gr == '@') {
5047961SNatalie.Li@Sun.COM 					if (smb_netmatch(&buf, gr + 1))
5057961SNatalie.Li@Sun.COM 						return (response);
5067961SNatalie.Li@Sun.COM 				} else {
5077961SNatalie.Li@Sun.COM 					/*
5087961SNatalie.Li@Sun.COM 					 * Just do a hostname match
5097961SNatalie.Li@Sun.COM 					 */
5107961SNatalie.Li@Sun.COM 					if (strcasecmp(gr, host) == 0)
5117961SNatalie.Li@Sun.COM 						return (response);
5127961SNatalie.Li@Sun.COM 				}
5137961SNatalie.Li@Sun.COM 			}
5147961SNatalie.Li@Sun.COM 		}
5157961SNatalie.Li@Sun.COM 
5167961SNatalie.Li@Sun.COM 		nentries++;
5177961SNatalie.Li@Sun.COM 	}
5187961SNatalie.Li@Sun.COM 
5197961SNatalie.Li@Sun.COM 	netgroup_match = smb_netgroup_match(clnames, access_list, nentries);
5207961SNatalie.Li@Sun.COM 
5217961SNatalie.Li@Sun.COM 	return (netgroup_match);
5227961SNatalie.Li@Sun.COM }
5237961SNatalie.Li@Sun.COM 
5247961SNatalie.Li@Sun.COM /*
5257961SNatalie.Li@Sun.COM  * smb_make_mask
5267961SNatalie.Li@Sun.COM  *
5277961SNatalie.Li@Sun.COM  * Construct a mask for an IPv4 address using the @<dotted-ip>/<len>
5287961SNatalie.Li@Sun.COM  * syntax or use the default mask for the IP address.
5297961SNatalie.Li@Sun.COM  */
5307961SNatalie.Li@Sun.COM static uint_t
smb_make_mask(char * maskstr,uint_t addr)5317961SNatalie.Li@Sun.COM smb_make_mask(char *maskstr, uint_t addr)
5327961SNatalie.Li@Sun.COM {
5337961SNatalie.Li@Sun.COM 	uint_t mask;
5347961SNatalie.Li@Sun.COM 	uint_t bits;
5357961SNatalie.Li@Sun.COM 
5367961SNatalie.Li@Sun.COM 	/*
5377961SNatalie.Li@Sun.COM 	 * If the mask is specified explicitly then
5387961SNatalie.Li@Sun.COM 	 * use that value, e.g.
5397961SNatalie.Li@Sun.COM 	 *
5407961SNatalie.Li@Sun.COM 	 *    @109.104.56/28
5417961SNatalie.Li@Sun.COM 	 *
5427961SNatalie.Li@Sun.COM 	 * otherwise assume a mask from the zero octets
5437961SNatalie.Li@Sun.COM 	 * in the least significant bits of the address, e.g.
5447961SNatalie.Li@Sun.COM 	 *
5457961SNatalie.Li@Sun.COM 	 *   @109.104  or  @109.104.0.0
5467961SNatalie.Li@Sun.COM 	 */
5477961SNatalie.Li@Sun.COM 	if (maskstr) {
5487961SNatalie.Li@Sun.COM 		bits = atoi(maskstr);
5497961SNatalie.Li@Sun.COM 		mask = bits ? ~0 << ((sizeof (struct in_addr) * NBBY) - bits)
5507961SNatalie.Li@Sun.COM 		    : 0;
5517961SNatalie.Li@Sun.COM 		addr &= mask;
5527961SNatalie.Li@Sun.COM 	} else {
5537961SNatalie.Li@Sun.COM 		if ((addr & IN_CLASSA_HOST) == 0)
5547961SNatalie.Li@Sun.COM 			mask = IN_CLASSA_NET;
5557961SNatalie.Li@Sun.COM 		else if ((addr & IN_CLASSB_HOST) == 0)
5567961SNatalie.Li@Sun.COM 			mask = IN_CLASSB_NET;
5577961SNatalie.Li@Sun.COM 		else if ((addr & IN_CLASSC_HOST) == 0)
5587961SNatalie.Li@Sun.COM 			mask = IN_CLASSC_NET;
5597961SNatalie.Li@Sun.COM 		else
5607961SNatalie.Li@Sun.COM 			mask = IN_CLASSE_NET;
5617961SNatalie.Li@Sun.COM 	}
5627961SNatalie.Li@Sun.COM 
5637961SNatalie.Li@Sun.COM 	return (mask);
5647961SNatalie.Li@Sun.COM }
5657961SNatalie.Li@Sun.COM 
5667961SNatalie.Li@Sun.COM /*
5677961SNatalie.Li@Sun.COM  * smb_netmatch
5687961SNatalie.Li@Sun.COM  *
5697961SNatalie.Li@Sun.COM  * Check to see if the address in the netbuf matches the "net"
5707961SNatalie.Li@Sun.COM  * specified by name.  The format of "name" can be:
5717961SNatalie.Li@Sun.COM  *	fully qualified domain name
5727961SNatalie.Li@Sun.COM  *	dotted IP address
5737961SNatalie.Li@Sun.COM  *	dotted IP address followed by '/<len>'
5747961SNatalie.Li@Sun.COM  *	See sharen_nfs(1M) for details.
5757961SNatalie.Li@Sun.COM  */
5767961SNatalie.Li@Sun.COM 
5777961SNatalie.Li@Sun.COM static boolean_t
smb_netmatch(struct netbuf * nb,char * name)5787961SNatalie.Li@Sun.COM smb_netmatch(struct netbuf *nb, char *name)
5797961SNatalie.Li@Sun.COM {
5807961SNatalie.Li@Sun.COM 	uint_t claddr;
5817961SNatalie.Li@Sun.COM 	struct netent n, *np;
5827961SNatalie.Li@Sun.COM 	char *mp, *p;
5837961SNatalie.Li@Sun.COM 	uint_t addr, mask;
5847961SNatalie.Li@Sun.COM 	int i;
5857961SNatalie.Li@Sun.COM 	char buff[256];
5867961SNatalie.Li@Sun.COM 
5877961SNatalie.Li@Sun.COM 	/*
5887961SNatalie.Li@Sun.COM 	 * Check if it's an IPv4 addr
5897961SNatalie.Li@Sun.COM 	 */
5907961SNatalie.Li@Sun.COM 	if (nb->len != sizeof (struct sockaddr_in))
5917961SNatalie.Li@Sun.COM 		return (B_FALSE);
5927961SNatalie.Li@Sun.COM 
5937961SNatalie.Li@Sun.COM 	(void) memcpy(&claddr,
5947961SNatalie.Li@Sun.COM 	    /* LINTED pointer alignment */
5957961SNatalie.Li@Sun.COM 	    &((struct sockaddr_in *)nb->buf)->sin_addr.s_addr,
5967961SNatalie.Li@Sun.COM 	    sizeof (struct in_addr));
5977961SNatalie.Li@Sun.COM 	claddr = ntohl(claddr);
5987961SNatalie.Li@Sun.COM 
5997961SNatalie.Li@Sun.COM 	mp = strchr(name, '/');
6007961SNatalie.Li@Sun.COM 	if (mp)
6017961SNatalie.Li@Sun.COM 		*mp++ = '\0';
6027961SNatalie.Li@Sun.COM 
6037961SNatalie.Li@Sun.COM 	if (isdigit(*name)) {
6047961SNatalie.Li@Sun.COM 		/*
6057961SNatalie.Li@Sun.COM 		 * Convert a dotted IP address
6067961SNatalie.Li@Sun.COM 		 * to an IP address. The conversion
6077961SNatalie.Li@Sun.COM 		 * is not the same as that in inet_addr().
6087961SNatalie.Li@Sun.COM 		 */
6097961SNatalie.Li@Sun.COM 		p = name;
6107961SNatalie.Li@Sun.COM 		addr = 0;
6117961SNatalie.Li@Sun.COM 		for (i = 0; i < 4; i++) {
6127961SNatalie.Li@Sun.COM 			addr |= atoi(p) << ((3-i) * 8);
6137961SNatalie.Li@Sun.COM 			p = strchr(p, '.');
6147961SNatalie.Li@Sun.COM 			if (p == NULL)
6157961SNatalie.Li@Sun.COM 				break;
6167961SNatalie.Li@Sun.COM 			p++;
6177961SNatalie.Li@Sun.COM 		}
6187961SNatalie.Li@Sun.COM 	} else {
6197961SNatalie.Li@Sun.COM 		/*
6207961SNatalie.Li@Sun.COM 		 * Turn the netname into
6217961SNatalie.Li@Sun.COM 		 * an IP address.
6227961SNatalie.Li@Sun.COM 		 */
6237961SNatalie.Li@Sun.COM 		np = getnetbyname_r(name, &n, buff, sizeof (buff));
6247961SNatalie.Li@Sun.COM 		if (np == NULL) {
6257961SNatalie.Li@Sun.COM 			return (B_FALSE);
6267961SNatalie.Li@Sun.COM 		}
6277961SNatalie.Li@Sun.COM 		addr = np->n_net;
6287961SNatalie.Li@Sun.COM 	}
6297961SNatalie.Li@Sun.COM 
6307961SNatalie.Li@Sun.COM 	mask = smb_make_mask(mp, addr);
6317961SNatalie.Li@Sun.COM 	return ((claddr & mask) == addr);
6327961SNatalie.Li@Sun.COM }
6337961SNatalie.Li@Sun.COM 
6347961SNatalie.Li@Sun.COM /*
6357961SNatalie.Li@Sun.COM  * smb_netgroup_match
6367961SNatalie.Li@Sun.COM  *
6377961SNatalie.Li@Sun.COM  * Check whether any of the hostnames in clnames are
6387961SNatalie.Li@Sun.COM  * members (or non-members) of the netgroups in glist.
6397961SNatalie.Li@Sun.COM  * Since the innetgr lookup is rather expensive, the
6407961SNatalie.Li@Sun.COM  * result is cached. The cached entry is valid only
6417961SNatalie.Li@Sun.COM  * for VALID_TIME seconds.  This works well because
6427961SNatalie.Li@Sun.COM  * typically these lookups occur in clusters when
6437961SNatalie.Li@Sun.COM  * a client is mounting.
6447961SNatalie.Li@Sun.COM  *
6457961SNatalie.Li@Sun.COM  * Note that this routine establishes a host membership
6467961SNatalie.Li@Sun.COM  * in a list of netgroups - we've no idea just which
6477961SNatalie.Li@Sun.COM  * netgroup in the list it is a member of.
6487961SNatalie.Li@Sun.COM  *
6497961SNatalie.Li@Sun.COM  * glist is a character array containing grc strings
6507961SNatalie.Li@Sun.COM  * representing netgroup names (optionally prefixed
6517961SNatalie.Li@Sun.COM  * with '-'). Each string is ended with '\0'  and
6527961SNatalie.Li@Sun.COM  * followed immediately by the next string.
6537961SNatalie.Li@Sun.COM  */
6547961SNatalie.Li@Sun.COM static boolean_t
smb_netgroup_match(struct nd_hostservlist * clnames,char * glist,int grc)6557961SNatalie.Li@Sun.COM smb_netgroup_match(struct nd_hostservlist *clnames, char  *glist, int grc)
6567961SNatalie.Li@Sun.COM {
6577961SNatalie.Li@Sun.COM 	char **grl;
6587961SNatalie.Li@Sun.COM 	char *gr;
6597961SNatalie.Li@Sun.COM 	int nhosts = clnames->h_cnt;
6607961SNatalie.Li@Sun.COM 	char *host;
6617961SNatalie.Li@Sun.COM 	int i, j, n;
6627961SNatalie.Li@Sun.COM 	boolean_t response;
6637961SNatalie.Li@Sun.COM 	boolean_t belong = B_FALSE;
6647961SNatalie.Li@Sun.COM 	static char *domain = NULL;
6657961SNatalie.Li@Sun.COM 
6667961SNatalie.Li@Sun.COM 	if (domain == NULL) {
6677961SNatalie.Li@Sun.COM 		int	ssize;
6687961SNatalie.Li@Sun.COM 
6697961SNatalie.Li@Sun.COM 		domain = malloc(SYS_NMLN);
6707961SNatalie.Li@Sun.COM 		if (domain == NULL)
6717961SNatalie.Li@Sun.COM 			return (B_FALSE);
6727961SNatalie.Li@Sun.COM 
6737961SNatalie.Li@Sun.COM 		ssize = sysinfo(SI_SRPC_DOMAIN, domain, SYS_NMLN);
6747961SNatalie.Li@Sun.COM 		if (ssize > SYS_NMLN) {
6757961SNatalie.Li@Sun.COM 			free(domain);
6767961SNatalie.Li@Sun.COM 			domain = malloc(ssize);
6777961SNatalie.Li@Sun.COM 			if (domain == NULL)
6787961SNatalie.Li@Sun.COM 				return (B_FALSE);
6797961SNatalie.Li@Sun.COM 			ssize = sysinfo(SI_SRPC_DOMAIN, domain, ssize);
6807961SNatalie.Li@Sun.COM 		}
6817961SNatalie.Li@Sun.COM 		/* Check for error in syscall or NULL domain name */
6827961SNatalie.Li@Sun.COM 		if (ssize <= 1)
6837961SNatalie.Li@Sun.COM 			return (B_FALSE);
6847961SNatalie.Li@Sun.COM 	}
6857961SNatalie.Li@Sun.COM 
6867961SNatalie.Li@Sun.COM 	grl = calloc(grc, sizeof (char *));
6877961SNatalie.Li@Sun.COM 	if (grl == NULL)
6887961SNatalie.Li@Sun.COM 		return (B_FALSE);
6897961SNatalie.Li@Sun.COM 
6907961SNatalie.Li@Sun.COM 	for (i = 0, gr = glist; i < grc && !belong; ) {
6917961SNatalie.Li@Sun.COM 		/*
6927961SNatalie.Li@Sun.COM 		 * If the netgroup name has a '-' prepended
6937961SNatalie.Li@Sun.COM 		 * then a match of this name implies a failure
6947961SNatalie.Li@Sun.COM 		 * instead of success.
6957961SNatalie.Li@Sun.COM 		 */
6967961SNatalie.Li@Sun.COM 		response = (*gr != '-') ? B_TRUE : B_FALSE;
6977961SNatalie.Li@Sun.COM 
6987961SNatalie.Li@Sun.COM 		/*
6997961SNatalie.Li@Sun.COM 		 * Subsequent names with or without a '-' (but no mix)
7007961SNatalie.Li@Sun.COM 		 * can be grouped together for a single check.
7017961SNatalie.Li@Sun.COM 		 */
7027961SNatalie.Li@Sun.COM 		for (n = 0; i < grc; i++, n++, gr += strlen(gr) + 1) {
7037961SNatalie.Li@Sun.COM 			if ((response && *gr == '-') ||
7047961SNatalie.Li@Sun.COM 			    (!response && *gr != '-'))
7057961SNatalie.Li@Sun.COM 				break;
7067961SNatalie.Li@Sun.COM 
7077961SNatalie.Li@Sun.COM 			grl[n] = response ? gr : gr + 1;
7087961SNatalie.Li@Sun.COM 		}
7097961SNatalie.Li@Sun.COM 
7107961SNatalie.Li@Sun.COM 		/*
7117961SNatalie.Li@Sun.COM 		 * Check the netgroup for each
7127961SNatalie.Li@Sun.COM 		 * of the hosts names (usually just one).
7137961SNatalie.Li@Sun.COM 		 */
7147961SNatalie.Li@Sun.COM 		for (j = 0; j < nhosts && !belong; j++) {
7157961SNatalie.Li@Sun.COM 			host = clnames->h_hostservs[j].h_host;
7167961SNatalie.Li@Sun.COM 			if (__multi_innetgr(n, grl, 1, &host, 0, NULL,
7177961SNatalie.Li@Sun.COM 			    1, &domain))
7187961SNatalie.Li@Sun.COM 				belong = B_TRUE;
7197961SNatalie.Li@Sun.COM 		}
7207961SNatalie.Li@Sun.COM 	}
7217961SNatalie.Li@Sun.COM 
7227961SNatalie.Li@Sun.COM 	free(grl);
7237961SNatalie.Li@Sun.COM 	return (belong ? response : B_FALSE);
7247961SNatalie.Li@Sun.COM }
7258871Samw@Sun.COM 
7268871Samw@Sun.COM /*
7278871Samw@Sun.COM  * Resolve the ZFS dataset from a path.
7289832Samw@Sun.COM  * Returns,
7299832Samw@Sun.COM  *	0  = On success.
7309832Samw@Sun.COM  *	-1 = Failure to open /etc/mnttab file or to get ZFS dataset.
7318871Samw@Sun.COM  */
7328871Samw@Sun.COM int
smb_getdataset(const char * path,char * dataset,size_t len)7338871Samw@Sun.COM smb_getdataset(const char *path, char *dataset, size_t len)
7348871Samw@Sun.COM {
7358871Samw@Sun.COM 	char tmppath[MAXPATHLEN];
7368871Samw@Sun.COM 	char *cp;
7378871Samw@Sun.COM 	FILE *fp;
7388871Samw@Sun.COM 	struct mnttab mnttab;
7398871Samw@Sun.COM 	struct mnttab mntpref;
7408871Samw@Sun.COM 	int rc = -1;
7418871Samw@Sun.COM 
7428871Samw@Sun.COM 	if ((fp = fopen(MNTTAB, "r")) == NULL)
7438871Samw@Sun.COM 		return (-1);
7448871Samw@Sun.COM 
7458871Samw@Sun.COM 	(void) memset(&mnttab, '\0', sizeof (mnttab));
7468871Samw@Sun.COM 	(void) strlcpy(tmppath, path, MAXPATHLEN);
7478871Samw@Sun.COM 	cp = tmppath;
7488871Samw@Sun.COM 
7498871Samw@Sun.COM 	while (*cp != '\0') {
7508871Samw@Sun.COM 		resetmnttab(fp);
7518871Samw@Sun.COM 		(void) memset(&mntpref, '\0', sizeof (mntpref));
7528871Samw@Sun.COM 		mntpref.mnt_mountp = tmppath;
7538871Samw@Sun.COM 
7548871Samw@Sun.COM 		if (getmntany(fp, &mnttab, &mntpref) == 0) {
7559832Samw@Sun.COM 			if (mnttab.mnt_fstype == NULL)
7569832Samw@Sun.COM 				break;
7579832Samw@Sun.COM 
7589832Samw@Sun.COM 			if (strcmp(mnttab.mnt_fstype, "zfs") != 0)
7599832Samw@Sun.COM 				break;
7608871Samw@Sun.COM 			/*
7618871Samw@Sun.COM 			 * Ensure that there are no leading slashes
7628871Samw@Sun.COM 			 * (required for zfs_open).
7638871Samw@Sun.COM 			 */
7648871Samw@Sun.COM 			cp = mnttab.mnt_special;
7658871Samw@Sun.COM 			cp += strspn(cp, "/");
7668871Samw@Sun.COM 			(void) strlcpy(dataset, cp, len);
7678871Samw@Sun.COM 			rc = 0;
7688871Samw@Sun.COM 			break;
7698871Samw@Sun.COM 		}
7708871Samw@Sun.COM 
7719021Samw@Sun.COM 		if (strcmp(tmppath, "/") == 0)
7729021Samw@Sun.COM 			break;
7739021Samw@Sun.COM 
7749021Samw@Sun.COM 		if ((cp = strrchr(tmppath, '/')) == NULL)
7759021Samw@Sun.COM 			break;
7769021Samw@Sun.COM 
7779021Samw@Sun.COM 		/*
7789021Samw@Sun.COM 		 * The path has multiple components.
7799021Samw@Sun.COM 		 * Remove the last component and try again.
7809021Samw@Sun.COM 		 */
7819021Samw@Sun.COM 		*cp = '\0';
7829021Samw@Sun.COM 		if (tmppath[0] == '\0')
7839021Samw@Sun.COM 			(void) strcpy(tmppath, "/");
7848871Samw@Sun.COM 
7858871Samw@Sun.COM 		cp = tmppath;
7868871Samw@Sun.COM 	}
7878871Samw@Sun.COM 
7888871Samw@Sun.COM 	(void) fclose(fp);
7898871Samw@Sun.COM 	return (rc);
7908871Samw@Sun.COM }
7919832Samw@Sun.COM 
7929832Samw@Sun.COM /*
79310122SJordan.Brown@Sun.COM  * smb_dlopen
79410122SJordan.Brown@Sun.COM  *
79510122SJordan.Brown@Sun.COM  * Check to see if an interposer library exists.  If it exists
79610122SJordan.Brown@Sun.COM  * and reports a valid version number and key (UUID), return
79710122SJordan.Brown@Sun.COM  * a handle to the library.  Otherwise, return NULL.
79810122SJordan.Brown@Sun.COM  */
79910122SJordan.Brown@Sun.COM void *
smb_dlopen(void)80010122SJordan.Brown@Sun.COM smb_dlopen(void)
80110122SJordan.Brown@Sun.COM {
80210122SJordan.Brown@Sun.COM 	uuid_t uuid;
80310122SJordan.Brown@Sun.COM 	void *interposer_hdl;
80410122SJordan.Brown@Sun.COM 	typedef int (*smbex_versionfn_t)(smbex_version_t *);
80510122SJordan.Brown@Sun.COM 	smbex_versionfn_t getversion;
80610122SJordan.Brown@Sun.COM 	smbex_version_t *version;
80710122SJordan.Brown@Sun.COM 
80810122SJordan.Brown@Sun.COM 	bzero(&uuid, sizeof (uuid_t));
80910122SJordan.Brown@Sun.COM 	if (uuid_parse(SMBEX_KEY, uuid) < 0)
81010122SJordan.Brown@Sun.COM 		return (NULL);
81110122SJordan.Brown@Sun.COM 
81210122SJordan.Brown@Sun.COM 	interposer_hdl = dlopen(SMB_LIB_ALT, RTLD_NOW | RTLD_LOCAL);
81310122SJordan.Brown@Sun.COM 	if (interposer_hdl == NULL)
81410122SJordan.Brown@Sun.COM 		return (NULL);
81510122SJordan.Brown@Sun.COM 
81610122SJordan.Brown@Sun.COM 	bzero(&getversion, sizeof (smbex_versionfn_t));
81710122SJordan.Brown@Sun.COM 	getversion = (smbex_versionfn_t)dlsym(interposer_hdl,
81810122SJordan.Brown@Sun.COM 	    "smbex_get_version");
81910122SJordan.Brown@Sun.COM 	if ((getversion == NULL) ||
82010122SJordan.Brown@Sun.COM 	    (version = malloc(sizeof (smbex_version_t))) == NULL) {
82110122SJordan.Brown@Sun.COM 		(void) dlclose(interposer_hdl);
82210122SJordan.Brown@Sun.COM 		return (NULL);
82310122SJordan.Brown@Sun.COM 	}
82410122SJordan.Brown@Sun.COM 	bzero(version, sizeof (smbex_version_t));
82510122SJordan.Brown@Sun.COM 
82610122SJordan.Brown@Sun.COM 	if ((getversion(version) != 0) ||
82710122SJordan.Brown@Sun.COM 	    (version->v_version != SMBEX_VERSION) ||
82810122SJordan.Brown@Sun.COM 	    (uuid_compare(version->v_uuid, uuid) != 0)) {
82910122SJordan.Brown@Sun.COM 		free(version);
83010122SJordan.Brown@Sun.COM 		(void) dlclose(interposer_hdl);
83110122SJordan.Brown@Sun.COM 		return (NULL);
83210122SJordan.Brown@Sun.COM 	}
83310122SJordan.Brown@Sun.COM 
83410122SJordan.Brown@Sun.COM 	free(version);
83510122SJordan.Brown@Sun.COM 	return (interposer_hdl);
83610122SJordan.Brown@Sun.COM }
83710122SJordan.Brown@Sun.COM 
83810122SJordan.Brown@Sun.COM /*
83910122SJordan.Brown@Sun.COM  * smb_dlclose
84010122SJordan.Brown@Sun.COM  *
84110122SJordan.Brown@Sun.COM  * Closes handle to the interposed library.
84210122SJordan.Brown@Sun.COM  */
84310122SJordan.Brown@Sun.COM void
smb_dlclose(void * handle)84410122SJordan.Brown@Sun.COM smb_dlclose(void *handle)
84510122SJordan.Brown@Sun.COM {
84610122SJordan.Brown@Sun.COM 	if (handle)
84710122SJordan.Brown@Sun.COM 		(void) dlclose(handle);
84810122SJordan.Brown@Sun.COM }
84910122SJordan.Brown@Sun.COM 
85010122SJordan.Brown@Sun.COM /*
85111963SAfshin.Ardakani@Sun.COM  * This function is a wrapper for getnameinfo() to look up a hostname given an
85211963SAfshin.Ardakani@Sun.COM  * IP address. The hostname returned by this function is used for constructing
85311963SAfshin.Ardakani@Sun.COM  * the service principal name field of KRB AP-REQs. Hence, it should be
85411963SAfshin.Ardakani@Sun.COM  * converted to lowercase for RFC 4120 section 6.2.1 conformance.
8559832Samw@Sun.COM  */
8569832Samw@Sun.COM int
smb_getnameinfo(smb_inaddr_t * ip,char * hostname,int hostlen,int flags)8579832Samw@Sun.COM smb_getnameinfo(smb_inaddr_t *ip, char *hostname, int hostlen, int flags)
8589832Samw@Sun.COM {
8599832Samw@Sun.COM 	socklen_t salen;
8609832Samw@Sun.COM 	struct sockaddr_in6 sin6;
8619832Samw@Sun.COM 	struct sockaddr_in sin;
8629832Samw@Sun.COM 	void *sp;
86311963SAfshin.Ardakani@Sun.COM 	int rc;
8649832Samw@Sun.COM 
8659832Samw@Sun.COM 	if (ip->a_family == AF_INET) {
8669832Samw@Sun.COM 		salen = sizeof (struct sockaddr_in);
8679832Samw@Sun.COM 		sin.sin_family = ip->a_family;
8689832Samw@Sun.COM 		sin.sin_port = 0;
8699832Samw@Sun.COM 		sin.sin_addr.s_addr = ip->a_ipv4;
8709832Samw@Sun.COM 		sp = &sin;
8719832Samw@Sun.COM 	} else {
8729832Samw@Sun.COM 		salen = sizeof (struct sockaddr_in6);
8739832Samw@Sun.COM 		sin6.sin6_family = ip->a_family;
8749832Samw@Sun.COM 		sin6.sin6_port = 0;
8759832Samw@Sun.COM 		(void) memcpy(&sin6.sin6_addr.s6_addr, &ip->a_ipv6,
8769832Samw@Sun.COM 		    sizeof (sin6.sin6_addr.s6_addr));
8779832Samw@Sun.COM 		sp = &sin6;
8789832Samw@Sun.COM 	}
87911963SAfshin.Ardakani@Sun.COM 
88011963SAfshin.Ardakani@Sun.COM 	if ((rc = (getnameinfo((struct sockaddr *)sp, salen,
88111963SAfshin.Ardakani@Sun.COM 	    hostname, hostlen, NULL, 0, flags))) == 0)
88211963SAfshin.Ardakani@Sun.COM 		(void) smb_strlwr(hostname);
88311963SAfshin.Ardakani@Sun.COM 
88411963SAfshin.Ardakani@Sun.COM 	return (rc);
8859832Samw@Sun.COM }
88611337SWilliam.Krier@Sun.COM 
88711337SWilliam.Krier@Sun.COM /*
88811337SWilliam.Krier@Sun.COM  * A share name is considered invalid if it contains control
88911337SWilliam.Krier@Sun.COM  * characters or any of the following characters (MSDN 236388).
89011337SWilliam.Krier@Sun.COM  *
89111337SWilliam.Krier@Sun.COM  *	" / \ [ ] : | < > + ; , ? * =
89211337SWilliam.Krier@Sun.COM  */
89311337SWilliam.Krier@Sun.COM uint32_t
smb_name_validate_share(const char * sharename)89411337SWilliam.Krier@Sun.COM smb_name_validate_share(const char *sharename)
89511337SWilliam.Krier@Sun.COM {
89611337SWilliam.Krier@Sun.COM 	const char *invalid = "\"/\\[]:|<>+;,?*=";
89711337SWilliam.Krier@Sun.COM 	const char *p;
89811337SWilliam.Krier@Sun.COM 
89911337SWilliam.Krier@Sun.COM 	if (sharename == NULL)
90011337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_PARAMETER);
90111337SWilliam.Krier@Sun.COM 
90211337SWilliam.Krier@Sun.COM 	if (strpbrk(sharename, invalid) != NULL)
90311337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_NAME);
90411337SWilliam.Krier@Sun.COM 
90511337SWilliam.Krier@Sun.COM 	for (p = sharename; *p != '\0'; p++) {
90611337SWilliam.Krier@Sun.COM 		if (iscntrl(*p))
90711337SWilliam.Krier@Sun.COM 			return (ERROR_INVALID_NAME);
90811337SWilliam.Krier@Sun.COM 	}
90911337SWilliam.Krier@Sun.COM 
91011337SWilliam.Krier@Sun.COM 	return (ERROR_SUCCESS);
91111337SWilliam.Krier@Sun.COM }
91211337SWilliam.Krier@Sun.COM 
91311337SWilliam.Krier@Sun.COM /*
91411337SWilliam.Krier@Sun.COM  * User and group names are limited to 256 characters, cannot be terminated
91511337SWilliam.Krier@Sun.COM  * by '.' and must not contain control characters or any of the following
91611337SWilliam.Krier@Sun.COM  * characters.
91711337SWilliam.Krier@Sun.COM  *
91811337SWilliam.Krier@Sun.COM  *	" / \ [ ] < > + ; , ? * = @
91911337SWilliam.Krier@Sun.COM  */
92011337SWilliam.Krier@Sun.COM uint32_t
smb_name_validate_account(const char * name)92111337SWilliam.Krier@Sun.COM smb_name_validate_account(const char *name)
92211337SWilliam.Krier@Sun.COM {
92311337SWilliam.Krier@Sun.COM 	const char	*invalid = "\"/\\[]<>+;,?*=@";
92411337SWilliam.Krier@Sun.COM 	const char	*p;
92511337SWilliam.Krier@Sun.COM 	int		len;
92611337SWilliam.Krier@Sun.COM 
92711337SWilliam.Krier@Sun.COM 	if ((name == NULL) || (*name == '\0'))
92811337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_PARAMETER);
92911337SWilliam.Krier@Sun.COM 
93011337SWilliam.Krier@Sun.COM 	len = strlen(name);
93111337SWilliam.Krier@Sun.COM 	if ((len > MAXNAMELEN) || (name[len - 1] == '.'))
93211337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_NAME);
93311337SWilliam.Krier@Sun.COM 
93411337SWilliam.Krier@Sun.COM 	if (strpbrk(name, invalid) != NULL)
93511337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_NAME);
93611337SWilliam.Krier@Sun.COM 
93711337SWilliam.Krier@Sun.COM 	for (p = name; *p != '\0'; p++) {
93811337SWilliam.Krier@Sun.COM 		if (iscntrl(*p))
93911337SWilliam.Krier@Sun.COM 			return (ERROR_INVALID_NAME);
94011337SWilliam.Krier@Sun.COM 	}
94111337SWilliam.Krier@Sun.COM 
94211337SWilliam.Krier@Sun.COM 	return (ERROR_SUCCESS);
94311337SWilliam.Krier@Sun.COM }
94411337SWilliam.Krier@Sun.COM 
94511337SWilliam.Krier@Sun.COM /*
94611337SWilliam.Krier@Sun.COM  * Check a domain name for RFC 1035 and 1123 compliance.  Domain names may
94711337SWilliam.Krier@Sun.COM  * contain alphanumeric characters, hyphens and dots.  The first and last
94811337SWilliam.Krier@Sun.COM  * character of a label must be alphanumeric.  Interior characters may be
94911337SWilliam.Krier@Sun.COM  * alphanumeric or hypens.
95011337SWilliam.Krier@Sun.COM  *
95111337SWilliam.Krier@Sun.COM  * Domain names should not contain underscores but we allow them because
95211337SWilliam.Krier@Sun.COM  * Windows names are often in non-compliance with this rule.
95311337SWilliam.Krier@Sun.COM  */
95411337SWilliam.Krier@Sun.COM uint32_t
smb_name_validate_domain(const char * domain)95511337SWilliam.Krier@Sun.COM smb_name_validate_domain(const char *domain)
95611337SWilliam.Krier@Sun.COM {
95711337SWilliam.Krier@Sun.COM 	boolean_t new_label = B_TRUE;
95811337SWilliam.Krier@Sun.COM 	const char *p;
95911337SWilliam.Krier@Sun.COM 	char label_terminator;
96011337SWilliam.Krier@Sun.COM 
96111337SWilliam.Krier@Sun.COM 	if (domain == NULL)
96211337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_PARAMETER);
96311337SWilliam.Krier@Sun.COM 
96411337SWilliam.Krier@Sun.COM 	if (*domain == '\0')
96511337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_NAME);
96611337SWilliam.Krier@Sun.COM 
96711337SWilliam.Krier@Sun.COM 	label_terminator = *domain;
96811337SWilliam.Krier@Sun.COM 
96911337SWilliam.Krier@Sun.COM 	for (p = domain; *p != '\0'; ++p) {
97011337SWilliam.Krier@Sun.COM 		if (new_label) {
97111337SWilliam.Krier@Sun.COM 			if (!isalnum(*p))
97211337SWilliam.Krier@Sun.COM 				return (ERROR_INVALID_NAME);
97311337SWilliam.Krier@Sun.COM 			new_label = B_FALSE;
97411337SWilliam.Krier@Sun.COM 			label_terminator = *p;
97511337SWilliam.Krier@Sun.COM 			continue;
97611337SWilliam.Krier@Sun.COM 		}
97711337SWilliam.Krier@Sun.COM 
97811337SWilliam.Krier@Sun.COM 		if (*p == '.') {
97911337SWilliam.Krier@Sun.COM 			if (!isalnum(label_terminator))
98011337SWilliam.Krier@Sun.COM 				return (ERROR_INVALID_NAME);
98111337SWilliam.Krier@Sun.COM 			new_label = B_TRUE;
98211337SWilliam.Krier@Sun.COM 			label_terminator = *p;
98311337SWilliam.Krier@Sun.COM 			continue;
98411337SWilliam.Krier@Sun.COM 		}
98511337SWilliam.Krier@Sun.COM 
98611337SWilliam.Krier@Sun.COM 		label_terminator = *p;
98711337SWilliam.Krier@Sun.COM 
98811337SWilliam.Krier@Sun.COM 		if (isalnum(*p) || *p == '-' || *p == '_')
98911337SWilliam.Krier@Sun.COM 			continue;
99011337SWilliam.Krier@Sun.COM 
99111337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_NAME);
99211337SWilliam.Krier@Sun.COM 	}
99311337SWilliam.Krier@Sun.COM 
99411337SWilliam.Krier@Sun.COM 	if (!isalnum(label_terminator))
99511337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_NAME);
99611337SWilliam.Krier@Sun.COM 
99711337SWilliam.Krier@Sun.COM 	return (ERROR_SUCCESS);
99811337SWilliam.Krier@Sun.COM }
99911337SWilliam.Krier@Sun.COM 
100011337SWilliam.Krier@Sun.COM /*
100111337SWilliam.Krier@Sun.COM  * A NetBIOS domain name can contain letters (a-zA-Z), numbers (0-9) and
100211337SWilliam.Krier@Sun.COM  * hyphens.
100311337SWilliam.Krier@Sun.COM  *
100411337SWilliam.Krier@Sun.COM  * It cannot:
100511337SWilliam.Krier@Sun.COM  * 	- be blank or longer than 15 chracters
100611337SWilliam.Krier@Sun.COM  * 	- contain all numbers
100711337SWilliam.Krier@Sun.COM  * 	- be the same as the computer name
100811337SWilliam.Krier@Sun.COM  */
100911337SWilliam.Krier@Sun.COM uint32_t
smb_name_validate_nbdomain(const char * name)101011337SWilliam.Krier@Sun.COM smb_name_validate_nbdomain(const char *name)
101111337SWilliam.Krier@Sun.COM {
101211337SWilliam.Krier@Sun.COM 	char		netbiosname[NETBIOS_NAME_SZ];
101311337SWilliam.Krier@Sun.COM 	const char	*p;
101411337SWilliam.Krier@Sun.COM 	int		len;
101511337SWilliam.Krier@Sun.COM 
101611337SWilliam.Krier@Sun.COM 	if (name == NULL)
101711337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_PARAMETER);
101811337SWilliam.Krier@Sun.COM 
101911337SWilliam.Krier@Sun.COM 	len = strlen(name);
102011337SWilliam.Krier@Sun.COM 	if (len == 0 || len >= NETBIOS_NAME_SZ)
102111337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_NAME);
102211337SWilliam.Krier@Sun.COM 
102311337SWilliam.Krier@Sun.COM 	if (strspn(name, "0123456789") == len)
102411337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_NAME);
102511337SWilliam.Krier@Sun.COM 
102611337SWilliam.Krier@Sun.COM 	if (smb_getnetbiosname(netbiosname, NETBIOS_NAME_SZ) == 0) {
102711337SWilliam.Krier@Sun.COM 		if (smb_strcasecmp(name, netbiosname, 0) == 0)
102811337SWilliam.Krier@Sun.COM 			return (ERROR_INVALID_NAME);
102911337SWilliam.Krier@Sun.COM 	}
103011337SWilliam.Krier@Sun.COM 
103111337SWilliam.Krier@Sun.COM 	for (p = name; *p != '\0'; ++p) {
103211337SWilliam.Krier@Sun.COM 		if (isalnum(*p) || *p == '-' || *p == '_')
103311337SWilliam.Krier@Sun.COM 			continue;
103411337SWilliam.Krier@Sun.COM 
103511337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_NAME);
103611337SWilliam.Krier@Sun.COM 	}
103711337SWilliam.Krier@Sun.COM 
103811337SWilliam.Krier@Sun.COM 	return (ERROR_SUCCESS);
103911337SWilliam.Krier@Sun.COM }
104011337SWilliam.Krier@Sun.COM 
104111337SWilliam.Krier@Sun.COM /*
104211337SWilliam.Krier@Sun.COM  * A workgroup name can contain 1 to 15 characters but cannot be the same
104311337SWilliam.Krier@Sun.COM  * as the NetBIOS name.  The name must begin with a letter or number.
104411337SWilliam.Krier@Sun.COM  *
104511337SWilliam.Krier@Sun.COM  * The name cannot consist entirely of spaces or dots, which is covered
104611337SWilliam.Krier@Sun.COM  * by the requirement that the name must begin with an alphanumeric
104711337SWilliam.Krier@Sun.COM  * character.
104811337SWilliam.Krier@Sun.COM  *
104911337SWilliam.Krier@Sun.COM  * The name must not contain control characters or any of the following
105011337SWilliam.Krier@Sun.COM  * characters.
105111337SWilliam.Krier@Sun.COM  *
105211337SWilliam.Krier@Sun.COM  *	" / \ [ ] : | < > + = ; , ?
105311337SWilliam.Krier@Sun.COM  */
105411337SWilliam.Krier@Sun.COM uint32_t
smb_name_validate_workgroup(const char * workgroup)105511337SWilliam.Krier@Sun.COM smb_name_validate_workgroup(const char *workgroup)
105611337SWilliam.Krier@Sun.COM {
105711337SWilliam.Krier@Sun.COM 	char netbiosname[NETBIOS_NAME_SZ];
105811337SWilliam.Krier@Sun.COM 	const char *invalid = "\"/\\[]:|<>+=;,?";
105911337SWilliam.Krier@Sun.COM 	const char *p;
106011337SWilliam.Krier@Sun.COM 
106111337SWilliam.Krier@Sun.COM 	if (workgroup == NULL)
106211337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_PARAMETER);
106311337SWilliam.Krier@Sun.COM 
106411337SWilliam.Krier@Sun.COM 	if (*workgroup == '\0' || (!isalnum(*workgroup)))
106511337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_NAME);
106611337SWilliam.Krier@Sun.COM 
106711337SWilliam.Krier@Sun.COM 	if (strlen(workgroup) >= NETBIOS_NAME_SZ)
106811337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_NAME);
106911337SWilliam.Krier@Sun.COM 
107011337SWilliam.Krier@Sun.COM 	if (smb_getnetbiosname(netbiosname, NETBIOS_NAME_SZ) == 0) {
107111337SWilliam.Krier@Sun.COM 		if (smb_strcasecmp(workgroup, netbiosname, 0) == 0)
107211337SWilliam.Krier@Sun.COM 			return (ERROR_INVALID_NAME);
107311337SWilliam.Krier@Sun.COM 	}
107411337SWilliam.Krier@Sun.COM 
107511337SWilliam.Krier@Sun.COM 	if (strpbrk(workgroup, invalid) != NULL)
107611337SWilliam.Krier@Sun.COM 		return (ERROR_INVALID_NAME);
107711337SWilliam.Krier@Sun.COM 
107811337SWilliam.Krier@Sun.COM 	for (p = workgroup; *p != '\0'; p++) {
107911337SWilliam.Krier@Sun.COM 		if (iscntrl(*p))
108011337SWilliam.Krier@Sun.COM 			return (ERROR_INVALID_NAME);
108111337SWilliam.Krier@Sun.COM 	}
108211337SWilliam.Krier@Sun.COM 
108311337SWilliam.Krier@Sun.COM 	return (ERROR_SUCCESS);
108411337SWilliam.Krier@Sun.COM }
108511337SWilliam.Krier@Sun.COM 
108611337SWilliam.Krier@Sun.COM /*
108711963SAfshin.Ardakani@Sun.COM  * Check for invalid characters in the given path.  The list of invalid
108811963SAfshin.Ardakani@Sun.COM  * characters includes control characters and the following:
108911963SAfshin.Ardakani@Sun.COM  *
109011963SAfshin.Ardakani@Sun.COM  * " / \ [ ] : | < > + ; , ? * =
109111963SAfshin.Ardakani@Sun.COM  *
109211963SAfshin.Ardakani@Sun.COM  * Since this is checking a path not each component, '/' is accepted
109311963SAfshin.Ardakani@Sun.COM  * as separator not an invalid character, except as the first character
109411963SAfshin.Ardakani@Sun.COM  * since this is supposed to be a relative path.
109511963SAfshin.Ardakani@Sun.COM  */
109611963SAfshin.Ardakani@Sun.COM uint32_t
smb_name_validate_rpath(const char * relpath)109711963SAfshin.Ardakani@Sun.COM smb_name_validate_rpath(const char *relpath)
109811963SAfshin.Ardakani@Sun.COM {
109911963SAfshin.Ardakani@Sun.COM 	char *invalid = "\"\\[]:|<>+;,?*=";
110011963SAfshin.Ardakani@Sun.COM 	char *cp;
110111963SAfshin.Ardakani@Sun.COM 
110211963SAfshin.Ardakani@Sun.COM 	if ((relpath == NULL) || (*relpath == '\0') || (*relpath == '/'))
110311963SAfshin.Ardakani@Sun.COM 		return (ERROR_INVALID_NAME);
110411963SAfshin.Ardakani@Sun.COM 
110511963SAfshin.Ardakani@Sun.COM 	if (strpbrk(relpath, invalid))
110611963SAfshin.Ardakani@Sun.COM 		return (ERROR_INVALID_NAME);
110711963SAfshin.Ardakani@Sun.COM 
110811963SAfshin.Ardakani@Sun.COM 	for (cp = (char *)relpath; *cp != '\0'; cp++) {
110911963SAfshin.Ardakani@Sun.COM 		if (iscntrl(*cp))
111011963SAfshin.Ardakani@Sun.COM 			return (ERROR_INVALID_NAME);
111111963SAfshin.Ardakani@Sun.COM 	}
111211963SAfshin.Ardakani@Sun.COM 
111311963SAfshin.Ardakani@Sun.COM 	return (ERROR_SUCCESS);
111411963SAfshin.Ardakani@Sun.COM }
111511963SAfshin.Ardakani@Sun.COM 
111611963SAfshin.Ardakani@Sun.COM /*
111711337SWilliam.Krier@Sun.COM  * Parse a string to obtain the account and domain names as separate strings.
111811337SWilliam.Krier@Sun.COM  *
111911337SWilliam.Krier@Sun.COM  * Names containing a backslash ('\') are known as qualified or composite
112011337SWilliam.Krier@Sun.COM  * names.  The string preceding the backslash should be the domain name
112111337SWilliam.Krier@Sun.COM  * and the string following the slash should be a name within that domain.
112211337SWilliam.Krier@Sun.COM  *
112311337SWilliam.Krier@Sun.COM  * Names that do not contain a backslash are known as isolated names.
112411337SWilliam.Krier@Sun.COM  * An isolated name may be a single label, such as john, or may be in
112511337SWilliam.Krier@Sun.COM  * user principal name (UPN) form, such as john@example.com.
112611337SWilliam.Krier@Sun.COM  *
112711337SWilliam.Krier@Sun.COM  *	domain\name
112811337SWilliam.Krier@Sun.COM  *	domain/name
112911337SWilliam.Krier@Sun.COM  *	name
113011337SWilliam.Krier@Sun.COM  *	name@domain
113111337SWilliam.Krier@Sun.COM  *
113211337SWilliam.Krier@Sun.COM  * If we encounter any of the forms above in arg, the @, / or \ separator
113311337SWilliam.Krier@Sun.COM  * is replaced by \0 and the name and domain pointers are set to point to
113411337SWilliam.Krier@Sun.COM  * the appropriate components in arg.  Otherwise, name and domain pointers
113511337SWilliam.Krier@Sun.COM  * will be set to NULL.
113611337SWilliam.Krier@Sun.COM  */
113711337SWilliam.Krier@Sun.COM void
smb_name_parse(char * arg,char ** account,char ** domain)113811337SWilliam.Krier@Sun.COM smb_name_parse(char *arg, char **account, char **domain)
113911337SWilliam.Krier@Sun.COM {
114011337SWilliam.Krier@Sun.COM 	char *p;
114111337SWilliam.Krier@Sun.COM 
114211337SWilliam.Krier@Sun.COM 	*account = NULL;
114311337SWilliam.Krier@Sun.COM 	*domain = NULL;
114411337SWilliam.Krier@Sun.COM 
114511337SWilliam.Krier@Sun.COM 	if ((p = strpbrk(arg, "/\\@")) != NULL) {
114611337SWilliam.Krier@Sun.COM 		if (*p == '@') {
114711337SWilliam.Krier@Sun.COM 			*p = '\0';
114811337SWilliam.Krier@Sun.COM 			++p;
114911337SWilliam.Krier@Sun.COM 			*domain = p;
115011337SWilliam.Krier@Sun.COM 			*account = arg;
115111337SWilliam.Krier@Sun.COM 		} else {
115211337SWilliam.Krier@Sun.COM 			*p = '\0';
115311337SWilliam.Krier@Sun.COM 			++p;
115411337SWilliam.Krier@Sun.COM 			*account = p;
115511337SWilliam.Krier@Sun.COM 			*domain = arg;
115611337SWilliam.Krier@Sun.COM 		}
115711337SWilliam.Krier@Sun.COM 	}
115811337SWilliam.Krier@Sun.COM }
1159*12508Samw@Sun.COM 
1160*12508Samw@Sun.COM /*
1161*12508Samw@Sun.COM  * The txid is an arbitrary transaction.  A new txid is returned on each call.
1162*12508Samw@Sun.COM  *
1163*12508Samw@Sun.COM  * 0 or -1 are not assigned so that they can be used to detect
1164*12508Samw@Sun.COM  * invalid conditions.
1165*12508Samw@Sun.COM  */
1166*12508Samw@Sun.COM uint32_t
smb_get_txid(void)1167*12508Samw@Sun.COM smb_get_txid(void)
1168*12508Samw@Sun.COM {
1169*12508Samw@Sun.COM 	static mutex_t	txmutex;
1170*12508Samw@Sun.COM 	static uint32_t	txid;
1171*12508Samw@Sun.COM 	uint32_t	txid_ret;
1172*12508Samw@Sun.COM 
1173*12508Samw@Sun.COM 	(void) mutex_lock(&txmutex);
1174*12508Samw@Sun.COM 
1175*12508Samw@Sun.COM 	if (txid == 0)
1176*12508Samw@Sun.COM 		txid = time(NULL);
1177*12508Samw@Sun.COM 
1178*12508Samw@Sun.COM 	do {
1179*12508Samw@Sun.COM 		++txid;
1180*12508Samw@Sun.COM 	} while (txid == 0 || txid == (uint32_t)-1);
1181*12508Samw@Sun.COM 
1182*12508Samw@Sun.COM 	txid_ret = txid;
1183*12508Samw@Sun.COM 	(void) mutex_unlock(&txmutex);
1184*12508Samw@Sun.COM 
1185*12508Samw@Sun.COM 	return (txid_ret);
1186*12508Samw@Sun.COM }
1187*12508Samw@Sun.COM 
1188*12508Samw@Sun.COM /*
1189*12508Samw@Sun.COM  *  Creates a log object and inserts it into a list of logs.
1190*12508Samw@Sun.COM  */
1191*12508Samw@Sun.COM smb_log_hdl_t
smb_log_create(int max_cnt,char * name)1192*12508Samw@Sun.COM smb_log_create(int max_cnt, char *name)
1193*12508Samw@Sun.COM {
1194*12508Samw@Sun.COM 	smb_loglist_item_t *log_node;
1195*12508Samw@Sun.COM 	smb_log_t *log = NULL;
1196*12508Samw@Sun.COM 	smb_log_hdl_t handle = 0;
1197*12508Samw@Sun.COM 
1198*12508Samw@Sun.COM 	if (max_cnt <= 0 || name == NULL)
1199*12508Samw@Sun.COM 		return (0);
1200*12508Samw@Sun.COM 
1201*12508Samw@Sun.COM 	(void) mutex_lock(&smb_loglist.ll_mtx);
1202*12508Samw@Sun.COM 
1203*12508Samw@Sun.COM 	log_node = malloc(sizeof (smb_loglist_item_t));
1204*12508Samw@Sun.COM 
1205*12508Samw@Sun.COM 	if (log_node != NULL) {
1206*12508Samw@Sun.COM 		log = &log_node->lli_log;
1207*12508Samw@Sun.COM 
1208*12508Samw@Sun.COM 		bzero(log, sizeof (smb_log_t));
1209*12508Samw@Sun.COM 
1210*12508Samw@Sun.COM 		handle = log->l_handle = smb_get_txid();
1211*12508Samw@Sun.COM 		log->l_max_cnt = max_cnt;
1212*12508Samw@Sun.COM 		(void) snprintf(log->l_file, sizeof (log->l_file),
1213*12508Samw@Sun.COM 		    SMB_LOG_FILE_FMT, name);
1214*12508Samw@Sun.COM 
1215*12508Samw@Sun.COM 		list_create(&log->l_list, sizeof (smb_log_item_t),
1216*12508Samw@Sun.COM 		    offsetof(smb_log_item_t, li_lnd));
1217*12508Samw@Sun.COM 
1218*12508Samw@Sun.COM 		if (smb_loglist.ll_list.list_size == 0)
1219*12508Samw@Sun.COM 			list_create(&smb_loglist.ll_list,
1220*12508Samw@Sun.COM 			    sizeof (smb_loglist_item_t),
1221*12508Samw@Sun.COM 			    offsetof(smb_loglist_item_t, lli_lnd));
1222*12508Samw@Sun.COM 
1223*12508Samw@Sun.COM 		list_insert_tail(&smb_loglist.ll_list, log_node);
1224*12508Samw@Sun.COM 	}
1225*12508Samw@Sun.COM 
1226*12508Samw@Sun.COM 	(void) mutex_unlock(&smb_loglist.ll_mtx);
1227*12508Samw@Sun.COM 
1228*12508Samw@Sun.COM 	return (handle);
1229*12508Samw@Sun.COM }
1230*12508Samw@Sun.COM 
1231*12508Samw@Sun.COM /*
1232*12508Samw@Sun.COM  * Keep the most recent log entries, based on max count.
1233*12508Samw@Sun.COM  * If the priority is LOG_ERR or higher then the entire log is
1234*12508Samw@Sun.COM  * dumped to a file.
1235*12508Samw@Sun.COM  *
1236*12508Samw@Sun.COM  * The date format for each message is the same as a syslog entry.
1237*12508Samw@Sun.COM  *
1238*12508Samw@Sun.COM  * The log is also added to syslog via smb_log_trace().
1239*12508Samw@Sun.COM  */
1240*12508Samw@Sun.COM void
smb_log(smb_log_hdl_t hdl,int priority,const char * fmt,...)1241*12508Samw@Sun.COM smb_log(smb_log_hdl_t hdl, int priority, const char *fmt, ...)
1242*12508Samw@Sun.COM {
1243*12508Samw@Sun.COM 	va_list		ap;
1244*12508Samw@Sun.COM 	smb_log_t	*log;
1245*12508Samw@Sun.COM 	smb_log_item_t	*msg;
1246*12508Samw@Sun.COM 	time_t		now;
1247*12508Samw@Sun.COM 	struct		tm *tm;
1248*12508Samw@Sun.COM 	char		timebuf[SMB_TIMEBUF_SZ];
1249*12508Samw@Sun.COM 	char		buf[SMB_TRACEBUF_SZ];
1250*12508Samw@Sun.COM 	char		netbiosname[NETBIOS_NAME_SZ];
1251*12508Samw@Sun.COM 	char		*pri_name;
1252*12508Samw@Sun.COM 	int		i;
1253*12508Samw@Sun.COM 
1254*12508Samw@Sun.COM 	va_start(ap, fmt);
1255*12508Samw@Sun.COM 	(void) vsnprintf(buf, SMB_TRACEBUF_SZ, fmt, ap);
1256*12508Samw@Sun.COM 	va_end(ap);
1257*12508Samw@Sun.COM 
1258*12508Samw@Sun.COM 	priority &= LOG_PRIMASK;
1259*12508Samw@Sun.COM 	smb_log_trace(priority, buf);
1260*12508Samw@Sun.COM 
1261*12508Samw@Sun.COM 	if ((log = smb_log_get(hdl)) == NULL)
1262*12508Samw@Sun.COM 		return;
1263*12508Samw@Sun.COM 
1264*12508Samw@Sun.COM 	(void) mutex_lock(&log->l_mtx);
1265*12508Samw@Sun.COM 
1266*12508Samw@Sun.COM 	(void) time(&now);
1267*12508Samw@Sun.COM 	tm = localtime(&now);
1268*12508Samw@Sun.COM 	(void) strftime(timebuf, SMB_TIMEBUF_SZ, "%b %d %H:%M:%S", tm);
1269*12508Samw@Sun.COM 
1270*12508Samw@Sun.COM 	if (smb_getnetbiosname(netbiosname, NETBIOS_NAME_SZ) != 0)
1271*12508Samw@Sun.COM 		(void) strlcpy(netbiosname, "unknown", NETBIOS_NAME_SZ);
1272*12508Samw@Sun.COM 
1273*12508Samw@Sun.COM 	if (log->l_cnt == log->l_max_cnt) {
1274*12508Samw@Sun.COM 		msg = list_head(&log->l_list);
1275*12508Samw@Sun.COM 		list_remove(&log->l_list, msg);
1276*12508Samw@Sun.COM 	} else {
1277*12508Samw@Sun.COM 		if ((msg = malloc(sizeof (smb_log_item_t))) == NULL) {
1278*12508Samw@Sun.COM 			(void) mutex_unlock(&log->l_mtx);
1279*12508Samw@Sun.COM 			return;
1280*12508Samw@Sun.COM 		}
1281*12508Samw@Sun.COM 		log->l_cnt++;
1282*12508Samw@Sun.COM 	}
1283*12508Samw@Sun.COM 
1284*12508Samw@Sun.COM 	pri_name = "info";
1285*12508Samw@Sun.COM 	for (i = 0; i < sizeof (smb_log_pri) / sizeof (smb_log_pri[0]); i++) {
1286*12508Samw@Sun.COM 		if (priority == smb_log_pri[i].lp_value) {
1287*12508Samw@Sun.COM 			pri_name = smb_log_pri[i].lp_name;
1288*12508Samw@Sun.COM 			break;
1289*12508Samw@Sun.COM 		}
1290*12508Samw@Sun.COM 	}
1291*12508Samw@Sun.COM 
1292*12508Samw@Sun.COM 	(void) snprintf(msg->li_msg, SMB_LOG_LINE_SZ,
1293*12508Samw@Sun.COM 	    "%s %s smb[%d]: [ID 0 daemon.%s] %s",
1294*12508Samw@Sun.COM 	    timebuf, netbiosname, getpid(), pri_name, buf);
1295*12508Samw@Sun.COM 	list_insert_tail(&log->l_list, msg);
1296*12508Samw@Sun.COM 
1297*12508Samw@Sun.COM 	if (priority <= LOG_ERR)
1298*12508Samw@Sun.COM 		smb_log_dump(log);
1299*12508Samw@Sun.COM 
1300*12508Samw@Sun.COM 	(void) mutex_unlock(&log->l_mtx);
1301*12508Samw@Sun.COM }
1302*12508Samw@Sun.COM 
1303*12508Samw@Sun.COM /*
1304*12508Samw@Sun.COM  * Dumps all the logs in the log list.
1305*12508Samw@Sun.COM  */
1306*12508Samw@Sun.COM void
smb_log_dumpall()1307*12508Samw@Sun.COM smb_log_dumpall()
1308*12508Samw@Sun.COM {
1309*12508Samw@Sun.COM 	smb_loglist_item_t *log_node;
1310*12508Samw@Sun.COM 
1311*12508Samw@Sun.COM 	(void) mutex_lock(&smb_loglist.ll_mtx);
1312*12508Samw@Sun.COM 
1313*12508Samw@Sun.COM 	log_node = list_head(&smb_loglist.ll_list);
1314*12508Samw@Sun.COM 
1315*12508Samw@Sun.COM 	while (log_node != NULL) {
1316*12508Samw@Sun.COM 		smb_log_dump(&log_node->lli_log);
1317*12508Samw@Sun.COM 		log_node = list_next(&smb_loglist.ll_list, log_node);
1318*12508Samw@Sun.COM 	}
1319*12508Samw@Sun.COM 
1320*12508Samw@Sun.COM 	(void) mutex_unlock(&smb_loglist.ll_mtx);
1321*12508Samw@Sun.COM }
1322*12508Samw@Sun.COM 
1323*12508Samw@Sun.COM static void
smb_log_trace(int priority,const char * s)1324*12508Samw@Sun.COM smb_log_trace(int priority, const char *s)
1325*12508Samw@Sun.COM {
1326*12508Samw@Sun.COM 	syslog(priority, "%s", s);
1327*12508Samw@Sun.COM }
1328*12508Samw@Sun.COM 
1329*12508Samw@Sun.COM static smb_log_t *
smb_log_get(smb_log_hdl_t hdl)1330*12508Samw@Sun.COM smb_log_get(smb_log_hdl_t hdl)
1331*12508Samw@Sun.COM {
1332*12508Samw@Sun.COM 	smb_loglist_item_t *log_node;
1333*12508Samw@Sun.COM 	smb_log_t *log;
1334*12508Samw@Sun.COM 
1335*12508Samw@Sun.COM 	(void) mutex_lock(&smb_loglist.ll_mtx);
1336*12508Samw@Sun.COM 
1337*12508Samw@Sun.COM 	log_node = list_head(&smb_loglist.ll_list);
1338*12508Samw@Sun.COM 
1339*12508Samw@Sun.COM 	while (log_node != NULL) {
1340*12508Samw@Sun.COM 		if (log_node->lli_log.l_handle == hdl) {
1341*12508Samw@Sun.COM 			log = &log_node->lli_log;
1342*12508Samw@Sun.COM 			(void) mutex_unlock(&smb_loglist.ll_mtx);
1343*12508Samw@Sun.COM 			return (log);
1344*12508Samw@Sun.COM 		}
1345*12508Samw@Sun.COM 		log_node = list_next(&smb_loglist.ll_list, log_node);
1346*12508Samw@Sun.COM 	}
1347*12508Samw@Sun.COM 
1348*12508Samw@Sun.COM 	(void) mutex_unlock(&smb_loglist.ll_mtx);
1349*12508Samw@Sun.COM 	return (NULL);
1350*12508Samw@Sun.COM }
1351*12508Samw@Sun.COM 
1352*12508Samw@Sun.COM /*
1353*12508Samw@Sun.COM  * Dumps the log to a file.
1354*12508Samw@Sun.COM  */
1355*12508Samw@Sun.COM static void
smb_log_dump(smb_log_t * log)1356*12508Samw@Sun.COM smb_log_dump(smb_log_t *log)
1357*12508Samw@Sun.COM {
1358*12508Samw@Sun.COM 	smb_log_item_t *msg;
1359*12508Samw@Sun.COM 	FILE *fp;
1360*12508Samw@Sun.COM 
1361*12508Samw@Sun.COM 	if ((fp = fopen(log->l_file, "w")) == NULL)
1362*12508Samw@Sun.COM 		return;
1363*12508Samw@Sun.COM 
1364*12508Samw@Sun.COM 	msg = list_head(&log->l_list);
1365*12508Samw@Sun.COM 
1366*12508Samw@Sun.COM 	while (msg != NULL) {
1367*12508Samw@Sun.COM 		(void) fprintf(fp, "%s\n", msg->li_msg);
1368*12508Samw@Sun.COM 		msg = list_next(&log->l_list, msg);
1369*12508Samw@Sun.COM 	}
1370*12508Samw@Sun.COM 
1371*12508Samw@Sun.COM 	(void) fclose(fp);
1372*12508Samw@Sun.COM }
1373