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