summaryrefslogtreecommitdiff
path: root/source3/lib
diff options
context:
space:
mode:
Diffstat (limited to 'source3/lib')
-rw-r--r--source3/lib/.cvsignore3
-rw-r--r--source3/lib/access.c601
-rw-r--r--source3/lib/account_pol.c126
-rw-r--r--source3/lib/bitmap.c139
-rw-r--r--source3/lib/charcnv.c822
-rw-r--r--source3/lib/charset.c111
-rw-r--r--source3/lib/crc32.c67
-rw-r--r--source3/lib/debug.c771
-rw-r--r--source3/lib/dmallocmsg.c72
-rw-r--r--source3/lib/dprintf.c110
-rw-r--r--source3/lib/error.c72
-rw-r--r--source3/lib/fault.c58
-rw-r--r--source3/lib/fsusage.c148
-rw-r--r--source3/lib/genrand.c267
-rw-r--r--source3/lib/getsmbpass.c34
-rw-r--r--source3/lib/hash.c315
-rw-r--r--source3/lib/hmacmd5.c134
-rw-r--r--source3/lib/iconv.c581
-rw-r--r--source3/lib/interface.c370
-rw-r--r--source3/lib/interfaces.c401
-rw-r--r--source3/lib/kanji.c895
-rw-r--r--source3/lib/md4.c446
-rw-r--r--source3/lib/md5.c245
-rw-r--r--source3/lib/messages.c534
-rw-r--r--source3/lib/ms_fnmatch.c225
-rw-r--r--source3/lib/netatalk.c155
-rw-r--r--source3/lib/pam_errors.c125
-rw-r--r--source3/lib/pidfile.c112
-rw-r--r--source3/lib/readline.c119
-rw-r--r--source3/lib/replace.c416
-rw-r--r--source3/lib/select.c159
-rw-r--r--source3/lib/signal.c139
-rw-r--r--source3/lib/smbpasswd.c200
-rw-r--r--source3/lib/smbrun.c180
-rw-r--r--source3/lib/snprintf.c962
-rw-r--r--source3/lib/substitute.c358
-rw-r--r--source3/lib/sysacls.c3210
-rw-r--r--source3/lib/system.c1222
-rw-r--r--source3/lib/talloc.c441
-rw-r--r--source3/lib/tallocmsg.c58
-rw-r--r--source3/lib/talloctort.c65
-rw-r--r--source3/lib/time.c749
-rw-r--r--source3/lib/ufc.c67
-rw-r--r--source3/lib/username.c776
-rw-r--r--source3/lib/util.c5381
-rw-r--r--source3/lib/util_file.c595
-rw-r--r--source3/lib/util_getent.c318
-rw-r--r--source3/lib/util_pw.c133
-rw-r--r--source3/lib/util_seaccess.c446
-rw-r--r--source3/lib/util_sec.c422
-rw-r--r--source3/lib/util_sid.c720
-rw-r--r--source3/lib/util_sock.c1340
-rw-r--r--source3/lib/util_str.c1003
-rw-r--r--source3/lib/util_unistr.c777
-rw-r--r--source3/lib/wins_srv.c339
-rw-r--r--source3/lib/xfile.c339
56 files changed, 22962 insertions, 5911 deletions
diff --git a/source3/lib/.cvsignore b/source3/lib/.cvsignore
new file mode 100644
index 0000000000..07da2225c7
--- /dev/null
+++ b/source3/lib/.cvsignore
@@ -0,0 +1,3 @@
+*.po
+*.po32
+
diff --git a/source3/lib/access.c b/source3/lib/access.c
index 14a84b2fb4..f12ee92799 100644
--- a/source3/lib/access.c
+++ b/source3/lib/access.c
@@ -1,147 +1,162 @@
/*
-This module is an adaption of code from the tcpd-1.4 package written
-by Wietse Venema, Eindhoven University of Technology, The Netherlands.
+ This module is an adaption of code from the tcpd-1.4 package written
+ by Wietse Venema, Eindhoven University of Technology, The Netherlands.
-The code is used here with permission.
+ The code is used here with permission.
-The code has been considerably changed from the original. Bug reports
-should be sent to Andrew.Tridgell@anu.edu.au
+ The code has been considerably changed from the original. Bug reports
+ should be sent to samba@samba.org
*/
#include "includes.h"
-#include "loadparm.h"
-#define ALLOW_PURE_ADDRESSES
-
-extern int DEBUGLEVEL;
-
-#ifndef INADDR_NONE
-#define INADDR_NONE ((unsigned long)~0)
-#endif
-
-
-#define FROM_ADDRLEN (4*3+3+1)
-#define Good True
-#define Bad False
-
-#define CLIENT_MATCH client_match
-
-/* Delimiters for lists of daemons or clients. */
-
-static char sep[] = ", \t";
-
-/* Constants to be used in assignments only, not in comparisons... */
-
-#define YES 1
-#define NO 0
#define FAIL (-1)
-/* Forward declarations. */
-BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client);
-static int list_match(char *list,char *item, int (*match_fn)());
-static int client_match(char *tok,char *item);
-static int string_match(char *tok,char *s);
-static int masked_match(char *tok, char *slash, char *s);
-static int matchname(char *remotehost,struct in_addr addr);
-BOOL fromhost(int sock,struct from_host *f);
-
-
-/* Size of logical line buffer. */
-#define BUFLEN 2048
+#define ALLONES ((uint32)0xFFFFFFFF)
+/* masked_match - match address against netnumber/netmask */
+static int masked_match(char *tok, char *slash, char *s)
+{
+ uint32 net;
+ uint32 mask;
+ uint32 addr;
+
+ if ((addr = interpret_addr(s)) == INADDR_NONE)
+ return (False);
+ *slash = 0;
+ net = interpret_addr(tok);
+ *slash = '/';
+
+ if (strlen(slash + 1) > 2) {
+ mask = interpret_addr(slash + 1);
+ } else {
+ mask = (uint32)((ALLONES >> atoi(slash + 1)) ^ ALLONES);
+ }
+
+ if (net == INADDR_NONE || mask == INADDR_NONE) {
+ DEBUG(0,("access: bad net/mask access control: %s\n", tok));
+ return (False);
+ }
+ return ((addr & mask) == net);
+}
-/* return true if access should be allowed to a service*/
-BOOL check_access(int snum)
+/* string_match - match string against token */
+static int string_match(char *tok,char *s, char *invalid_char)
{
- extern int Client;
- extern struct from_host Client_info;
- char *denyl,*allowl;
- BOOL ret = False;
+ size_t tok_len;
+ size_t str_len;
+ char *cut;
+
+ *invalid_char = '\0';
+
+ /* Return True if a token has the magic value "ALL". Return
+ * FAIL if the token is "FAIL". If the token starts with a "."
+ * (domain name), return True if it matches the last fields of
+ * the string. If the token has the magic value "LOCAL",
+ * return True if the string does not contain a "."
+ * character. If the token ends on a "." (network number),
+ * return True if it matches the first fields of the
+ * string. If the token begins with a "@" (netgroup name),
+ * return True if the string is a (host) member of the
+ * netgroup. Return True if the token fully matches the
+ * string. If the token is a netnumber/netmask pair, return
+ * True if the address is a member of the specified subnet.
+ */
+
+ if (tok[0] == '.') { /* domain: match last fields */
+ if ((str_len = strlen(s)) > (tok_len = strlen(tok))
+ && strcasecmp(tok, s + str_len - tok_len) == 0)
+ return (True);
+ } else if (tok[0] == '@') { /* netgroup: look it up */
+#ifdef HAVE_NETGROUP
+ static char *mydomain = NULL;
+ char *hostname = NULL;
+ BOOL netgroup_ok = False;
+
+ if (!mydomain) yp_get_default_domain(&mydomain);
+
+ if (!mydomain) {
+ DEBUG(0,("Unable to get default yp domain.\n"));
+ return False;
+ }
+ if (!(hostname = strdup(s))) {
+ DEBUG(1,("out of memory for strdup!\n"));
+ return False;
+ }
+
+ netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain);
+
+ DEBUG(5,("looking for %s of domain %s in netgroup %s gave %s\n",
+ hostname,
+ mydomain,
+ tok+1,
+ BOOLSTR(netgroup_ok)));
+
+ SAFE_FREE(hostname);
+
+ if (netgroup_ok) return(True);
+#else
+ DEBUG(0,("access: netgroup support is not configured\n"));
+ return (False);
+#endif
+ } else if (strcasecmp(tok, "ALL") == 0) { /* all: match any */
+ return (True);
+ } else if (strcasecmp(tok, "FAIL") == 0) { /* fail: match any */
+ return (FAIL);
+ } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */
+ if (strchr_m(s, '.') == 0 && strcasecmp(s, "unknown") != 0)
+ return (True);
+ } else if (!strcasecmp(tok, s)) { /* match host name or address */
+ return (True);
+ } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { /* network */
+ if (strncmp(tok, s, tok_len) == 0)
+ return (True);
+ } else if ((cut = strchr_m(tok, '/')) != 0) { /* netnumber/netmask */
+ if (isdigit((int)s[0]) && masked_match(tok, cut, s))
+ return (True);
+ } else if (strchr_m(tok, '*') != 0) {
+ *invalid_char = '*';
+ } else if (strchr_m(tok, '?') != 0) {
+ *invalid_char = '?';
+ }
+ return (False);
+}
- denyl = lp_hostsdeny(snum);
- if (denyl) denyl = strdup(denyl);
- allowl = lp_hostsallow(snum);
- if (allowl) allowl = strdup(allowl);
+/* client_match - match host name and address against token */
+static int client_match(char *tok,char *item)
+{
+ char **client = (char **)item;
+ int match;
+ char invalid_char = '\0';
+ /*
+ * Try to match the address first. If that fails, try to match the host
+ * name if available.
+ */
- fromhost(Client,&Client_info);
+ if ((match = string_match(tok, client[1], &invalid_char)) == 0) {
+ if(invalid_char)
+ DEBUG(0,("client_match: address match failing due to invalid character '%c' found in \
+token '%s' in an allow/deny hosts line.\n", invalid_char, tok ));
- if ((!denyl || *denyl==0) && (!allowl || *allowl==0))
- ret = True;
+ if (client[0][0] != 0)
+ match = string_match(tok, client[0], &invalid_char);
- if (!ret)
- {
- if (!fromhost(Client,&Client_info))
- DEBUG(0,("ERROR: Can't get from_host info\n"));
- else
- {
- if (allow_access(denyl,allowl,&Client_info))
- {
- if (snum >= 0)
- DEBUG(2,("Allowed connection from %s (%s) to %s\n",
- Client_info.name,Client_info.addr,
- lp_servicename(snum)));
- ret = True;
- }
- else
- if (snum >= 0)
- DEBUG(0,("Denied connection from %s (%s) to %s\n",
- Client_info.name,Client_info.addr,
- lp_servicename(snum)));
+ if(invalid_char)
+ DEBUG(0,("client_match: address match failing due to invalid character '%c' found in \
+token '%s' in an allow/deny hosts line.\n", invalid_char, tok ));
}
- }
-
- if (denyl) free(denyl);
- if (allowl) free(allowl);
- return(ret);
-}
-
-/* return true if access should be allowed */
-BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client)
-{
- /* if theres no deny list and no allow list then allow access */
- if ((!deny_list || *deny_list == 0) && (!allow_list || *allow_list == 0))
- return(True);
-
- /* if there is an allow list but no deny list then allow only hosts
- on the allow list */
- if (!deny_list || *deny_list == 0)
- return(list_match(allow_list,(char *)client,CLIENT_MATCH));
-
- /* if theres a deny list but no allow list then allow
- all hosts not on the deny list */
- if (!allow_list || *allow_list == 0)
- return(!list_match(deny_list,(char *)client,CLIENT_MATCH));
-
- /* if there are both type of list then allow all hosts on the allow list */
- if (list_match(allow_list,(char *)client,CLIENT_MATCH))
- return (True);
-
- /* if there are both type of list and it's not on the allow then
- allow it if its not on the deny */
- if (list_match(deny_list,(char *)client,CLIENT_MATCH))
- return (False);
-
- return (True);
+ return (match);
}
/* list_match - match an item against a list of tokens with exceptions */
-/* (All modifications are marked with the initials "jkf") */
-static int list_match(char *list,char *item, int (*match_fn)())
+static int list_match(char **list,char *item, int (*match_fn)(char *, char *))
{
- char *tok;
- char *listcopy; /* jkf */
- int match = NO;
-
- /*
- * jkf@soton.ac.uk -- 31 August 1994 -- Stop list_match()
- * overwriting the list given as its first parameter.
- */
+ int match = False;
- /* jkf -- can get called recursively with NULL list */
- listcopy = (list == 0) ? (char *)0 : strdup(list);
+ if (!list) return False;
/*
* Process tokens one at a time. We have exhausted all possible matches
@@ -150,240 +165,158 @@ static int list_match(char *list,char *item, int (*match_fn)())
* the match is affected by any exceptions.
*/
- for (tok = strtok(listcopy, sep); tok ; tok = strtok(NULL, sep)) {
- if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */
+ for (; *list ; list++) {
+ if (strcasecmp(*list, "EXCEPT") == 0) /* EXCEPT: give up */
break;
- if ((match = (*match_fn) (tok, item))) /* YES or FAIL */
+ if ((match = (*match_fn) (*list, item))) /* True or FAIL */
break;
}
- /* Process exceptions to YES or FAIL matches. */
-
- if (match != NO) {
- while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT"))
- /* VOID */ ;
- if (tok == 0 || list_match((char *) 0, item, match_fn) == NO) {
- if (listcopy != 0) free(listcopy); /* jkf */
- return (match);
- }
- }
-
- if (listcopy != 0) free(listcopy); /* jkf */
- return (NO);
-}
+ /* Process exceptions to True or FAIL matches. */
+ if (match != False) {
+ while (*list && strcasecmp(*list, "EXCEPT"))
+ list++;
-/* client_match - match host name and address against token */
-static int client_match(char *tok,char *item)
-{
- struct from_host *client = (struct from_host *) item;
- int match;
-
- /*
- * Try to match the address first. If that fails, try to match the host
- * name if available.
- */
+ for (; *list; list++) {
+ if ((*match_fn) (*list, item)) /* Exception Found */
+ return False;
+ }
+ }
- if ((match = string_match(tok, client->addr)) == 0)
- if (client->name[0] != 0)
- match = string_match(tok, client->name);
return (match);
}
-/* string_match - match string against token */
-static int string_match(char *tok,char *s)
-{
- int tok_len;
- int str_len;
- char *cut;
-
- /*
- * Return YES if a token has the magic value "ALL". Return FAIL if the
- * token is "FAIL". If the token starts with a "." (domain name), return
- * YES if it matches the last fields of the string. If the token has the
- * magic value "LOCAL", return YES if the string does not contain a "."
- * character. If the token ends on a "." (network number), return YES if
- * it matches the first fields of the string. If the token begins with a
- * "@" (netgroup name), return YES if the string is a (host) member of
- * the netgroup. Return YES if the token fully matches the string. If the
- * token is a netnumber/netmask pair, return YES if the address is a
- * member of the specified subnet.
- */
- if (tok[0] == '.') { /* domain: match last fields */
- if ((str_len = strlen(s)) > (tok_len = strlen(tok))
- && strcasecmp(tok, s + str_len - tok_len) == 0)
- return (YES);
- } else if (tok[0] == '@') { /* netgroup: look it up */
-#ifdef NETGROUP
- static char *mydomain = NULL;
- char *hostname = NULL;
- BOOL netgroup_ok = False;
-
- if (!mydomain) yp_get_default_domain(&mydomain);
-
- if (!(hostname = strdup(s))) {
- DEBUG(1,("out of memory for strdup!\n"));
- return NO;
- }
-
- netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain);
-
- DEBUG(5,("looking for %s of domain %s in netgroup %s gave %s\n",
- hostname,
- mydomain,
- tok+1,
- BOOLSTR(netgroup_ok)));
-
-#ifdef NETGROUP_INSECURE
- /* if you really want netgroups that match non qualified names
- then define NETGROUP_INSECURE. It can, however, be a big
- security hole */
- {
- char *clnt_domain;
- if (!netgroup_ok && (clnt_domain=strchr(hostname,'.'))) {
- *clnt_domain++ = '\0';
- netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain);
+/* return true if access should be allowed */
+BOOL allow_access(char **deny_list,char **allow_list,
+ char *cname,char *caddr)
+{
+ char *client[2];
+
+ client[0] = cname;
+ client[1] = caddr;
+
+ /* if it is loopback then always allow unless specifically denied */
+ if (strcmp(caddr, "127.0.0.1") == 0) {
+ /*
+ * If 127.0.0.1 matches both allow and deny then allow.
+ * Patch from Steve Langasek vorlon@netexpress.net.
+ */
+ if (deny_list &&
+ list_match(deny_list,(char *)client,client_match) &&
+ (!allow_list ||
+ !list_match(allow_list,(char *)client, client_match))) {
+ return False;
+ }
+ return True;
}
- }
-#endif
- free(hostname);
-
- if (netgroup_ok) return(YES);
-#else
- DEBUG(0,("access: netgroup support is not configured"));
- return (NO);
-#endif
- } else if (strcasecmp(tok, "ALL") == 0) { /* all: match any */
- return (YES);
- } else if (strcasecmp(tok, "FAIL") == 0) { /* fail: match any */
- return (FAIL);
- } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */
- if (strchr(s, '.') == 0 && strcasecmp(s, "unknown") != 0)
- return (YES);
- } else if (!strcasecmp(tok, s)) { /* match host name or address */
- return (YES);
- } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { /* network */
- if (strncmp(tok, s, tok_len) == 0)
- return (YES);
- } else if ((cut = strchr(tok, '/')) != 0) { /* netnumber/netmask */
- if (isdigit(s[0]) && masked_match(tok, cut, s))
- return (YES);
- }
- return (NO);
-}
+ /* if theres no deny list and no allow list then allow access */
+ if ((!deny_list || *deny_list == 0) &&
+ (!allow_list || *allow_list == 0)) {
+ return(True);
+ }
-/* masked_match - match address against netnumber/netmask */
-static int masked_match(char *tok, char *slash, char *s)
-{
- unsigned long net;
- unsigned long mask;
- unsigned long addr;
-
- if ((addr = interpret_addr(s)) == INADDR_NONE)
- return (NO);
- *slash = 0;
- net = interpret_addr(tok);
- *slash = '/';
- if (net == INADDR_NONE || (mask = interpret_addr(slash + 1)) == INADDR_NONE) {
- DEBUG(0,("access: bad net/mask access control: %s", tok));
- return (NO);
- }
- return ((addr & mask) == net);
+ /* if there is an allow list but no deny list then allow only hosts
+ on the allow list */
+ if (!deny_list || *deny_list == 0)
+ return(list_match(allow_list,(char *)client,client_match));
+
+ /* if theres a deny list but no allow list then allow
+ all hosts not on the deny list */
+ if (!allow_list || *allow_list == 0)
+ return(!list_match(deny_list,(char *)client,client_match));
+
+ /* if there are both types of list then allow all hosts on the
+ allow list */
+ if (list_match(allow_list,(char *)client,client_match))
+ return (True);
+
+ /* if there are both types of list and it's not on the allow then
+ allow it if its not on the deny */
+ if (list_match(deny_list,(char *)client,client_match))
+ return (False);
+
+ return (True);
}
-
-/* fromhost - find out what is at the other end of a socket */
-BOOL fromhost(int sock,struct from_host *f)
+/* return true if the char* contains ip addrs only. Used to avoid
+gethostbyaddr() calls */
+static BOOL only_ipaddrs_in_list(char** list)
{
- static struct sockaddr sa;
- struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
- struct hostent *hp;
- int length = sizeof(sa);
- static char addr_buf[FROM_ADDRLEN];
- static char name_buf[MAXHOSTNAMELEN];
- BOOL takeAddressAsHostname = False;
-
- if (getpeername(sock, &sa, &length) < 0)
- {
- DEBUG(0,("getpeername failed\n"));
- return(False);
- }
-
- f->sin = sockin;
- f->addr = strcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
-
- /* Look up the remote host name. */
- if ((hp = gethostbyaddr((char *) &sockin->sin_addr,
- sizeof(sockin->sin_addr),
- AF_INET)) == 0) {
- DEBUG(1,("Gethostbyaddr failed for %s\n",addr_buf));
-#ifdef ALLOW_PURE_ADDRESSES
- takeAddressAsHostname = True;
-#else
- return(False);
-#endif
- }
-
- /* Save the host name. A later gethostbyxxx() call may clobber it. */
- f->name = StrnCpy(name_buf,
- takeAddressAsHostname? f->addr : hp->h_name,
- sizeof(name_buf) - 1);
-
- /*
- * Verify that the host name does not belong to someone else. If host
- * name verification fails, pretend that the host name lookup failed.
- */
- if (!takeAddressAsHostname && !matchname(f->name, sockin->sin_addr))
- {
- DEBUG(0,("Matchname failed\n"));
- return(False);
- }
-
- return(True);
+ BOOL only_ip = True;
+
+ if (!list) return True;
+
+ for (; *list ; list++)
+ {
+ /* factor out the special strings */
+ if (!strcasecmp(*list, "ALL") || !strcasecmp(*list, "FAIL") ||
+ !strcasecmp(*list, "EXCEPT"))
+ {
+ continue;
+ }
+
+ if (!is_ipaddress(*list))
+ {
+ char *p;
+ /*
+ * if we failed, make sure that it was not because the token
+ * was a network/netmask pair. Only network/netmask pairs
+ * have a '/' in them
+ */
+ if ((p=strchr_m(*list, '/')) == NULL)
+ {
+ only_ip = False;
+ DEBUG(3,("only_ipaddrs_in_list: list has non-ip address (%s)\n", *list));
+ break;
+ }
+ }
+ }
+
+ return only_ip;
}
-/* matchname - determine if host name matches IP address */
-static int matchname(char *remotehost,struct in_addr addr)
+/* return true if access should be allowed to a service for a socket */
+BOOL check_access(int sock, char **allow_list, char **deny_list)
{
- struct hostent *hp;
- int i;
-
- if ((hp = Get_Hostbyname(remotehost)) == 0) {
- DEBUG(0,("Get_Hostbyname(%s): lookup failure", remotehost));
- return (Bad);
- }
-
- /*
- * Make sure that gethostbyname() returns the "correct" host name.
- * Unfortunately, gethostbyname("localhost") sometimes yields
- * "localhost.domain". Since the latter host name comes from the
- * local DNS, we just have to trust it (all bets are off if the local
- * DNS is perverted). We always check the address list, though.
- */
-
- if (strcasecmp(remotehost, hp->h_name)
- && strcasecmp(remotehost, "localhost")) {
- DEBUG(0,("host name/name mismatch: %s != %s",
- remotehost, hp->h_name));
- return (Bad);
- }
+ BOOL ret = False;
+ BOOL only_ip = False;
- /* Look up the host address in the address list we just got. */
- for (i = 0; hp->h_addr_list[i]; i++) {
- if (memcmp(hp->h_addr_list[i], (caddr_t) & addr, sizeof(addr)) == 0)
- return (Good);
- }
-
- /*
- * The host name does not map to the original host address. Perhaps
- * someone has compromised a name server. More likely someone botched
- * it, but that could be dangerous, too.
- */
-
- DEBUG(0,("host name/address mismatch: %s != %s",
- inet_ntoa(addr), hp->h_name));
- return (Bad);
-}
+ if ((!deny_list || *deny_list==0) && (!allow_list || *allow_list==0))
+ {
+ ret = True;
+ }
+ if (!ret)
+ {
+ /* bypass gethostbyaddr() calls if the lists only contain IP addrs */
+ if (only_ipaddrs_in_list(allow_list) && only_ipaddrs_in_list(deny_list))
+ {
+ only_ip = True;
+ DEBUG (3, ("check_access: no hostnames in host allow/deny list.\n"));
+ ret = allow_access(deny_list,allow_list, "", get_socket_addr(sock));
+ }
+ else
+ {
+ DEBUG (3, ("check_access: hostnames in host allow/deny list.\n"));
+ ret = allow_access(deny_list,allow_list, get_socket_name(sock),
+ get_socket_addr(sock));
+ }
+
+ if (ret)
+ {
+ DEBUG(2,("Allowed connection from %s (%s)\n",
+ only_ip ? "" : get_socket_name(sock),
+ get_socket_addr(sock)));
+ }
+ else
+ {
+ DEBUG(0,("Denied connection from %s (%s)\n",
+ only_ip ? "" : get_socket_name(sock),
+ get_socket_addr(sock)));
+ }
+ }
+ return(ret);
+}
diff --git a/source3/lib/account_pol.c b/source3/lib/account_pol.c
new file mode 100644
index 0000000000..07676e2202
--- /dev/null
+++ b/source3/lib/account_pol.c
@@ -0,0 +1,126 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * account policy storage
+ * Copyright (C) Jean François Micouleau 1998-2001.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+static TDB_CONTEXT *tdb; /* used for driver files */
+
+#define DATABASE_VERSION 1
+
+/****************************************************************************
+ Open the account policy tdb.
+****************************************************************************/
+
+BOOL init_account_policy(void)
+{
+ static pid_t local_pid;
+ char *vstring = "INFO/version";
+
+ if (tdb && local_pid == sys_getpid())
+ return True;
+ tdb = tdb_open_log(lock_path("account_policy.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if (!tdb) {
+ DEBUG(0,("Failed to open account policy database\n"));
+ return False;
+ }
+
+ local_pid = sys_getpid();
+
+ /* handle a Samba upgrade */
+ tdb_lock_bystring(tdb, vstring);
+ if (tdb_fetch_int32(tdb, vstring) != DATABASE_VERSION) {
+ tdb_traverse(tdb, tdb_traverse_delete_fn, NULL);
+ tdb_store_int32(tdb, vstring, DATABASE_VERSION);
+
+ account_policy_set(AP_MIN_PASSWORD_LEN, MINPASSWDLENGTH); /* 5 chars minimum */
+ account_policy_set(AP_PASSWORD_HISTORY, 0); /* don't keep any old password */
+ account_policy_set(AP_USER_MUST_LOGON_TO_CHG_PASS, 0); /* don't force user to logon */
+ account_policy_set(AP_MAX_PASSWORD_AGE, MAX_PASSWORD_AGE); /* 21 days */
+ account_policy_set(AP_MIN_PASSWORD_AGE, 0); /* 0 days */
+ account_policy_set(AP_LOCK_ACCOUNT_DURATION, 0); /* lockout for 0 minutes */
+ account_policy_set(AP_RESET_COUNT_TIME, 0); /* reset immediatly */
+ account_policy_set(AP_BAD_ATTEMPT_LOCKOUT, 0); /* don't lockout */
+ account_policy_set(AP_TIME_TO_LOGOUT, -1); /* don't force logout */
+ }
+ tdb_unlock_bystring(tdb, vstring);
+
+ return True;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static char *decode_account_policy_name(int field)
+{
+ switch (field) {
+ case AP_MIN_PASSWORD_LEN:
+ return "min password length";
+ case AP_PASSWORD_HISTORY:
+ return "password history";
+ case AP_USER_MUST_LOGON_TO_CHG_PASS:
+ return "user must logon to change password";
+ case AP_MAX_PASSWORD_AGE:
+ return "maximum password age";
+ case AP_MIN_PASSWORD_AGE:
+ return "minimum password age";
+ case AP_LOCK_ACCOUNT_DURATION:
+ return "lockout duration";
+ case AP_RESET_COUNT_TIME:
+ return "reset count minutes";
+ case AP_BAD_ATTEMPT_LOCKOUT:
+ return "bad lockout attempt";
+ case AP_TIME_TO_LOGOUT:
+ return "disconnect time";
+ default:
+ return "undefined value";
+ }
+}
+
+
+/****************************************************************************
+****************************************************************************/
+BOOL account_policy_get(int field, uint32 *value)
+{
+ fstring name;
+
+ init_account_policy();
+
+ fstrcpy(name, decode_account_policy_name(field));
+ *value=tdb_fetch_int32(tdb, name);
+ DEBUG(10,("account_policy_get: %s:%d\n", name, *value));
+ return True;
+}
+
+
+/****************************************************************************
+****************************************************************************/
+BOOL account_policy_set(int field, uint32 value)
+{
+ fstring name;
+
+ init_account_policy();
+
+ fstrcpy(name, decode_account_policy_name(field));
+ if ( tdb_store_int32(tdb, name, value)== -1)
+ return False;
+ DEBUG(10,("account_policy_set: %s:%d\n", name, value));
+
+ return True;
+}
+
diff --git a/source3/lib/bitmap.c b/source3/lib/bitmap.c
new file mode 100644
index 0000000000..8121c38bd5
--- /dev/null
+++ b/source3/lib/bitmap.c
@@ -0,0 +1,139 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple bitmap functions
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* these functions provide a simple way to allocate integers from a
+ pool without repetition */
+
+/****************************************************************************
+allocate a bitmap of the specified size
+****************************************************************************/
+struct bitmap *bitmap_allocate(int n)
+{
+ struct bitmap *bm;
+
+ bm = (struct bitmap *)malloc(sizeof(*bm));
+
+ if (!bm) return NULL;
+
+ bm->n = n;
+ bm->b = (uint32 *)malloc(sizeof(bm->b[0])*(n+31)/32);
+ if (!bm->b) {
+ SAFE_FREE(bm);
+ return NULL;
+ }
+
+ memset(bm->b, 0, sizeof(bm->b[0])*(n+31)/32);
+
+ return bm;
+}
+
+/****************************************************************************
+free a bitmap.
+****************************************************************************/
+
+void bitmap_free(struct bitmap *bm)
+{
+ if (!bm)
+ return;
+
+ SAFE_FREE(bm->b);
+ SAFE_FREE(bm);
+}
+
+/****************************************************************************
+set a bit in a bitmap
+****************************************************************************/
+BOOL bitmap_set(struct bitmap *bm, unsigned i)
+{
+ if (i >= bm->n) {
+ DEBUG(0,("Setting invalid bitmap entry %d (of %d)\n",
+ i, bm->n));
+ return False;
+ }
+ bm->b[i/32] |= (1<<(i%32));
+ return True;
+}
+
+/****************************************************************************
+clear a bit in a bitmap
+****************************************************************************/
+BOOL bitmap_clear(struct bitmap *bm, unsigned i)
+{
+ if (i >= bm->n) {
+ DEBUG(0,("clearing invalid bitmap entry %d (of %d)\n",
+ i, bm->n));
+ return False;
+ }
+ bm->b[i/32] &= ~(1<<(i%32));
+ return True;
+}
+
+/****************************************************************************
+query a bit in a bitmap
+****************************************************************************/
+BOOL bitmap_query(struct bitmap *bm, unsigned i)
+{
+ if (i >= bm->n) return False;
+ if (bm->b[i/32] & (1<<(i%32))) {
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************************
+find a zero bit in a bitmap starting at the specified offset, with
+wraparound
+****************************************************************************/
+int bitmap_find(struct bitmap *bm, unsigned ofs)
+{
+ int i, j;
+
+ if (ofs > bm->n) ofs = 0;
+
+ i = ofs;
+ while (i < bm->n) {
+ if (~(bm->b[i/32])) {
+ j = i;
+ do {
+ if (!bitmap_query(bm, j)) return j;
+ j++;
+ } while (j & 31 && j < bm->n);
+ }
+ i += 32;
+ i &= ~31;
+ }
+
+ i = 0;
+ while (i < ofs) {
+ if (~(bm->b[i/32])) {
+ j = i;
+ do {
+ if (!bitmap_query(bm, j)) return j;
+ j++;
+ } while (j & 31 && j < bm->n);
+ }
+ i += 32;
+ i &= ~31;
+ }
+
+ return -1;
+}
diff --git a/source3/lib/charcnv.c b/source3/lib/charcnv.c
index 049390f2a4..cdfca8eb97 100644
--- a/source3/lib/charcnv.c
+++ b/source3/lib/charcnv.c
@@ -1,8 +1,9 @@
/*
- Unix SMB/Netbios implementation.
- Version 1.9.
+ Unix SMB/CIFS implementation.
Character set conversion Extensions
- Copyright (C) Andrew Tridgell 1992-1994
+ Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Simo Sorce 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,107 +21,768 @@
*/
#include "includes.h"
-extern int DEBUGLEVEL;
-static char cvtbuf[1024];
+static pstring cvtbuf;
-static mapsinited = 0;
+static smb_iconv_t conv_handles[NUM_CHARSETS][NUM_CHARSETS];
-static char unix2dos[256];
-static char dos2unix[256];
+/****************************************************************************
+return the name of a charset to give to iconv()
+****************************************************************************/
+static char *charset_name(charset_t ch)
+{
+ char *ret = NULL;
+
+ if (ch == CH_UCS2) ret = "UCS-2LE";
+ else if (ch == CH_UNIX) ret = lp_unix_charset();
+ else if (ch == CH_DOS) ret = lp_dos_charset();
+ else if (ch == CH_DISPLAY) ret = lp_display_charset();
+ else if (ch == CH_UTF8) ret = "UTF8";
+
+ if (!ret || !*ret) ret = "ASCII";
+ return ret;
+}
+
+
+static void lazy_initialize_conv(void)
+{
+ static int initialized = False;
+
+ if (!initialized) {
+ initialized = True;
+ load_case_tables();
+ init_iconv();
+ init_valid_table();
+ }
+}
+
+/****************************************************************************
+ Initialize iconv conversion descriptors
+****************************************************************************/
+void init_iconv(void)
+{
+ int c1, c2;
+ BOOL did_reload = False;
+
+ /* so that charset_name() works we need to get the UNIX<->UCS2 going
+ first */
+ if (!conv_handles[CH_UNIX][CH_UCS2]) {
+ conv_handles[CH_UNIX][CH_UCS2] = smb_iconv_open("UCS-2LE", "ASCII");
+ }
+ if (!conv_handles[CH_UCS2][CH_UNIX]) {
+ conv_handles[CH_UCS2][CH_UNIX] = smb_iconv_open("ASCII", "UCS-2LE");
+ }
+
+
+ for (c1=0;c1<NUM_CHARSETS;c1++) {
+ for (c2=0;c2<NUM_CHARSETS;c2++) {
+ char *n1 = charset_name((charset_t)c1);
+ char *n2 = charset_name((charset_t)c2);
+ if (conv_handles[c1][c2] &&
+ strcmp(n1, conv_handles[c1][c2]->from_name) == 0 &&
+ strcmp(n2, conv_handles[c1][c2]->to_name) == 0) continue;
+
+ did_reload = True;
+
+ if (conv_handles[c1][c2]) {
+ smb_iconv_close(conv_handles[c1][c2]);
+ }
+ conv_handles[c1][c2] = smb_iconv_open(n2,n1);
+ if (conv_handles[c1][c2] == (smb_iconv_t)-1) {
+ DEBUG(0,("Conversion from %s to %s not supported\n",
+ charset_name((charset_t)c1), charset_name((charset_t)c2)));
+ conv_handles[c1][c2] = NULL;
+ }
+ }
+ }
+
+ if (did_reload) {
+ init_valid_table();
+ }
+}
+
+/**
+ * Convert string from one encoding to another, making error checking etc
+ *
+ * @param descriptor conversion descriptor, created in init_iconv()
+ * @param src pointer to source string (multibyte or singlebyte)
+ * @param srclen length of the source string in bytes
+ * @param dest pointer to destination string (multibyte or singlebyte)
+ * @param destlen maximal length allowed for string
+ * @retval the number of bytes occupied in the destination
+ **/
+size_t convert_string(charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t destlen)
+{
+ size_t i_len, o_len;
+ size_t retval;
+ const char* inbuf = (const char*)src;
+ char* outbuf = (char*)dest;
+ smb_iconv_t descriptor;
+
+ if (srclen == -1) srclen = strlen(src)+1;
-static void initmaps() {
- int k;
+ lazy_initialize_conv();
- for (k = 0; k < 256; k++) unix2dos[k] = k;
- for (k = 0; k < 256; k++) dos2unix[k] = k;
+ descriptor = conv_handles[from][to];
- mapsinited = 1;
+ if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
+ /* conversion not supported, use as is */
+ int len = MIN(srclen,destlen);
+ memcpy(dest,src,len);
+ return len;
+ }
+
+ i_len=srclen;
+ o_len=destlen;
+ retval = smb_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len);
+ if(retval==-1)
+ {
+ char *reason="unknown error";
+ switch(errno)
+ { case EINVAL: reason="Incomplete multibyte sequence"; break;
+ case E2BIG: reason="No more room";
+ DEBUG(0, ("Required %d, available %d\n",
+ srclen, destlen));
+ /* we are not sure we need srclen bytes,
+ may be more, may be less.
+ We only know we need more than destlen
+ bytes ---simo */
+
+
+ break;
+ case EILSEQ: reason="Illegal multibyte sequence"; break;
+ }
+ /* smb_panic(reason); */
+ }
+ return destlen-o_len;
}
-static void update_map(char * str) {
- char *p;
+/**
+ * Convert between character sets, allocating a new buffer for the result.
+ *
+ * @param srclen length of source buffer.
+ * @param dest always set at least to NULL
+ * @note -1 is not accepted for srclen.
+ *
+ * @retval Size in bytes of the converted string; or -1 in case of error.
+ **/
+size_t convert_string_allocate(charset_t from, charset_t to,
+ void const *src, size_t srclen, void **dest)
+{
+ size_t i_len, o_len, destlen;
+ size_t retval;
+ const char *inbuf = (const char *)src;
+ char *outbuf, *ob;
+ smb_iconv_t descriptor;
+
+ *dest = NULL;
+
+ if (src == NULL || srclen == -1) return -1;
+
+ lazy_initialize_conv();
- for (p = str; *p; p++) {
- if (p[1]) {
- unix2dos[(unsigned char)*p] = p[1];
- dos2unix[(unsigned char)p[1]] = *p;
- p++;
- }
- }
+ descriptor = conv_handles[from][to];
+
+ if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
+ /* conversion not supported, return -1*/
+ DEBUG(3, ("convert_string_allocate: conversion not supported!\n"));
+ return -1;
+ }
+
+ destlen = MAX(srclen, 512);
+ outbuf = NULL;
+convert:
+ destlen = destlen * 2;
+ ob = (char *)realloc(outbuf, destlen);
+ if (!ob) {
+ DEBUG(0, ("convert_string_allocate: realloc failed!\n"));
+ SAFE_FREE(outbuf);
+ return -1;
+ }
+ else outbuf = ob;
+ i_len = srclen;
+ o_len = destlen;
+ retval = smb_iconv(descriptor,
+ &inbuf, &i_len,
+ &outbuf, &o_len);
+ if(retval == -1)
+ {
+ char *reason="unknown error";
+ switch(errno)
+ {
+ case EINVAL:
+ reason="Incomplete multibyte sequence";
+ break;
+ case E2BIG:
+ goto convert;
+ case EILSEQ:
+ reason="Illegal multibyte sequence";
+ break;
+ }
+ DEBUG(0,("Conversion error: %s(%s)\n",reason,inbuf));
+ /* smb_panic(reason); */
+ return -1;
+ }
+
+ destlen = destlen - o_len;
+ *dest = (char *)Realloc(ob,destlen);
+ if (!*dest) {
+ DEBUG(0, ("convert_string_allocate: out of memory!\n"));
+ SAFE_FREE(ob);
+ return -1;
+ }
+
+ return destlen;
}
-static void initiso() {
+/**
+ * Convert between character sets, allocating a new buffer using talloc for the result.
+ *
+ * @param srclen length of source buffer.
+ * @param dest always set at least to NULL
+ * @note -1 is not accepted for srclen.
+ *
+ * @retval Size in bytes of the converted string; or -1 in case of error.
+ **/
+size_t convert_string_talloc(TALLOC_CTX *ctx, charset_t from, charset_t to,
+ void const *src, size_t srclen, void **dest)
+{
+ void *ob;
+ size_t dest_len;
- if (!mapsinited) initmaps();
+ *dest = NULL;
+ dest_len=convert_string_allocate(from, to, src, srclen, (void **)&ob);
+ if (dest_len == -1)
+ return -1;
+ *dest = talloc_strdup(ctx, (char *)ob);
+ SAFE_FREE(ob);
+ if (*dest == NULL)
+ return -1;
+ return dest_len;
+}
- update_map("\241\255\242\233\243\234\244\236\245\235\246\272\247\025\250\251");
- update_map("\251\273\252\246\253\256\254\252\255\274\256\310\257\257\260\370");
- update_map("\261\361\262\375\263\264\264\265\265\266\266\024\267\371\270\267");
- update_map("\271\270\272\247\273\275\274\254\275\253\276\276\277\250\200\277");
- update_map("\301\300\302\301\303\302\304\216\305\217\306\222\307\200\310\303");
- update_map("\311\220\312\305\313\306\314\307\315\315\316\317\317\320\320\311");
- update_map("\321\245\322\321\323\322\324\323\325\324\326\231\327\312\330\325");
- update_map("\331\326\332\327\333\330\334\232\335\313\336\314\337\341\340\205");
- update_map("\341\240\342\203\343\331\344\204\345\206\346\221\347\207\350\212");
- update_map("\351\202\352\210\353\211\354\215\355\241\356\214\357\213\360\316");
- update_map("\361\244\362\225\363\242\364\223\365\332\366\224\367\366\370\362");
- update_map("\371\227\372\243\373\226\374\201\375\304\376\263\377\230");
+int unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
+{
+ int size;
+ smb_ucs2_t *buffer=(smb_ucs2_t*)cvtbuf;
+ size=convert_string(CH_UNIX, CH_UCS2, src, srclen, buffer, sizeof(cvtbuf));
+ if (!strupper_w(buffer) && (dest == src)) return srclen;
+ return convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
}
-/*
- * Convert unix to dos
- */
-char *
-unix2dos_format(char *str,BOOL overwrite)
+int unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
{
- char *p;
- char *dp;
+ int size;
+ smb_ucs2_t *buffer=(smb_ucs2_t*)cvtbuf;
+ size=convert_string(CH_UNIX, CH_UCS2, src, srclen, buffer, sizeof(cvtbuf));
+ if (!strlower_w(buffer) && (dest == src)) return srclen;
+ return convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
+}
+
- if (!mapsinited) initmaps();
- if (overwrite) {
- for (p = str; *p; p++) *p = unix2dos[(unsigned char)*p];
- return str;
- } else {
- for (p = str, dp = cvtbuf; *p; p++,dp++) *dp = unix2dos[(unsigned char)*p];
- *dp = 0;
- return cvtbuf;
- }
+int ucs2_align(const void *base_ptr, const void *p, int flags)
+{
+ if (flags & (STR_NOALIGN|STR_ASCII)) return 0;
+ return PTR_DIFF(p, base_ptr) & 1;
}
-/*
- * Convert dos to unix
- */
-char *
-dos2unix_format (char *str, BOOL overwrite)
+
+/****************************************************************************
+copy a string from a char* unix src to a dos codepage string destination
+return the number of bytes occupied by the string in the destination
+flags can have:
+ STR_TERMINATE means include the null termination
+ STR_UPPER means uppercase in the destination
+dest_len is the maximum length allowed in the destination. If dest_len
+is -1 then no maxiumum is used
+****************************************************************************/
+int push_ascii(void *dest, const char *src, int dest_len, int flags)
{
- char *p;
- char *dp;
+ int src_len = strlen(src);
+ pstring tmpbuf;
- if (!mapsinited) initmaps();
- if (overwrite) {
- for (p = str; *p; p++) *p = dos2unix[(unsigned char)*p];
- return str;
- } else {
- for (p = str, dp = cvtbuf; *p; p++,dp++) *dp = dos2unix[(unsigned char)*p];
- *dp = 0;
- return cvtbuf;
- }
+ /* treat a pstring as "unlimited" length */
+ if (dest_len == -1) {
+ dest_len = sizeof(pstring);
+ }
+
+ if (flags & STR_UPPER) {
+ pstrcpy(tmpbuf, src);
+ strupper(tmpbuf);
+ src = tmpbuf;
+ }
+
+ if (flags & STR_TERMINATE) {
+ src_len++;
+ }
+
+ return convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len);
}
+int push_ascii_fstring(void *dest, const char *src)
+{
+ return push_ascii(dest, src, sizeof(fstring), STR_TERMINATE);
+}
-/*
- * Interpret character set.
- */
-int
-interpret_character_set (char *str, int def)
+int push_ascii_pstring(void *dest, const char *src)
{
+ return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
+}
+
+int push_pstring(void *dest, const char *src)
+{
+ return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
+}
+
+
+/****************************************************************************
+copy a string from a dos codepage source to a unix char* destination
+flags can have:
+ STR_TERMINATE means the string in src is null terminated
+if STR_TERMINATE is set then src_len is ignored
+src_len is the length of the source area in bytes
+return the number of bytes occupied by the string in src
+the resulting string in "dest" is always null terminated
+****************************************************************************/
+int pull_ascii(char *dest, const void *src, int dest_len, int src_len, int flags)
+{
+ int ret;
+
+ if (dest_len == -1) {
+ dest_len = sizeof(pstring);
+ }
+
+ if (flags & STR_TERMINATE) src_len = strlen(src)+1;
+
+ ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len);
+
+ if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
+
+ return src_len;
+}
+
+int pull_ascii_pstring(char *dest, const void *src)
+{
+ return pull_ascii(dest, src, sizeof(pstring), -1, STR_TERMINATE);
+}
+
+int pull_ascii_fstring(char *dest, const void *src)
+{
+ return pull_ascii(dest, src, sizeof(fstring), -1, STR_TERMINATE);
+}
+
+/****************************************************************************
+copy a string from a char* src to a unicode destination
+return the number of bytes occupied by the string in the destination
+flags can have:
+ STR_TERMINATE means include the null termination
+ STR_UPPER means uppercase in the destination
+ STR_NOALIGN means don't do alignment
+dest_len is the maximum length allowed in the destination. If dest_len
+is -1 then no maxiumum is used
+****************************************************************************/
+int push_ucs2(const void *base_ptr, void *dest, const char *src, int dest_len, int flags)
+{
+ int len=0;
+ int src_len = strlen(src);
+ pstring tmpbuf;
+
+ /* treat a pstring as "unlimited" length */
+ if (dest_len == -1) {
+ dest_len = sizeof(pstring);
+ }
+
+ if (flags & STR_UPPER) {
+ pstrcpy(tmpbuf, src);
+ strupper(tmpbuf);
+ src = tmpbuf;
+ }
+
+ if (flags & STR_TERMINATE) {
+ src_len++;
+ }
+
+ if (ucs2_align(base_ptr, dest, flags)) {
+ *(char *)dest = 0;
+ dest = (void *)((char *)dest + 1);
+ if (dest_len) dest_len--;
+ len++;
+ }
+
+ /* ucs2 is always a multiple of 2 bytes */
+ dest_len &= ~1;
+
+ len += convert_string(CH_UNIX, CH_UCS2, src, src_len, dest, dest_len);
+ return len;
+}
+
+/**
+ * Copy a string from a unix char* src to a UCS2 destination, allocating a buffer using talloc
+ *
+ * @param dest always set at least to NULL
+ *
+ * @retval The number of bytes occupied by the string in the destination
+ **/
+int push_ucs2_talloc(TALLOC_CTX *ctx, void **dest, const char *src)
+{
+ int src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_talloc(ctx, CH_UNIX, CH_UCS2, src, src_len, dest);
+}
+
+/**
+ * Copy a string from a unix char* src to a UCS2 destination, allocating a buffer
+ *
+ * @param dest always set at least to NULL
+ *
+ * @retval The number of bytes occupied by the string in the destination
+ **/
+int push_ucs2_allocate(void **dest, const char *src)
+{
+ int src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_allocate(CH_UNIX, CH_UCS2, src, src_len, dest);
+}
+
+/****************************************************************************
+copy a string from a char* src to a UTF-8 destination
+return the number of bytes occupied by the string in the destination
+flags can have:
+ STR_TERMINATE means include the null termination
+ STR_UPPER means uppercase in the destination
+dest_len is the maximum length allowed in the destination. If dest_len
+is -1 then no maxiumum is used
+****************************************************************************/
+int push_utf8(void *dest, const char *src, int dest_len, int flags)
+{
+ int src_len = strlen(src);
+ pstring tmpbuf;
+
+ /* treat a pstring as "unlimited" length */
+ if (dest_len == -1) {
+ dest_len = sizeof(pstring);
+ }
- if (strequal (str, "iso8859-1")) {
- initiso();
- return def;
- } else {
- DEBUG(0,("unrecognized character set\n"));
- }
- return def;
+ if (flags & STR_UPPER) {
+ pstrcpy(tmpbuf, src);
+ strupper(tmpbuf);
+ src = tmpbuf;
+ }
+
+ if (flags & STR_TERMINATE) {
+ src_len++;
+ }
+
+ return convert_string(CH_UNIX, CH_UTF8, src, src_len, dest, dest_len);
+}
+
+int push_utf8_fstring(void *dest, const char *src)
+{
+ return push_utf8(dest, src, sizeof(fstring), STR_TERMINATE);
+}
+
+int push_utf8_pstring(void *dest, const char *src)
+{
+ return push_utf8(dest, src, sizeof(pstring), STR_TERMINATE);
+}
+
+/**
+ * Copy a string from a unix char* src to a UTF-8 destination, allocating a buffer using talloc
+ *
+ * @param dest always set at least to NULL
+ *
+ * @retval The number of bytes occupied by the string in the destination
+ **/
+int push_utf8_talloc(TALLOC_CTX *ctx, void **dest, const char *src)
+{
+ int src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_talloc(ctx, CH_UNIX, CH_UTF8, src, src_len, dest);
+}
+
+/**
+ * Copy a string from a unix char* src to a UTF-8 destination, allocating a buffer
+ *
+ * @param dest always set at least to NULL
+ *
+ * @retval The number of bytes occupied by the string in the destination
+ **/
+int push_utf8_allocate(void **dest, const char *src)
+{
+ int src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_allocate(CH_UNIX, CH_UTF8, src, src_len, dest);
+}
+
+/****************************************************************************
+copy a string from a ucs2 source to a unix char* destination
+flags can have:
+ STR_TERMINATE means the string in src is null terminated
+ STR_NOALIGN means don't try to align
+if STR_TERMINATE is set then src_len is ignored
+src_len is the length of the source area in bytes
+return the number of bytes occupied by the string in src
+the resulting string in "dest" is always null terminated
+****************************************************************************/
+int pull_ucs2(const void *base_ptr, char *dest, const void *src, int dest_len, int src_len, int flags)
+{
+ int ret;
+
+ if (dest_len == -1) {
+ dest_len = sizeof(pstring);
+ }
+
+ if (ucs2_align(base_ptr, src, flags)) {
+ src = (const void *)((const char *)src + 1);
+ if (src_len > 0) src_len--;
+ }
+
+ if (flags & STR_TERMINATE) src_len = strlen_w(src)*2+2;
+
+ /* ucs2 is always a multiple of 2 bytes */
+ src_len &= ~1;
+
+ ret = convert_string(CH_UCS2, CH_UNIX, src, src_len, dest, dest_len);
+ if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
+
+ return src_len;
+}
+
+int pull_ucs2_pstring(char *dest, const void *src)
+{
+ return pull_ucs2(NULL, dest, src, sizeof(pstring), -1, STR_TERMINATE);
+}
+
+int pull_ucs2_fstring(char *dest, const void *src)
+{
+ return pull_ucs2(NULL, dest, src, sizeof(fstring), -1, STR_TERMINATE);
+}
+
+/**
+ * Copy a string from a UCS2 src to a unix char * destination, allocating a buffer using talloc
+ *
+ * @param dest always set at least to NULL
+ *
+ * @retval The number of bytes occupied by the string in the destination
+ **/
+int pull_ucs2_talloc(TALLOC_CTX *ctx, void **dest, const char *src)
+{
+ int src_len = strlen(src)+1;
+ *dest = NULL;
+ return convert_string_talloc(ctx, CH_UCS2, CH_UNIX, src, src_len, dest);
+}
+
+/**
+ * Copy a string from a UCS2 src to a unix char * destination, allocating a buffer
+ *
+ * @param dest always set at least to NULL
+ *
+ * @retval The number of bytes occupied by the string in the destination
+ **/
+int pull_ucs2_allocate(void **dest, const char *src)
+{
+ int src_len = strlen(src)+1;
+ *dest = NULL;
+ return convert_string_allocate(CH_UCS2, CH_UNIX, src, src_len, dest);
+}
+
+/****************************************************************************
+copy a string from a utf-8 source to a unix char* destination
+flags can have:
+ STR_TERMINATE means the string in src is null terminated
+if STR_TERMINATE is set then src_len is ignored
+src_len is the length of the source area in bytes
+return the number of bytes occupied by the string in src
+the resulting string in "dest" is always null terminated
+****************************************************************************/
+int pull_utf8(char *dest, const void *src, int dest_len, int src_len, int flags)
+{
+ int ret;
+
+ if (dest_len == -1) {
+ dest_len = sizeof(pstring);
+ }
+
+ if (flags & STR_TERMINATE) src_len = strlen(src)+1;
+
+ ret = convert_string(CH_UTF8, CH_UNIX, src, src_len, dest, dest_len);
+ if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
+
+ return src_len;
+}
+
+int pull_utf8_pstring(char *dest, const void *src)
+{
+ return pull_utf8(dest, src, sizeof(pstring), -1, STR_TERMINATE);
+}
+
+int pull_utf8_fstring(char *dest, const void *src)
+{
+ return pull_utf8(dest, src, sizeof(fstring), -1, STR_TERMINATE);
+}
+
+/**
+ * Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer using talloc
+ *
+ * @param dest always set at least to NULL
+ *
+ * @retval The number of bytes occupied by the string in the destination
+ **/
+int pull_utf8_talloc(TALLOC_CTX *ctx, void **dest, const char *src)
+{
+ int src_len = strlen(src)+1;
+ *dest = NULL;
+ return convert_string_talloc(ctx, CH_UTF8, CH_UNIX, src, src_len, dest);
+}
+
+/**
+ * Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer
+ *
+ * @param dest always set at least to NULL
+ *
+ * @retval The number of bytes occupied by the string in the destination
+ **/
+int pull_utf8_allocate(void **dest, const char *src)
+{
+ int src_len = strlen(src)+1;
+ *dest = NULL;
+ return convert_string_allocate(CH_UTF8, CH_UNIX, src, src_len, dest);
+}
+
+/****************************************************************************
+copy a string from a char* src to a unicode or ascii
+dos codepage destination choosing unicode or ascii based on the
+flags in the SMB buffer starting at base_ptr
+return the number of bytes occupied by the string in the destination
+flags can have:
+ STR_TERMINATE means include the null termination
+ STR_UPPER means uppercase in the destination
+ STR_ASCII use ascii even with unicode packet
+ STR_NOALIGN means don't do alignment
+dest_len is the maximum length allowed in the destination. If dest_len
+is -1 then no maxiumum is used
+****************************************************************************/
+int push_string(const void *base_ptr, void *dest, const char *src, int dest_len, int flags)
+{
+ if (!(flags & STR_ASCII) && \
+ ((flags & STR_UNICODE || \
+ (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
+ return push_ucs2(base_ptr, dest, src, dest_len, flags);
+ }
+ return push_ascii(dest, src, dest_len, flags);
+}
+
+
+/****************************************************************************
+copy a string from a unicode or ascii source (depending on
+the packet flags) to a char* destination
+flags can have:
+ STR_TERMINATE means the string in src is null terminated
+ STR_UNICODE means to force as unicode
+ STR_ASCII use ascii even with unicode packet
+ STR_NOALIGN means don't do alignment
+if STR_TERMINATE is set then src_len is ignored
+src_len is the length of the source area in bytes
+return the number of bytes occupied by the string in src
+the resulting string in "dest" is always null terminated
+****************************************************************************/
+int pull_string(const void *base_ptr, char *dest, const void *src, int dest_len, int src_len,
+ int flags)
+{
+ if (!(flags & STR_ASCII) && \
+ ((flags & STR_UNICODE || \
+ (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
+ return pull_ucs2(base_ptr, dest, src, dest_len, src_len, flags);
+ }
+ return pull_ascii(dest, src, dest_len, src_len, flags);
+}
+
+int align_string(const void *base_ptr, const char *p, int flags)
+{
+ if (!(flags & STR_ASCII) && \
+ ((flags & STR_UNICODE || \
+ (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
+ return ucs2_align(base_ptr, p, flags);
+ }
+ return 0;
+}
+
+
+
+/****************************************************************************
+convert from ucs2 to unix charset and return the
+allocated and converted string or NULL if an error occurred.
+you must provide a zero terminated string.
+the returning string will be zero terminated.
+****************************************************************************/
+char *acnv_u2ux(const smb_ucs2_t *src)
+{
+ size_t slen;
+ size_t dlen;
+ void *dest;
+
+ slen = (strlen_w(src) + 1) * sizeof(smb_ucs2_t);
+ dlen = convert_string_allocate(CH_UCS2, CH_UNIX, src, slen, &dest);
+ if (dlen == -1) return NULL;
+ else return dest;
+}
+
+/****************************************************************************
+convert from unix to ucs2 charset and return the
+allocated and converted string or NULL if an error occurred.
+you must provide a zero terminated string.
+the returning string will be zero terminated.
+****************************************************************************/
+smb_ucs2_t *acnv_uxu2(const char *src)
+{
+ size_t slen;
+ size_t dlen;
+ void *dest;
+
+ slen = strlen(src) + 1;
+ dlen = convert_string_allocate(CH_UNIX, CH_UCS2, src, slen, &dest);
+ if (dlen == -1) return NULL;
+ else return dest;
+}
+
+/****************************************************************************
+convert from ucs2 to dos charset and return the
+allocated and converted string or NULL if an error occurred.
+you must provide a zero terminated string.
+the returning string will be zero terminated.
+****************************************************************************/
+char *acnv_u2dos(const smb_ucs2_t *src)
+{
+ size_t slen;
+ size_t dlen;
+ void *dest;
+
+ slen = (strlen_w(src) + 1) * sizeof(smb_ucs2_t);
+ dlen = convert_string_allocate(CH_UCS2, CH_DOS, src, slen, &dest);
+ if (dlen == -1) return NULL;
+ else return dest;
+}
+
+/****************************************************************************
+convert from dos to ucs2 charset and return the
+allocated and converted string or NULL if an error occurred.
+you must provide a zero terminated string.
+the returning string will be zero terminated.
+****************************************************************************/
+smb_ucs2_t *acnv_dosu2(const char *src)
+{
+ size_t slen;
+ size_t dlen;
+ void *dest;
+
+ slen = strlen(src) + 1;
+ dlen = convert_string_allocate(CH_DOS, CH_UCS2, src, slen, &dest);
+ if (dlen == -1) return NULL;
+ else return dest;
}
diff --git a/source3/lib/charset.c b/source3/lib/charset.c
deleted file mode 100644
index ada3ef790a..0000000000
--- a/source3/lib/charset.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- Character set handling
- Copyright (C) Andrew Tridgell 1992-1995
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#define CHARSET_C
-#include "includes.h"
-
-extern int DEBUGLEVEL;
-
-char xx_dos_char_map[256];
-char xx_upper_char_map[256];
-char xx_lower_char_map[256];
-
-char *dos_char_map = NULL;
-char *upper_char_map = NULL;
-char *lower_char_map = NULL;
-
-static void add_dos_char(int lower, int upper)
-{
- DEBUG(6,("Adding chars 0%o 0%o\n",lower,upper));
- if (lower) dos_char_map[(char)lower] = 1;
- if (upper) dos_char_map[(char)upper] = 1;
- if (lower && upper) {
- lower_char_map[(char)upper] = (char)lower;
- upper_char_map[(char)lower] = (char)upper;
- }
-}
-
-/****************************************************************************
-initialise the charset arrays
-****************************************************************************/
-void charset_initialise(void)
-{
- int i;
-
- dos_char_map = &xx_dos_char_map[128];
- upper_char_map = &xx_upper_char_map[128];
- lower_char_map = &xx_lower_char_map[128];
-
- for (i= -128;i<=127;i++) {
- dos_char_map[(char)i] = 0;
- }
-
- for (i=0;i<=127;i++) {
- if (isalnum((char)i) || strchr("._^$~!#%&-{}()@'`",(char)i))
- add_dos_char(i,0);
- }
-
- for (i= -128;i<=127;i++) {
- char c = (char)i;
- upper_char_map[i] = lower_char_map[i] = c;
- if (isupper(c)) lower_char_map[c] = tolower(c);
- if (islower(c)) upper_char_map[c] = toupper(c);
- }
-
- /* valid for all DOS PC */
- add_dos_char(142,0); /* A trema */
- add_dos_char(143,0); /* A o */
- add_dos_char(144,0); /* E ' */
- add_dos_char(146,0); /* AE */
- add_dos_char(153,0); /* O trema */
- add_dos_char(154,0); /* U trema */
- add_dos_char(165,0); /* N tilda */
- add_dos_char(128,0); /* C cedille */
- add_dos_char(156,0); /* Pound */
- add_dos_char(183,0); /* A ` (WIN)*/
- add_dos_char(157,0); /* Phi (WIN)*/
- add_dos_char(212,0); /* E` (WIN)*/
-}
-
-
-/*******************************************************************
-add characters depending on a string passed by the user
-********************************************************************/
-void add_char_string(char *s)
-{
- char *extra_chars = (char *)strdup(s);
- char *t;
- if (!extra_chars) return;
-
- for (t=strtok(extra_chars," \t\r\n"); t; t=strtok(NULL," \t\r\n")) {
- char c1=0,c2=0;
- int i1=0,i2=0;
- if (isdigit(*t) || (*t)=='-') {
- sscanf(t,"%i:%i",&i1,&i2);
- add_dos_char(i1,i2);
- } else {
- sscanf(t,"%c:%c",&c1,&c2);
- add_dos_char(c1,c2);
- }
- }
-
- free(extra_chars);
-}
diff --git a/source3/lib/crc32.c b/source3/lib/crc32.c
new file mode 100644
index 0000000000..bd4f1633e5
--- /dev/null
+++ b/source3/lib/crc32.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright Francesco Ferrara, 1998 <francesco@aerra.it>
+ *
+ * Used by kind permission, 14th October 1998. http://www.aerre.it/francesco
+ *
+ *
+ */
+
+#include "includes.h"
+
+static unsigned long CRCTable[256] =
+{
+ 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,
+ 0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,
+ 0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,0x1DB71064,0x6AB020F2,
+ 0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,
+ 0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,
+ 0xFA0F3D63,0x8D080DF5,0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,
+ 0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,
+ 0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
+ 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,
+ 0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,
+ 0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,0x76DC4190,0x01DB7106,
+ 0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,
+ 0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,
+ 0x91646C97,0xE6635C01,0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,
+ 0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,
+ 0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
+ 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,
+ 0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,
+ 0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,0x5005713C,0x270241AA,
+ 0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,
+ 0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,
+ 0xB7BD5C3B,0xC0BA6CAD,0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,
+ 0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,
+ 0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
+ 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,
+ 0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,
+ 0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,0xD6D6A3E8,0xA1D1937E,
+ 0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,
+ 0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,
+ 0x316E8EEF,0x4669BE79,0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,
+ 0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,
+ 0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
+ 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,
+ 0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,
+ 0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,0x86D3D2D4,0xF1D4E242,
+ 0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,
+ 0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,
+ 0x616BFFD3,0x166CCF45,0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,
+ 0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,
+ 0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
+ 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,
+ 0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,
+ 0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D
+};
+
+uint32 crc32_calc_buffer( char *buffer, uint32 count)
+{
+ uint32 crc=0xffffffff, i;
+ for(i=0;i<count;i++)
+ crc = (crc>>8) ^ CRCTable[(buffer[i] ^ crc) & 0xff];
+ crc^=0xffffffff;
+ DEBUG(10,("crc32_calc_buffer: %x\n", crc));
+ dump_data(100, buffer, count);
+ return crc;
+}
diff --git a/source3/lib/debug.c b/source3/lib/debug.c
new file mode 100644
index 0000000000..7960c32b58
--- /dev/null
+++ b/source3/lib/debug.c
@@ -0,0 +1,771 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* -------------------------------------------------------------------------- **
+ * Defines...
+ *
+ * FORMAT_BUFR_MAX - Index of the last byte of the format buffer;
+ * format_bufr[FORMAT_BUFR_MAX] should always be reserved
+ * for a terminating null byte.
+ */
+
+#define FORMAT_BUFR_MAX ( sizeof( format_bufr ) - 1 )
+
+/* -------------------------------------------------------------------------- **
+ * This module implements Samba's debugging utility.
+ *
+ * The syntax of a debugging log file is represented as:
+ *
+ * <debugfile> :== { <debugmsg> }
+ *
+ * <debugmsg> :== <debughdr> '\n' <debugtext>
+ *
+ * <debughdr> :== '[' TIME ',' LEVEL ']' [ [FILENAME ':'] [FUNCTION '()'] ]
+ *
+ * <debugtext> :== { <debugline> }
+ *
+ * <debugline> :== TEXT '\n'
+ *
+ * TEXT is a string of characters excluding the newline character.
+ * LEVEL is the DEBUG level of the message (an integer in the range 0..10).
+ * TIME is a timestamp.
+ * FILENAME is the name of the file from which the debug message was generated.
+ * FUNCTION is the function from which the debug message was generated.
+ *
+ * Basically, what that all means is:
+ *
+ * - A debugging log file is made up of debug messages.
+ *
+ * - Each debug message is made up of a header and text. The header is
+ * separated from the text by a newline.
+ *
+ * - The header begins with the timestamp and debug level of the message
+ * enclosed in brackets. The filename and function from which the
+ * message was generated may follow. The filename is terminated by a
+ * colon, and the function name is terminated by parenthesis.
+ *
+ * - The message text is made up of zero or more lines, each terminated by
+ * a newline.
+ */
+
+/* -------------------------------------------------------------------------- **
+ * External variables.
+ *
+ * dbf - Global debug file handle.
+ * debugf - Debug file name.
+ * append_log - If True, then the output file will be opened in append
+ * mode.
+ * DEBUGLEVEL - System-wide debug message limit. Messages with message-
+ * levels higher than DEBUGLEVEL will not be processed.
+ */
+
+XFILE *dbf = NULL;
+pstring debugf = "";
+BOOL append_log = False;
+
+int DEBUGLEVEL_CLASS[DBGC_LAST];
+BOOL DEBUGLEVEL_CLASS_ISSET[DBGC_LAST];
+int DEBUGLEVEL = DEBUGLEVEL_CLASS;
+BOOL AllowDebugChange = True;
+
+
+/* -------------------------------------------------------------------------- **
+ * Internal variables.
+ *
+ * stdout_logging - Default False, if set to True then dbf will be set to
+ * stdout and debug output will go to dbf only, and not
+ * to syslog. Set in setup_logging() and read in Debug1().
+ *
+ * debug_count - Number of debug messages that have been output.
+ * Used to check log size.
+ *
+ * syslog_level - Internal copy of the message debug level. Written by
+ * dbghdr() and read by Debug1().
+ *
+ * format_bufr - Used to format debug messages. The dbgtext() function
+ * prints debug messages to a string, and then passes the
+ * string to format_debug_text(), which uses format_bufr
+ * to build the formatted output.
+ *
+ * format_pos - Marks the first free byte of the format_bufr.
+ *
+ *
+ * log_overflow - When this variable is True, never attempt to check the
+ * size of the log. This is a hack, so that we can write
+ * a message using DEBUG, from open_logs() when we
+ * are unable to open a new log file for some reason.
+ */
+
+static BOOL stdout_logging = False;
+static int debug_count = 0;
+#ifdef WITH_SYSLOG
+static int syslog_level = 0;
+#endif
+static pstring format_bufr = { '\0' };
+static size_t format_pos = 0;
+static BOOL log_overflow = False;
+
+/*
+ * Define all the debug class selection names here. Names *MUST NOT* contain
+ * white space. There must be one name for each DBGC_<class name>, and they
+ * must be in the table in the order of DBGC_<class name>..
+ */
+char *classname_table[] = {
+ "all", /* DBGC_ALL; index refs traditional DEBUGLEVEL */
+ "tdb", /* DBGC_TDB */
+ "printdrivers", /* DBGC_PRINTDRIVERS */
+ "lanman", /* DBGC_LANMAN */
+ "smb", /* DBGC_SMB */
+ "rpc", /* DBGC_RPC */
+ "rpc_hdr", /* DBGC_RPC_HDR */
+ "bdc", /* DBGC_BDC */
+};
+
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+/****************************************************************************
+utility access to debug class names's
+****************************************************************************/
+char* debug_classname_from_index(int ndx)
+{
+ return classname_table[ndx];
+}
+
+/****************************************************************************
+utility to translate names to debug class index's
+****************************************************************************/
+int debug_lookup_classname(char* classname)
+{
+ int i;
+
+ if (!classname) return -1;
+
+ for (i=0; i<DBGC_LAST; i++) {
+ if (strcmp(classname, classname_table[i])==0)
+ return i;
+ }
+ return -1;
+}
+
+/****************************************************************************
+parse the debug levels from smbcontrol. Example debug level parameter:
+ printdrivers:7
+****************************************************************************/
+BOOL debug_parse_params(char **params, int *debuglevel_class,
+ BOOL *debuglevel_class_isset)
+{
+ int i, ndx;
+ char *class_name;
+ char *class_level;
+
+ /* Set the new debug level array to the current DEBUGLEVEL array */
+ memcpy(debuglevel_class, DEBUGLEVEL_CLASS, sizeof(DEBUGLEVEL_CLASS));
+
+ /* Allow DBGC_ALL to be specified w/o requiring its class name e.g."10"
+ * v.s. "all:10", this is the traditional way to set DEBUGLEVEL
+ */
+ if (isdigit((int)params[0][0])) {
+ debuglevel_class[DBGC_ALL] = atoi(params[0]);
+ debuglevel_class_isset[DBGC_ALL] = True;
+ i = 1; /* start processing at the next params */
+ }
+ else
+ i = 0; /* DBGC_ALL not specified OR class name was included */
+
+ /* Fill in new debug class levels */
+ for (; i < DBGC_LAST && params[i]; i++) {
+ if ((class_name=strtok(params[i],":")) &&
+ (class_level=strtok(NULL, "\0")) &&
+ ((ndx = debug_lookup_classname(class_name)) != -1)) {
+ debuglevel_class[ndx] = atoi(class_level);
+ debuglevel_class_isset[ndx] = True;
+ } else {
+ DEBUG(0,("debug_parse_params: unrecognized debug class name or format [%s]\n", params[i]));
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/****************************************************************************
+parse the debug levels from smb.conf. Example debug level string:
+ 3 tdb:5 printdrivers:7
+Note: the 1st param has no "name:" preceeding it.
+****************************************************************************/
+BOOL debug_parse_levels(char *params_str)
+{
+ int i;
+ char *params[DBGC_LAST];
+ int debuglevel_class[DBGC_LAST];
+ BOOL debuglevel_class_isset[DBGC_LAST];
+
+ if (AllowDebugChange == False)
+ return True;
+ ZERO_ARRAY(params);
+ ZERO_ARRAY(debuglevel_class);
+ ZERO_ARRAY(debuglevel_class_isset);
+
+ if ((params[0]=strtok(params_str," ,"))) {
+ for (i=1; i<DBGC_LAST;i++) {
+ if ((params[i]=strtok(NULL," ,"))==NULL)
+ break;
+ }
+ }
+ else
+ return False;
+
+ if (debug_parse_params(params, debuglevel_class,
+ debuglevel_class_isset)) {
+ debug_message(0, sys_getpid(), (void*)debuglevel_class, sizeof(debuglevel_class));
+
+ memcpy(DEBUGLEVEL_CLASS, debuglevel_class,
+ sizeof(debuglevel_class));
+
+ memcpy(DEBUGLEVEL_CLASS_ISSET, debuglevel_class_isset,
+ sizeof(debuglevel_class_isset));
+
+ {
+ int q;
+
+ for (q = 0; q < DBGC_LAST; q++)
+ DEBUG(5, ("%s: %d/%d\n",
+ classname_table[q],
+ DEBUGLEVEL_CLASS[q],
+ DEBUGLEVEL_CLASS_ISSET[q]));
+ }
+
+ return True;
+ } else
+ return False;
+}
+
+/****************************************************************************
+receive a "set debug level" message
+****************************************************************************/
+void debug_message(int msg_type, pid_t src, void *buf, size_t len)
+{
+ struct debuglevel_message *dm = (struct debuglevel_message *)buf;
+ int i;
+
+ /* Set the new DEBUGLEVEL_CLASS array from the passed message */
+ memcpy(DEBUGLEVEL_CLASS, dm->debuglevel_class, sizeof(dm->debuglevel_class));
+ memcpy(DEBUGLEVEL_CLASS_ISSET, dm->debuglevel_class_isset, sizeof(dm->debuglevel_class_isset));
+
+ DEBUG(3,("INFO: Debug class %s level = %d (pid %u from pid %u)\n",
+ classname_table[DBGC_ALL],
+ DEBUGLEVEL_CLASS[DBGC_ALL], (unsigned int)sys_getpid(), (unsigned int)src));
+
+ for (i=1; i<DBGC_LAST; i++) {
+ if (DEBUGLEVEL_CLASS[i])
+ DEBUGADD(3,("INFO: Debug class %s level = %d\n",
+ classname_table[i], DEBUGLEVEL_CLASS[i]));
+ }
+}
+
+
+/****************************************************************************
+send a "set debug level" message
+****************************************************************************/
+void debug_message_send(pid_t pid, int level)
+{
+ message_send_pid(pid, MSG_DEBUG, &level, sizeof(int), False);
+}
+
+
+/* ************************************************************************** **
+ * get ready for syslog stuff
+ * ************************************************************************** **
+ */
+void setup_logging(char *pname, BOOL interactive)
+{
+ message_register(MSG_DEBUG, debug_message);
+
+ /* reset to allow multiple setup calls, going from interactive to
+ non-interactive */
+ stdout_logging = False;
+ dbf = NULL;
+
+ if (interactive) {
+ stdout_logging = True;
+ dbf = x_stdout;
+ }
+#ifdef WITH_SYSLOG
+ else {
+ char *p = strrchr_m( pname,'/' );
+ if (p)
+ pname = p + 1;
+#ifdef LOG_DAEMON
+ openlog( pname, LOG_PID, SYSLOG_FACILITY );
+#else
+ /* for old systems that have no facility codes. */
+ openlog( pname, LOG_PID );
+#endif
+ }
+#endif
+} /* setup_logging */
+
+/* ************************************************************************** **
+ * reopen the log files
+ * note that we now do this unconditionally
+ * We attempt to open the new debug fp before closing the old. This means
+ * if we run out of fd's we just keep using the old fd rather than aborting.
+ * Fix from dgibson@linuxcare.com.
+ * ************************************************************************** **
+ */
+
+BOOL reopen_logs( void )
+{
+ pstring fname;
+ mode_t oldumask;
+ XFILE *new_dbf = NULL;
+ BOOL ret = True;
+
+ if (stdout_logging)
+ return True;
+
+ oldumask = umask( 022 );
+
+ pstrcpy(fname, debugf );
+
+ if (lp_loaded()) {
+ char *logfname;
+
+ logfname = lp_logfile();
+ if (*logfname)
+ pstrcpy(fname, logfname);
+ }
+
+ pstrcpy( debugf, fname );
+ if (append_log)
+ new_dbf = x_fopen( debugf, O_WRONLY|O_APPEND|O_CREAT, 0644);
+ else
+ new_dbf = x_fopen( debugf, O_WRONLY|O_CREAT|O_TRUNC, 0644 );
+
+ if (!new_dbf) {
+ log_overflow = True;
+ DEBUG(0, ("Unable to open new log file %s: %s\n", debugf, strerror(errno)));
+ log_overflow = False;
+ if (dbf)
+ x_fflush(dbf);
+ ret = False;
+ } else {
+ x_setbuf(new_dbf, NULL);
+ if (dbf)
+ (void) x_fclose(dbf);
+ dbf = new_dbf;
+ }
+
+ /* Fix from klausr@ITAP.Physik.Uni-Stuttgart.De
+ * to fix problem where smbd's that generate less
+ * than 100 messages keep growing the log.
+ */
+ force_check_log_size();
+ (void)umask(oldumask);
+
+ return ret;
+}
+
+/* ************************************************************************** **
+ * Force a check of the log size.
+ * ************************************************************************** **
+ */
+void force_check_log_size( void )
+{
+ debug_count = 100;
+}
+
+/***************************************************************************
+ Check to see if there is any need to check if the logfile has grown too big.
+**************************************************************************/
+
+BOOL need_to_check_log_size( void )
+{
+ int maxlog;
+
+ if( debug_count++ < 100 )
+ return( False );
+
+ maxlog = lp_max_log_size() * 1024;
+ if( !dbf || maxlog <= 0 ) {
+ debug_count = 0;
+ return(False);
+ }
+ return( True );
+}
+
+/* ************************************************************************** **
+ * Check to see if the log has grown to be too big.
+ * ************************************************************************** **
+ */
+
+void check_log_size( void )
+{
+ int maxlog;
+ SMB_STRUCT_STAT st;
+
+ /*
+ * We need to be root to check/change log-file, skip this and let the main
+ * loop check do a new check as root.
+ */
+
+ if( geteuid() != 0 )
+ return;
+
+ if(log_overflow || !need_to_check_log_size() )
+ return;
+
+ maxlog = lp_max_log_size() * 1024;
+
+ if( sys_fstat( x_fileno( dbf ), &st ) == 0 && st.st_size > maxlog ) {
+ (void)reopen_logs();
+ if( dbf && get_file_size( debugf ) > maxlog ) {
+ pstring name;
+
+ slprintf( name, sizeof(name)-1, "%s.old", debugf );
+ (void)rename( debugf, name );
+
+ if (!reopen_logs()) {
+ /* We failed to reopen a log - continue using the old name. */
+ (void)rename(name, debugf);
+ }
+ }
+ }
+
+ /*
+ * Here's where we need to panic if dbf == NULL..
+ */
+
+ if(dbf == NULL) {
+ /* This code should only be reached in very strange
+ * circumstances. If we merely fail to open the new log we
+ * should stick with the old one. ergo this should only be
+ * reached when opening the logs for the first time: at
+ * startup or when the log level is increased from zero.
+ * -dwg 6 June 2000
+ */
+ dbf = x_fopen( "/dev/console", O_WRONLY, 0);
+ if(dbf) {
+ DEBUG(0,("check_log_size: open of debug file %s failed - using console.\n",
+ debugf ));
+ } else {
+ /*
+ * We cannot continue without a debug file handle.
+ */
+ abort();
+ }
+ }
+ debug_count = 0;
+} /* check_log_size */
+
+/* ************************************************************************** **
+ * Write an debug message on the debugfile.
+ * This is called by dbghdr() and format_debug_text().
+ * ************************************************************************** **
+ */
+ int Debug1( char *format_str, ... )
+{
+ va_list ap;
+ int old_errno = errno;
+
+ if( stdout_logging )
+ {
+ va_start( ap, format_str );
+ if(dbf)
+ (void)x_vfprintf( dbf, format_str, ap );
+ va_end( ap );
+ errno = old_errno;
+ return( 0 );
+ }
+
+#ifdef WITH_SYSLOG
+ if( !lp_syslog_only() )
+#endif
+ {
+ if( !dbf )
+ {
+ mode_t oldumask = umask( 022 );
+
+ if( append_log )
+ dbf = x_fopen( debugf, O_WRONLY|O_APPEND|O_CREAT, 0644 );
+ else
+ dbf = x_fopen( debugf, O_WRONLY|O_CREAT|O_TRUNC, 0644 );
+ (void)umask( oldumask );
+ if( dbf )
+ {
+ x_setbuf( dbf, NULL );
+ }
+ else
+ {
+ errno = old_errno;
+ return(0);
+ }
+ }
+ }
+
+#ifdef WITH_SYSLOG
+ if( syslog_level < lp_syslog() )
+ {
+ /* map debug levels to syslog() priorities
+ * note that not all DEBUG(0, ...) calls are
+ * necessarily errors
+ */
+ static int priority_map[] = {
+ LOG_ERR, /* 0 */
+ LOG_WARNING, /* 1 */
+ LOG_NOTICE, /* 2 */
+ LOG_INFO, /* 3 */
+ };
+ int priority;
+ pstring msgbuf;
+
+ if( syslog_level >= ( sizeof(priority_map) / sizeof(priority_map[0]) )
+ || syslog_level < 0)
+ priority = LOG_DEBUG;
+ else
+ priority = priority_map[syslog_level];
+
+ va_start( ap, format_str );
+ vslprintf( msgbuf, sizeof(msgbuf)-1, format_str, ap );
+ va_end( ap );
+
+ msgbuf[255] = '\0';
+ syslog( priority, "%s", msgbuf );
+ }
+#endif
+
+ check_log_size();
+
+#ifdef WITH_SYSLOG
+ if( !lp_syslog_only() )
+#endif
+ {
+ va_start( ap, format_str );
+ if(dbf)
+ (void)x_vfprintf( dbf, format_str, ap );
+ va_end( ap );
+ if(dbf)
+ (void)x_fflush( dbf );
+ }
+
+ errno = old_errno;
+
+ return( 0 );
+ } /* Debug1 */
+
+
+/* ************************************************************************** **
+ * Print the buffer content via Debug1(), then reset the buffer.
+ *
+ * Input: none
+ * Output: none
+ *
+ * ************************************************************************** **
+ */
+static void bufr_print( void )
+ {
+ format_bufr[format_pos] = '\0';
+ (void)Debug1( "%s", format_bufr );
+ format_pos = 0;
+ } /* bufr_print */
+
+/* ************************************************************************** **
+ * Format the debug message text.
+ *
+ * Input: msg - Text to be added to the "current" debug message text.
+ *
+ * Output: none.
+ *
+ * Notes: The purpose of this is two-fold. First, each call to syslog()
+ * (used by Debug1(), see above) generates a new line of syslog
+ * output. This is fixed by storing the partial lines until the
+ * newline character is encountered. Second, printing the debug
+ * message lines when a newline is encountered allows us to add
+ * spaces, thus indenting the body of the message and making it
+ * more readable.
+ *
+ * ************************************************************************** **
+ */
+static void format_debug_text( char *msg )
+ {
+ size_t i;
+ BOOL timestamp = (!stdout_logging && (lp_timestamp_logs() ||
+ !(lp_loaded())));
+
+ for( i = 0; msg[i]; i++ )
+ {
+ /* Indent two spaces at each new line. */
+ if(timestamp && 0 == format_pos)
+ {
+ format_bufr[0] = format_bufr[1] = ' ';
+ format_pos = 2;
+ }
+
+ /* If there's room, copy the character to the format buffer. */
+ if( format_pos < FORMAT_BUFR_MAX )
+ format_bufr[format_pos++] = msg[i];
+
+ /* If a newline is encountered, print & restart. */
+ if( '\n' == msg[i] )
+ bufr_print();
+
+ /* If the buffer is full dump it out, reset it, and put out a line
+ * continuation indicator.
+ */
+ if( format_pos >= FORMAT_BUFR_MAX )
+ {
+ bufr_print();
+ (void)Debug1( " +>\n" );
+ }
+ }
+
+ /* Just to be safe... */
+ format_bufr[format_pos] = '\0';
+ } /* format_debug_text */
+
+/* ************************************************************************** **
+ * Flush debug output, including the format buffer content.
+ *
+ * Input: none
+ * Output: none
+ *
+ * ************************************************************************** **
+ */
+void dbgflush( void )
+ {
+ bufr_print();
+ if(dbf)
+ (void)x_fflush( dbf );
+ } /* dbgflush */
+
+/* ************************************************************************** **
+ * Print a Debug Header.
+ *
+ * Input: level - Debug level of the message (not the system-wide debug
+ * level. )
+ * file - Pointer to a string containing the name of the file
+ * from which this function was called, or an empty string
+ * if the __FILE__ macro is not implemented.
+ * func - Pointer to a string containing the name of the function
+ * from which this function was called, or an empty string
+ * if the __FUNCTION__ macro is not implemented.
+ * line - line number of the call to dbghdr, assuming __LINE__
+ * works.
+ *
+ * Output: Always True. This makes it easy to fudge a call to dbghdr()
+ * in a macro, since the function can be called as part of a test.
+ * Eg: ( (level <= DEBUGLEVEL) && (dbghdr(level,"",line)) )
+ *
+ * Notes: This function takes care of setting syslog_level.
+ *
+ * ************************************************************************** **
+ */
+
+BOOL dbghdr( int level, char *file, char *func, int line )
+{
+ /* Ensure we don't lose any real errno value. */
+ int old_errno = errno;
+
+ if( format_pos ) {
+ /* This is a fudge. If there is stuff sitting in the format_bufr, then
+ * the *right* thing to do is to call
+ * format_debug_text( "\n" );
+ * to write the remainder, and then proceed with the new header.
+ * Unfortunately, there are several places in the code at which
+ * the DEBUG() macro is used to build partial lines. That in mind,
+ * we'll work under the assumption that an incomplete line indicates
+ * that a new header is *not* desired.
+ */
+ return( True );
+ }
+
+#ifdef WITH_SYSLOG
+ /* Set syslog_level. */
+ syslog_level = level;
+#endif
+
+ /* Don't print a header if we're logging to stdout. */
+ if( stdout_logging )
+ return( True );
+
+ /* Print the header if timestamps are turned on. If parameters are
+ * not yet loaded, then default to timestamps on.
+ */
+ if( lp_timestamp_logs() || !(lp_loaded()) ) {
+ char header_str[200];
+
+ header_str[0] = '\0';
+
+ if( lp_debug_pid())
+ slprintf(header_str,sizeof(header_str)-1,", pid=%u",(unsigned int)sys_getpid());
+
+ if( lp_debug_uid()) {
+ size_t hs_len = strlen(header_str);
+ slprintf(header_str + hs_len,
+ sizeof(header_str) - 1 - hs_len,
+ ", effective(%u, %u), real(%u, %u)",
+ (unsigned int)geteuid(), (unsigned int)getegid(),
+ (unsigned int)getuid(), (unsigned int)getgid());
+ }
+
+ /* Print it all out at once to prevent split syslog output. */
+ (void)Debug1( "[%s, %d%s] %s:%s(%d)\n",
+ timestring(lp_debug_hires_timestamp()), level,
+ header_str, file, func, line );
+ }
+
+ errno = old_errno;
+ return( True );
+}
+
+/* ************************************************************************** **
+ * Add text to the body of the "current" debug message via the format buffer.
+ *
+ * Input: format_str - Format string, as used in printf(), et. al.
+ * ... - Variable argument list.
+ *
+ * ..or.. va_alist - Old style variable parameter list starting point.
+ *
+ * Output: Always True. See dbghdr() for more info, though this is not
+ * likely to be used in the same way.
+ *
+ * ************************************************************************** **
+ */
+ BOOL dbgtext( char *format_str, ... )
+ {
+ va_list ap;
+ pstring msgbuf;
+
+ va_start( ap, format_str );
+ vslprintf( msgbuf, sizeof(msgbuf)-1, format_str, ap );
+ va_end( ap );
+
+ format_debug_text( msgbuf );
+
+ return( True );
+ } /* dbgtext */
+
+
+/* ************************************************************************** */
diff --git a/source3/lib/dmallocmsg.c b/source3/lib/dmallocmsg.c
new file mode 100644
index 0000000000..a83ed518d7
--- /dev/null
+++ b/source3/lib/dmallocmsg.c
@@ -0,0 +1,72 @@
+/*
+ samba -- Unix SMB/CIFS implementation.
+ Copyright (C) 2002 by Martin Pool
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/**
+ * @file dmallocmsg.c
+ *
+ * Glue code to cause dmalloc info to come out when we receive a prod
+ * over samba messaging.
+ **/
+
+#ifdef ENABLE_DMALLOC
+static unsigned long our_dm_mark = 0;
+#endif /* ENABLE_DMALLOC */
+
+
+/**
+ * Respond to a POOL_USAGE message by sending back string form of memory
+ * usage stats.
+ **/
+static void msg_req_dmalloc_mark(int UNUSED(msg_type), pid_t UNUSED(src_pid),
+ void *UNUSED(buf), size_t UNUSED(len))
+{
+#ifdef ENABLE_DMALLOC
+ our_dm_mark = dmalloc_mark();
+ DEBUG(2,("Got MSG_REQ_DMALLOC_MARK: mark set\n"));
+#else
+ DEBUG(2,("Got MSG_REQ_DMALLOC_MARK but dmalloc not in this process\n"));
+#endif
+}
+
+
+
+static void msg_req_dmalloc_log_changed(int UNUSED(msg_type),
+ pid_t UNUSED(src_pid),
+ void *UNUSED(buf), size_t UNUSED(len))
+{
+#ifdef ENABLE_DMALLOC
+ dmalloc_log_changed(our_dm_mark, True, True, True);
+ DEBUG(2,("Got MSG_REQ_DMALLOC_LOG_CHANGED: done\n"));
+#else
+ DEBUG(2,("Got MSG_REQ_DMALLOC_LOG_CHANGED but dmalloc not in this process\n"));
+#endif
+}
+
+
+/**
+ * Register handler for MSG_REQ_POOL_USAGE
+ **/
+void register_dmalloc_msgs(void)
+{
+ message_register(MSG_REQ_DMALLOC_MARK, msg_req_dmalloc_mark);
+ message_register(MSG_REQ_DMALLOC_LOG_CHANGED, msg_req_dmalloc_log_changed);
+ DEBUG(2, ("Registered MSG_REQ_DMALLOC_MARK and LOG_CHANGED\n"));
+}
diff --git a/source3/lib/dprintf.c b/source3/lib/dprintf.c
new file mode 100644
index 0000000000..dadebdb3b4
--- /dev/null
+++ b/source3/lib/dprintf.c
@@ -0,0 +1,110 @@
+/*
+ Unix SMB/CIFS implementation.
+ display print functions
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+/*
+ this module provides functions for printing internal strings in the "display charset"
+ This charset may be quite different from the chosen unix charset
+
+ Eventually these functions will need to take care of column count constraints
+
+ The d_ prefix on print functions in Samba refers to the display character set
+ conversion
+*/
+
+#include "includes.h"
+
+int d_vfprintf(FILE *f, const char *format, va_list ap)
+{
+ char *p, *p2;
+ int ret, maxlen, clen;
+ const char *msgstr;
+
+ /* do any message translations */
+ msgstr = lang_msg(format);
+ if (!msgstr) return -1;
+
+ ret = vasprintf(&p, msgstr, ap);
+
+ lang_msg_free(msgstr);
+
+ if (ret <= 0) return ret;
+
+ /* now we have the string in unix format, convert it to the display
+ charset, but beware of it growing */
+ maxlen = ret*2;
+again:
+ p2 = malloc(maxlen);
+ if (!p2) {
+ SAFE_FREE(p);
+ return -1;
+ }
+ clen = convert_string(CH_UNIX, CH_DISPLAY, p, ret, p2, maxlen);
+
+ if (clen >= maxlen) {
+ /* it didn't fit - try a larger buffer */
+ maxlen *= 2;
+ SAFE_FREE(p2);
+ goto again;
+ }
+
+ /* good, its converted OK */
+ SAFE_FREE(p);
+ ret = fwrite(p2, 1, clen, f);
+ SAFE_FREE(p2);
+
+ return ret;
+}
+
+
+ int d_fprintf(FILE *f, const char *format, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, format);
+ ret = d_vfprintf(f, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+static FILE *outfile;
+
+ int d_printf(const char *format, ...)
+{
+ int ret;
+ va_list ap;
+
+ if (!outfile) outfile = stdout;
+
+ va_start(ap, format);
+ ret = d_vfprintf(outfile, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+/* interactive programs need a way of tell d_*() to write to stderr instead
+ of stdout */
+void display_set_stderr(void)
+{
+ outfile = stderr;
+}
diff --git a/source3/lib/error.c b/source3/lib/error.c
new file mode 100644
index 0000000000..22ac1cb2d7
--- /dev/null
+++ b/source3/lib/error.c
@@ -0,0 +1,72 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Unix/DOS/NT error code conversions
+ * Copyright (C) Tim Potter 2000
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+/* Mapping between Unix, DOS and NT error numbers */
+
+const struct unix_error_map unix_dos_nt_errmap[] = {
+ { EPERM, ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED },
+ { EACCES, ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED },
+ { ENOENT, ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE },
+ { ENOTDIR, ERRDOS, ERRbadpath, NT_STATUS_NOT_A_DIRECTORY },
+ { EIO, ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR },
+ { EBADF, ERRSRV, ERRsrverror, NT_STATUS_INVALID_HANDLE },
+ { EINVAL, ERRSRV, ERRsrverror, NT_STATUS_INVALID_HANDLE },
+ { EEXIST, ERRDOS, ERRfilexists, NT_STATUS_OBJECT_NAME_COLLISION},
+ { ENFILE, ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES },
+ { EMFILE, ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES },
+ { ENOSPC, ERRHRD, ERRdiskfull, NT_STATUS_DISK_FULL },
+#ifdef EDQUOT
+ { EDQUOT, ERRHRD, ERRdiskfull, NT_STATUS_DISK_FULL },
+#endif
+#ifdef ENOTEMPTY
+ { ENOTEMPTY, ERRDOS, ERRnoaccess, NT_STATUS_DIRECTORY_NOT_EMPTY },
+#endif
+#ifdef EXDEV
+ { EXDEV, ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE },
+#endif
+#ifdef EROFS
+ { EROFS, ERRHRD, ERRnowrite, NT_STATUS_ACCESS_DENIED },
+#endif
+ { 0, 0, 0, NT_STATUS_OK }
+};
+
+/*********************************************************************
+ Map an NT error code from a Unix error code.
+*********************************************************************/
+
+NTSTATUS map_nt_error_from_unix(int unix_error)
+{
+ int i = 0;
+
+ if (unix_error == 0)
+ return NT_STATUS_OK;
+
+ /* Look through list */
+ while(unix_dos_nt_errmap[i].unix_error != 0) {
+ if (unix_dos_nt_errmap[i].unix_error == unix_error)
+ return unix_dos_nt_errmap[i].nt_error;
+ i++;
+ }
+
+ /* Default return */
+ return NT_STATUS_ACCESS_DENIED;
+}
diff --git a/source3/lib/fault.c b/source3/lib/fault.c
index 20c75f7876..e132ed8f67 100644
--- a/source3/lib/fault.c
+++ b/source3/lib/fault.c
@@ -1,8 +1,7 @@
/*
- Unix SMB/Netbios implementation.
- Version 1.9.
+ Unix SMB/CIFS implementation.
Critical Fault handling
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,44 +18,39 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#ifdef LINUX
-#define __KERNEL__
-#endif
-
#include "includes.h"
-extern int DEBUGLEVEL;
-
-
-static void (*cont_fn)();
+static void (*cont_fn)(void *);
/*******************************************************************
report a fault
********************************************************************/
static void fault_report(int sig)
{
- DEBUG(0,("===============================================================\n"));
- DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)getpid(),VERSION));
- DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n"));
- DEBUG(0,("===============================================================\n"));
+ static int counter;
+
+ if (counter) _exit(1);
+
+ counter++;
+
+ DEBUG(0,("===============================================================\n"));
+ DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)sys_getpid(),VERSION));
+ DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n"));
+ DEBUG(0,("===============================================================\n"));
-#if AJT
- ajt_panic();
-#endif
+ smb_panic("internal error");
- if (cont_fn)
- {
- fault_setup(cont_fn);
- cont_fn(NULL);
+ if (cont_fn) {
+ cont_fn(NULL);
#ifdef SIGSEGV
- signal(SIGSEGV,SIGNAL_CAST SIG_DFL);
+ CatchSignal(SIGSEGV,SIGNAL_CAST SIG_DFL);
#endif
#ifdef SIGBUS
- signal(SIGBUS,SIGNAL_CAST SIG_DFL);
+ CatchSignal(SIGBUS,SIGNAL_CAST SIG_DFL);
#endif
- return; /* this should cause a core dump */
- }
- exit(1);
+ return; /* this should cause a core dump */
+ }
+ exit(1);
}
/****************************************************************************
@@ -64,21 +58,21 @@ catch serious errors
****************************************************************************/
static void sig_fault(int sig)
{
- fault_report(sig);
+ fault_report(sig);
}
/*******************************************************************
setup our fault handlers
********************************************************************/
-void fault_setup(void (*fn)())
+void fault_setup(void (*fn)(void *))
{
- cont_fn = fn;
+ cont_fn = fn;
#ifdef SIGSEGV
- signal(SIGSEGV,SIGNAL_CAST sig_fault);
+ CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault);
#endif
#ifdef SIGBUS
- signal(SIGBUS,SIGNAL_CAST sig_fault);
+ CatchSignal(SIGBUS,SIGNAL_CAST sig_fault);
#endif
}
diff --git a/source3/lib/fsusage.c b/source3/lib/fsusage.c
new file mode 100644
index 0000000000..bb7cff0645
--- /dev/null
+++ b/source3/lib/fsusage.c
@@ -0,0 +1,148 @@
+/*
+ Unix SMB/CIFS implementation.
+ functions to calculate the free disk space
+ Copyright (C) Andrew Tridgell 1998-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+
+/* Return the number of TOSIZE-byte blocks used by
+ BLOCKS FROMSIZE-byte blocks, rounding away from zero.
+*/
+static SMB_BIG_UINT adjust_blocks(SMB_BIG_UINT blocks, SMB_BIG_UINT fromsize, SMB_BIG_UINT tosize)
+{
+ if (fromsize == tosize) /* e.g., from 512 to 512 */
+ return blocks;
+ else if (fromsize > tosize) /* e.g., from 2048 to 512 */
+ return blocks * (fromsize / tosize);
+ else /* e.g., from 256 to 512 */
+ return (blocks + 1) / (tosize / fromsize);
+}
+
+/* this does all of the system specific guff to get the free disk space.
+ It is derived from code in the GNU fileutils package, but has been
+ considerably mangled for use here
+
+ results are returned in *dfree and *dsize, in 512 byte units
+*/
+int sys_fsusage(const char *path, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
+{
+#ifdef STAT_STATFS3_OSF1
+#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_fsize, (SMB_BIG_UINT)512)
+ struct statfs fsd;
+
+ if (statfs (path, &fsd, sizeof (struct statfs)) != 0)
+ return -1;
+#endif /* STAT_STATFS3_OSF1 */
+
+#ifdef STAT_STATFS2_FS_DATA /* Ultrix */
+#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)1024, (SMB_BIG_UINT)512)
+ struct fs_data fsd;
+
+ if (statfs (path, &fsd) != 1)
+ return -1;
+
+ (*dsize) = CONVERT_BLOCKS (fsd.fd_req.btot);
+ (*dfree) = CONVERT_BLOCKS (fsd.fd_req.bfreen);
+#endif /* STAT_STATFS2_FS_DATA */
+
+#ifdef STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX */
+#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_bsize, (SMB_BIG_UINT)512)
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+
+#ifdef STATFS_TRUNCATES_BLOCK_COUNTS
+ /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
+ struct statfs are truncated to 2GB. These conditions detect that
+ truncation, presumably without botching the 4.1.1 case, in which
+ the values are not truncated. The correct counts are stored in
+ undocumented spare fields. */
+ if (fsd.f_blocks == 0x1fffff && fsd.f_spare[0] > 0) {
+ fsd.f_blocks = fsd.f_spare[0];
+ fsd.f_bfree = fsd.f_spare[1];
+ fsd.f_bavail = fsd.f_spare[2];
+ }
+#endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
+#endif /* STAT_STATFS2_BSIZE */
+
+
+#ifdef STAT_STATFS2_FSIZE /* 4.4BSD */
+#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_fsize, (SMB_BIG_UINT)512)
+
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+#endif /* STAT_STATFS2_FSIZE */
+
+#ifdef STAT_STATFS4 /* SVR3, Dynix, Irix, AIX */
+# if _AIX || defined(_CRAY)
+# define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_bsize, (SMB_BIG_UINT)512)
+# ifdef _CRAY
+# define f_bavail f_bfree
+# endif
+# else
+# define CONVERT_BLOCKS(B) ((SMB_BIG_UINT)B)
+# ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx */
+# ifndef DOLPHIN /* DOLPHIN 3.8.alfa/7.18 has f_bavail */
+# define f_bavail f_bfree
+# endif
+# endif
+# endif
+
+ struct statfs fsd;
+
+ if (statfs (path, &fsd, sizeof fsd, 0) < 0)
+ return -1;
+ /* Empirically, the block counts on most SVR3 and SVR3-derived
+ systems seem to always be in terms of 512-byte blocks,
+ no matter what value f_bsize has. */
+
+#endif /* STAT_STATFS4 */
+
+#if defined(STAT_STATVFS) || defined(STAT_STATVFS64) /* SVR4 */
+# define CONVERT_BLOCKS(B) \
+ adjust_blocks ((SMB_BIG_UINT)(B), fsd.f_frsize ? (SMB_BIG_UINT)fsd.f_frsize : (SMB_BIG_UINT)fsd.f_bsize, (SMB_BIG_UINT)512)
+
+#ifdef STAT_STATVFS64
+ struct statvfs64 fsd;
+ if (statvfs64(path, &fsd) < 0) return -1;
+#else
+ struct statvfs fsd;
+ if (statvfs(path, &fsd) < 0) return -1;
+#endif
+
+ /* f_frsize isn't guaranteed to be supported. */
+
+#endif /* STAT_STATVFS */
+
+#ifndef CONVERT_BLOCKS
+ /* we don't have any dfree code! */
+ return -1;
+#else
+#if !defined(STAT_STATFS2_FS_DATA)
+ /* !Ultrix */
+ (*dsize) = CONVERT_BLOCKS (fsd.f_blocks);
+ (*dfree) = CONVERT_BLOCKS (fsd.f_bavail);
+#endif /* not STAT_STATFS2_FS_DATA */
+#endif
+
+ return 0;
+}
diff --git a/source3/lib/genrand.c b/source3/lib/genrand.c
new file mode 100644
index 0000000000..6296ead726
--- /dev/null
+++ b/source3/lib/genrand.c
@@ -0,0 +1,267 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Functions to create reasonable random numbers for crypto use.
+
+ Copyright (C) Jeremy Allison 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static unsigned char hash[258];
+static uint32 counter;
+unsigned char *reseed_data;
+size_t reseed_data_size;
+
+/****************************************************************
+ Copy any user given reseed data.
+*****************************************************************/
+
+void set_rand_reseed_data(unsigned char *data, size_t len)
+{
+ SAFE_FREE(reseed_data);
+ reseed_data_size = 0;
+
+ reseed_data = (unsigned char *)memdup(data, len);
+ if (reseed_data)
+ reseed_data_size = len;
+}
+
+/****************************************************************
+ Setup the seed.
+*****************************************************************/
+
+static void seed_random_stream(unsigned char *seedval, size_t seedlen)
+{
+ unsigned char j = 0;
+ size_t ind;
+
+ for (ind = 0; ind < 256; ind++)
+ hash[ind] = (unsigned char)ind;
+
+ for( ind = 0; ind < 256; ind++) {
+ unsigned char tc;
+
+ j += (hash[ind] + seedval[ind%seedlen]);
+
+ tc = hash[ind];
+ hash[ind] = hash[j];
+ hash[j] = tc;
+ }
+
+ hash[256] = 0;
+ hash[257] = 0;
+}
+
+/****************************************************************
+ Get datasize bytes worth of random data.
+*****************************************************************/
+
+static void get_random_stream(unsigned char *data, size_t datasize)
+{
+ unsigned char index_i = hash[256];
+ unsigned char index_j = hash[257];
+ size_t ind;
+
+ for( ind = 0; ind < datasize; ind++) {
+ unsigned char tc;
+ unsigned char t;
+
+ index_i++;
+ index_j += hash[index_i];
+
+ tc = hash[index_i];
+ hash[index_i] = hash[index_j];
+ hash[index_j] = tc;
+
+ t = hash[index_i] + hash[index_j];
+ data[ind] = hash[t];
+ }
+
+ hash[256] = index_i;
+ hash[257] = index_j;
+}
+
+/****************************************************************
+ Get a 16 byte hash from the contents of a file.
+ Note that the hash is not initialised.
+*****************************************************************/
+
+static void do_filehash(char *fname, unsigned char *the_hash)
+{
+ unsigned char buf[1011]; /* deliberate weird size */
+ unsigned char tmp_md4[16];
+ int fd, n;
+
+ fd = sys_open(fname,O_RDONLY,0);
+ if (fd == -1)
+ return;
+
+ while ((n = read(fd, (char *)buf, sizeof(buf))) > 0) {
+ mdfour(tmp_md4, buf, n);
+ for (n=0;n<16;n++)
+ the_hash[n] ^= tmp_md4[n];
+ }
+ close(fd);
+}
+
+/**************************************************************
+ Try and get a good random number seed. Try a number of
+ different factors. Firstly, try /dev/urandom - use if exists.
+
+ We use /dev/urandom as a read of /dev/random can block if
+ the entropy pool dries up. This leads clients to timeout
+ or be very slow on connect.
+
+ If we can't use /dev/urandom then seed the stream random generator
+ above...
+**************************************************************/
+
+static int do_reseed(BOOL use_fd, int fd)
+{
+ unsigned char seed_inbuf[40];
+ uint32 v1, v2; struct timeval tval; pid_t mypid;
+ struct passwd *pw;
+
+ if (use_fd) {
+ if (fd != -1)
+ return fd;
+
+ fd = sys_open( "/dev/urandom", O_RDONLY,0);
+ if(fd >= 0)
+ return fd;
+ }
+
+ /* Add in some secret file contents */
+
+ do_filehash("/etc/shadow", &seed_inbuf[0]);
+ do_filehash(lp_smb_passwd_file(), &seed_inbuf[16]);
+
+ /*
+ * Add in the root encrypted password.
+ * On any system where security is taken
+ * seriously this will be secret.
+ */
+
+ pw = getpwnam_alloc("root");
+ if (pw && pw->pw_passwd) {
+ size_t i;
+ unsigned char md4_tmp[16];
+ mdfour(md4_tmp, (unsigned char *)pw->pw_passwd, strlen(pw->pw_passwd));
+ for (i=0;i<16;i++)
+ seed_inbuf[8+i] ^= md4_tmp[i];
+ passwd_free(&pw);
+ }
+
+ /*
+ * Add the counter, time of day, and pid.
+ */
+
+ GetTimeOfDay(&tval);
+ mypid = sys_getpid();
+ v1 = (counter++) + mypid + tval.tv_sec;
+ v2 = (counter++) * mypid + tval.tv_usec;
+
+ SIVAL(seed_inbuf, 32, v1 ^ IVAL(seed_inbuf, 32));
+ SIVAL(seed_inbuf, 36, v2 ^ IVAL(seed_inbuf, 36));
+
+ /*
+ * Add any user-given reseed data.
+ */
+
+ if (reseed_data) {
+ size_t i;
+ for (i = 0; i < sizeof(seed_inbuf); i++)
+ seed_inbuf[i] ^= reseed_data[i % reseed_data_size];
+ }
+
+ seed_random_stream(seed_inbuf, sizeof(seed_inbuf));
+
+ return -1;
+}
+
+/*******************************************************************
+ Interface to the (hopefully) good crypto random number generator.
+********************************************************************/
+
+void generate_random_buffer( unsigned char *out, int len, BOOL do_reseed_now)
+{
+ static BOOL done_reseed = False;
+ static int urand_fd = -1;
+ unsigned char md4_buf[64];
+ unsigned char tmp_buf[16];
+ unsigned char *p;
+
+ if(!done_reseed || do_reseed_now) {
+ urand_fd = do_reseed(True, urand_fd);
+ done_reseed = True;
+ }
+
+ if (urand_fd != -1 && len > 0) {
+
+ if (read(urand_fd, out, len) == len)
+ return; /* len bytes of random data read from urandom. */
+
+ /* Read of urand error, drop back to non urand method. */
+ close(urand_fd);
+ urand_fd = -1;
+ do_reseed(False, -1);
+ done_reseed = True;
+ }
+
+ /*
+ * Generate random numbers in chunks of 64 bytes,
+ * then md4 them & copy to the output buffer.
+ * This way the raw state of the stream is never externally
+ * seen.
+ */
+
+ p = out;
+ while(len > 0) {
+ int copy_len = len > 16 ? 16 : len;
+
+ get_random_stream(md4_buf, sizeof(md4_buf));
+ mdfour(tmp_buf, md4_buf, sizeof(md4_buf));
+ memcpy(p, tmp_buf, copy_len);
+ p += copy_len;
+ len -= copy_len;
+ }
+}
+
+/*******************************************************************
+ Use the random number generator to generate a random string.
+********************************************************************/
+
+static char c_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
+
+char *generate_random_str(size_t len)
+{
+ static unsigned char retstr[256];
+ size_t i;
+
+ memset(retstr, '\0', sizeof(retstr));
+
+ if (len > sizeof(retstr)-1)
+ len = sizeof(retstr) -1;
+ generate_random_buffer( retstr, len, False);
+ for (i = 0; i < len; i++)
+ retstr[i] = c_list[ retstr[i] % sizeof(c_list) ];
+
+ retstr[i] = '\0';
+
+ return (char *)retstr;
+}
diff --git a/source3/lib/getsmbpass.c b/source3/lib/getsmbpass.c
index 07a7dbfd9b..0874529d32 100644
--- a/source3/lib/getsmbpass.c
+++ b/source3/lib/getsmbpass.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+/* Copyright (C) 1992-1998 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -40,20 +40,19 @@ static struct termio t;
#define TCSANOW 0
#endif
-int tcgetattr(int fd, struct termio *t)
+static int tcgetattr(int fd, struct termio *t)
{
return ioctl(fd, TCGETA, t);
}
-int tcsetattr(int fd, int flags, const struct termio *t)
+static int tcsetattr(int fd, int flags, struct termio *t)
{
if(flags & TCSAFLUSH)
ioctl(fd, TCFLSH, TCIOFLUSH);
return ioctl(fd, TCSETS, t);
}
-#else /* SYSV_TERMIO */
-#ifdef BSD_TERMIO
+#elif !defined(TCSAFLUSH)
/* BSD TERMIO HANDLING */
@@ -63,37 +62,28 @@ static struct sgttyb t;
#define TURN_ECHO_OFF(t) ((t).sg_flags &= ~ECHO)
#define TURN_ECHO_ON(t) ((t).sg_flags |= ECHO)
-#ifndef TCSAFLUSH
#define TCSAFLUSH 1
-#endif
-
-#ifndef TCSANOW
#define TCSANOW 0
-#endif
-int tcgetattr(int fd, struct sgttyb *t)
+static int tcgetattr(int fd, struct sgttyb *t)
{
return ioctl(fd, TIOCGETP, (char *)t);
}
-int tcsetattr(int fd, int flags, const struct sgttyb *t)
+static int tcsetattr(int fd, int flags, struct sgttyb *t)
{
return ioctl(fd, TIOCSETP, (char *)t);
}
-#else /* BSD_TERMIO */
-
-/* POSIX TERMIO HANDLING */
+#else /* POSIX TERMIO HANDLING */
#define ECHO_IS_ON(t) ((t).c_lflag & ECHO)
#define TURN_ECHO_OFF(t) ((t).c_lflag &= ~ECHO)
#define TURN_ECHO_ON(t) ((t).c_lflag |= ECHO)
static struct termios t;
-#endif /* BSD_TERMIO */
#endif /* SYSV_TERMIO */
-char *
-getsmbpass(char *prompt)
+char *getsmbpass(char *prompt)
{
FILE *in, *out;
int echo_off;
@@ -102,7 +92,7 @@ getsmbpass(char *prompt)
size_t nread;
/* Catch problematic signals */
- signal(SIGINT, SIGNAL_CAST SIG_IGN);
+ CatchSignal(SIGINT, SIGNAL_CAST SIG_IGN);
/* Try to write to and read from the terminal if we can.
If we can't open the terminal, use stderr and stdin. */
@@ -154,13 +144,13 @@ getsmbpass(char *prompt)
fclose (in);
/* Catch problematic signals */
- signal(SIGINT, SIGNAL_CAST SIG_DFL);
+ CatchSignal(SIGINT, SIGNAL_CAST SIG_DFL);
printf("\n");
return buf;
}
#else
-
-void getsmbpasswd_dummy() {;}
+ void getsmbpasswd_dummy(void);
+ void getsmbpasswd_dummy(void) {;}
#endif
diff --git a/source3/lib/hash.c b/source3/lib/hash.c
new file mode 100644
index 0000000000..6b7a8476b1
--- /dev/null
+++ b/source3/lib/hash.c
@@ -0,0 +1,315 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Ying Chen 2000.
+ Copyright (C) Jeremy Allison 2000.
+ - added some defensive programming.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ * NB. We may end up replacing this functionality in a future 2.x
+ * release to reduce the number of hashing/lookup methods we support. JRA.
+ */
+
+#include "includes.h"
+
+static BOOL enlarge_hash_table(hash_table *table);
+static int primes[] =
+ {17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, 16411};
+
+/****************************************************************************
+ * This function initializes the hash table.
+ * This hash function hashes on string keys.
+ * This number of hash buckets is always rounded up to a power of
+ * 2 first, then to a prime number that is large than the power of two.
+ * Input:
+ * table -- the hash table pointer.
+ * num_buckets -- the number of buckets to be allocated. This
+ * hash function can dynamically increase its size when the
+ * the hash table size becomes small. There is a MAX hash table
+ * size defined in hash.h.
+ * compare_func -- the function pointer to a comparison function
+ * used by the hash key comparison.
+ ****************************************************************************
+ */
+
+BOOL hash_table_init(hash_table *table, int num_buckets, compare_function compare_func)
+{
+ int i;
+ ubi_dlList *bucket;
+
+ table->num_elements = 0;
+ table->size = 2;
+ table->comp_func = compare_func;
+ while (table->size < num_buckets)
+ table->size <<= 1;
+ for (i = 0; i < ARRAY_SIZE(primes); i++) {
+ if (primes[i] > table->size) {
+ table->size = primes[i];
+ break;
+ }
+ }
+
+ DEBUG(5, ("Hash size = %d.\n", table->size));
+
+ if(!(table->buckets = (ubi_dlList *) malloc(sizeof(ubi_dlList) * table->size))) {
+ DEBUG(0,("hash_table_init: malloc fail !\n"));
+ return False;
+ }
+ ubi_dlInitList(&(table->lru_chain));
+ for (i=0, bucket = table->buckets; i < table->size; i++, bucket++)
+ ubi_dlInitList(bucket);
+
+ return True;
+}
+
+/*
+ **************************************************************
+ * Compute a hash value based on a string key value.
+ * Make the string key into an array of int's if possible.
+ * For the last few chars that cannot be int'ed, use char instead.
+ * The function returns the bucket index number for the hashed
+ * key.
+ **************************************************************
+ */
+
+static int string_hash(int hash_size, const char *key)
+{
+ u32 value; /* Used to compute the hash value. */
+ u32 i; /* Used to cycle through random values. */
+
+ for (value = 0x238F13AF, i=0; key[i]; i++)
+ value = (value + (key[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345) % hash_size;
+}
+
+
+/* *************************************************************************
+ * Search the hash table for the entry in the hash chain.
+ * The function returns the pointer to the
+ * element found in the chain or NULL if none is found.
+ * If the element is found, the element is also moved to
+ * the head of the LRU list.
+ *
+ * Input:
+ * table -- The hash table where the element is stored in.
+ * hash_chain -- The pointer to the bucket that stores the
+ * element to be found.
+ * key -- The hash key to be found.
+ ***************************************************************************
+ */
+
+static hash_element *hash_chain_find(hash_table *table, ubi_dlList *hash_chain, char *key)
+{
+ hash_element *hash_elem;
+ ubi_dlNodePtr lru_item;
+ int i = 0;
+
+ for (hash_elem = (hash_element *)(ubi_dlFirst(hash_chain)); i < hash_chain->count;
+ i++, hash_elem = (hash_element *)(ubi_dlNext(hash_elem))) {
+ if ((table->comp_func)(hash_elem->key, key) == 0) {
+ /* Move to the head of the lru List. */
+ lru_item = ubi_dlRemove(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
+ ubi_dlAddHead(&(table->lru_chain), lru_item);
+ return(hash_elem);
+ }
+ }
+ return ((hash_element *) NULL);
+}
+
+/* ***************************************************************************
+ *
+ * Lookup a hash table for an element with key.
+ * The function returns a pointer to the hash element.
+ * If no element is found, the function returns NULL.
+ *
+ * Input:
+ * table -- The hash table to be searched on.
+ * key -- The key to be found.
+ *****************************************************************************
+ */
+
+hash_element *hash_lookup(hash_table *table, char *key)
+{
+ return (hash_chain_find(table, &table->buckets[string_hash(table->size, key)], key));
+}
+
+/* ***************************************************************
+ *
+ * This function first checks if an element with key "key"
+ * exists in the hash table. If so, the function moves the
+ * element to the front of the LRU list. Otherwise, a new
+ * hash element corresponding to "value" and "key" is allocated
+ * and inserted into the hash table. The new elements are
+ * always inserted in the LRU order to the LRU list as well.
+ *
+ * Input:
+ * table -- The hash table to be inserted in.
+ * value -- The content of the element to be inserted.
+ * key -- The key of the new element to be inserted.
+ *
+ ****************************************************************
+ */
+
+hash_element *hash_insert(hash_table *table, char *value, char *key)
+{
+ hash_element *hash_elem;
+ ubi_dlNodePtr lru_item;
+ ubi_dlList *bucket;
+
+ /*
+ * If the hash table size has not reached the MAX_HASH_TABLE_SIZE,
+ * the hash table may be enlarged if the current hash table is full.
+ * If the hash table size has reached the MAX_HASH_TABLE_SIZE,
+ * use LRU to remove the oldest element from the hash table.
+ */
+
+ if ((table->num_elements >= table->size) &&
+ (table->num_elements < MAX_HASH_TABLE_SIZE)) {
+ if(!enlarge_hash_table(table))
+ return (hash_element *)NULL;
+ table->num_elements += 1;
+ } else if (table->num_elements >= MAX_HASH_TABLE_SIZE) {
+ /* Do an LRU replacement. */
+ lru_item = ubi_dlLast(&(table->lru_chain));
+ hash_elem = (hash_element *)(((lru_node *)lru_item)->hash_elem);
+ bucket = hash_elem->bucket;
+ ubi_dlRemThis(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
+ ubi_dlRemThis(bucket, (ubi_dlNodePtr)hash_elem);
+ SAFE_FREE(hash_elem->value);
+ SAFE_FREE(hash_elem);
+ } else {
+ table->num_elements += 1;
+ }
+
+ bucket = &table->buckets[string_hash(table->size, key)];
+
+ /* Since we only have 1-byte for the key string, we need to
+ * allocate extra space in the hash_element to store the entire key
+ * string.
+ */
+
+ if(!(hash_elem = (hash_element *) malloc(sizeof(hash_element) + strlen(key)))) {
+ DEBUG(0,("hash_insert: malloc fail !\n"));
+ return (hash_element *)NULL;
+ }
+
+ safe_strcpy((char *) hash_elem->key, key, strlen(key)+1);
+
+ hash_elem->value = (char *)value;
+ hash_elem->bucket = bucket;
+ /* Insert in front of the lru list and the bucket list. */
+ ubi_dlAddHead(bucket, hash_elem);
+ hash_elem->lru_link.hash_elem = hash_elem;
+ ubi_dlAddHead(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
+
+ return(hash_elem);
+}
+
+/* **************************************************************************
+ *
+ * Remove a hash element from the hash table. The hash element is
+ * removed from both the LRU list and the hash bucket chain.
+ *
+ * Input:
+ * table -- the hash table to be manipulated on.
+ * hash_elem -- the element to be removed.
+ **************************************************************************
+ */
+
+void hash_remove(hash_table *table, hash_element *hash_elem)
+{
+ if (hash_elem) {
+ ubi_dlRemove(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
+ ubi_dlRemove(hash_elem->bucket, (ubi_dlNodePtr) hash_elem);
+ SAFE_FREE(hash_elem->value);
+ SAFE_FREE(hash_elem);
+ table->num_elements--;
+ }
+}
+
+/* ******************************************************************
+ * Increase the hash table size if it is too small.
+ * The hash table size is increased by the HASH_TABLE_INCREMENT
+ * ratio.
+ * Input:
+ * table -- the hash table to be enlarged.
+ ******************************************************************
+ */
+
+static BOOL enlarge_hash_table(hash_table *table)
+{
+ hash_element *hash_elem;
+ int size, hash_value;
+ ubi_dlList *buckets;
+ ubi_dlList *old_bucket;
+ ubi_dlList *bucket;
+ ubi_dlList lru_chain;
+
+ buckets = table->buckets;
+ lru_chain = table->lru_chain;
+ size = table->size;
+
+ /* Reinitialize the hash table. */
+ if(!hash_table_init(table, table->size * HASH_TABLE_INCREMENT, table->comp_func))
+ return False;
+
+ for (old_bucket = buckets; size > 0; size--, old_bucket++) {
+ while (old_bucket->count != 0) {
+ hash_elem = (hash_element *) ubi_dlRemHead(old_bucket);
+ ubi_dlRemove(&lru_chain, &(hash_elem->lru_link.lru_link));
+ hash_value = string_hash(table->size, (char *) hash_elem->key);
+ bucket = &(table->buckets[hash_value]);
+ ubi_dlAddHead(bucket, hash_elem);
+ ubi_dlAddHead(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
+ hash_elem->bucket = bucket;
+ hash_elem->lru_link.hash_elem = hash_elem;
+ table->num_elements++;
+ }
+ }
+ SAFE_FREE(buckets);
+
+ return True;
+}
+
+/* **********************************************************************
+ *
+ * Remove everything from a hash table and free up the memory it
+ * occupies.
+ * Input:
+ * table -- the hash table to be cleared.
+ *
+ *************************************************************************
+ */
+
+void hash_clear(hash_table *table)
+{
+ int i;
+ ubi_dlList *bucket = table->buckets;
+ hash_element *hash_elem;
+ for (i = 0; i < table->size; bucket++, i++) {
+ while (bucket->count != 0) {
+ hash_elem = (hash_element *) ubi_dlRemHead(bucket);
+ SAFE_FREE(hash_elem->value);
+ SAFE_FREE(hash_elem);
+ }
+ }
+ table->size = 0;
+ SAFE_FREE(table->buckets);
+ table->buckets = NULL;
+}
diff --git a/source3/lib/hmacmd5.c b/source3/lib/hmacmd5.c
new file mode 100644
index 0000000000..f436fd30c0
--- /dev/null
+++ b/source3/lib/hmacmd5.c
@@ -0,0 +1,134 @@
+/*
+ Unix SMB/CIFS implementation.
+ HMAC MD5 code for use in NTLMv2
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Andrew Tridgell 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* taken direct from rfc2104 implementation and modified for suitable use
+ * for ntlmv2.
+ */
+
+#include "includes.h"
+
+/***********************************************************************
+ the rfc 2104 version of hmac_md5 initialisation.
+***********************************************************************/
+void hmac_md5_init_rfc2104(uchar* key, int key_len, HMACMD5Context *ctx)
+{
+ int i;
+
+ /* if key is longer than 64 bytes reset it to key=MD5(key) */
+ if (key_len > 64)
+ {
+ uchar tk[16];
+ struct MD5Context tctx;
+
+ MD5Init(&tctx);
+ MD5Update(&tctx, key, key_len);
+ MD5Final(tk, &tctx);
+
+ key = tk;
+ key_len = 16;
+ }
+
+ /* start out by storing key in pads */
+ ZERO_STRUCT(ctx->k_ipad);
+ ZERO_STRUCT(ctx->k_opad);
+ memcpy( ctx->k_ipad, key, key_len);
+ memcpy( ctx->k_opad, key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i=0; i<64; i++)
+ {
+ ctx->k_ipad[i] ^= 0x36;
+ ctx->k_opad[i] ^= 0x5c;
+ }
+
+ MD5Init(&ctx->ctx);
+ MD5Update(&ctx->ctx, ctx->k_ipad, 64);
+}
+
+/***********************************************************************
+ the microsoft version of hmac_md5 initialisation.
+***********************************************************************/
+void hmac_md5_init_limK_to_64(const uchar* key, int key_len,
+ HMACMD5Context *ctx)
+{
+ int i;
+
+ /* if key is longer than 64 bytes truncate it */
+ if (key_len > 64)
+ {
+ key_len = 64;
+ }
+
+ /* start out by storing key in pads */
+ ZERO_STRUCT(ctx->k_ipad);
+ ZERO_STRUCT(ctx->k_opad);
+ memcpy( ctx->k_ipad, key, key_len);
+ memcpy( ctx->k_opad, key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i=0; i<64; i++) {
+ ctx->k_ipad[i] ^= 0x36;
+ ctx->k_opad[i] ^= 0x5c;
+ }
+
+ MD5Init(&ctx->ctx);
+ MD5Update(&ctx->ctx, ctx->k_ipad, 64);
+}
+
+/***********************************************************************
+ update hmac_md5 "inner" buffer
+***********************************************************************/
+void hmac_md5_update(const uchar* text, int text_len, HMACMD5Context *ctx)
+{
+ MD5Update(&ctx->ctx, text, text_len); /* then text of datagram */
+}
+
+/***********************************************************************
+ finish off hmac_md5 "inner" buffer and generate outer one.
+***********************************************************************/
+void hmac_md5_final(uchar *digest, HMACMD5Context *ctx)
+
+{
+ struct MD5Context ctx_o;
+
+ MD5Final(digest, &ctx->ctx);
+
+ MD5Init(&ctx_o);
+ MD5Update(&ctx_o, ctx->k_opad, 64);
+ MD5Update(&ctx_o, digest, 16);
+ MD5Final(digest, &ctx_o);
+}
+
+/***********************************************************
+ single function to calculate an HMAC MD5 digest from data.
+ use the microsoft hmacmd5 init method because the key is 16 bytes.
+************************************************************/
+void hmac_md5( uchar key[16], uchar* data, int data_len, uchar* digest)
+{
+ HMACMD5Context ctx;
+ hmac_md5_init_limK_to_64(key, 16, &ctx);
+ if (data_len != 0)
+ {
+ hmac_md5_update(data, data_len, &ctx);
+ }
+ hmac_md5_final(digest, &ctx);
+}
+
diff --git a/source3/lib/iconv.c b/source3/lib/iconv.c
new file mode 100644
index 0000000000..43350d9349
--- /dev/null
+++ b/source3/lib/iconv.c
@@ -0,0 +1,581 @@
+/*
+ Unix SMB/CIFS implementation.
+ minimal iconv implementation
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static size_t ascii_pull(void *,char **, size_t *, char **, size_t *);
+static size_t ascii_push(void *,char **, size_t *, char **, size_t *);
+static size_t utf8_pull(void *,char **, size_t *, char **, size_t *);
+static size_t utf8_push(void *,char **, size_t *, char **, size_t *);
+static size_t weird_pull(void *,char **, size_t *, char **, size_t *);
+static size_t weird_push(void *,char **, size_t *, char **, size_t *);
+static size_t ucs2hex_pull(void *,char **, size_t *, char **, size_t *);
+static size_t ucs2hex_push(void *,char **, size_t *, char **, size_t *);
+static size_t iconv_copy(void *,char **, size_t *, char **, size_t *);
+
+/*
+ for each charset we have a function that pulls from that charset to
+ a ucs2 buffer, and a function that pushes to a ucs2 buffer
+*/
+static struct {
+ char *name;
+ size_t (*pull)(void *, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+ size_t (*push)(void *, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+} charsets[] = {
+ {"UCS-2LE", iconv_copy, iconv_copy},
+ {"UTF8", utf8_pull, utf8_push},
+ {"ASCII", ascii_pull, ascii_push},
+ {"WEIRD", weird_pull, weird_push},
+ {"UCS2-HEX", ucs2hex_pull, ucs2hex_push},
+ {NULL, NULL, NULL}
+};
+
+
+/* if there was an error then reset the internal state,
+ this ensures that we don't have a shift state remaining for
+ character sets like SJIS */
+static size_t sys_iconv(void *cd,
+ char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+#ifdef HAVE_NATIVE_ICONV
+ size_t ret = iconv((iconv_t)cd,
+ inbuf, inbytesleft,
+ outbuf, outbytesleft);
+ if (ret == (size_t)-1) iconv(cd, NULL, NULL, NULL, NULL);
+ return ret;
+#else
+ errno = EINVAL;
+ return -1;
+#endif
+}
+
+/*
+ this is a simple portable iconv() implementaion. It only knows about
+ a very small number of character sets - just enough that Samba works
+ on systems that don't have iconv
+ */
+size_t smb_iconv(smb_iconv_t cd,
+ const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ char cvtbuf[2048];
+ char *bufp = cvtbuf;
+ size_t bufsize;
+
+ /* in many cases we can go direct */
+ if (cd->direct) {
+ return cd->direct(cd->cd_direct,
+ (char **)inbuf, inbytesleft, outbuf, outbytesleft);
+ }
+
+
+ /* otherwise we have to do it chunks at a time */
+ while (*inbytesleft > 0) {
+ bufp = cvtbuf;
+ bufsize = sizeof(cvtbuf);
+
+ if (cd->pull(cd->cd_pull,
+ (char **)inbuf, inbytesleft, &bufp, &bufsize) == -1
+ && errno != E2BIG) return -1;
+
+ bufp = cvtbuf;
+ bufsize = sizeof(cvtbuf) - bufsize;
+
+ if (cd->push(cd->cd_push,
+ &bufp, &bufsize,
+ outbuf, outbytesleft) == -1) return -1;
+ }
+
+ return 0;
+}
+
+/*
+ simple iconv_open() wrapper
+ */
+smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
+{
+ smb_iconv_t ret;
+ int from, to;
+
+ ret = (smb_iconv_t)malloc(sizeof(*ret));
+ if (!ret) {
+ errno = ENOMEM;
+ return (smb_iconv_t)-1;
+ }
+ memset(ret, 0, sizeof(*ret));
+
+ ret->from_name = strdup(fromcode);
+ ret->to_name = strdup(tocode);
+
+ /* check for the simplest null conversion */
+ if (strcmp(fromcode, tocode) == 0) {
+ ret->direct = iconv_copy;
+ return ret;
+ }
+
+ for (from=0; charsets[from].name; from++) {
+ if (strcasecmp(charsets[from].name, fromcode) == 0) break;
+ }
+ for (to=0; charsets[to].name; to++) {
+ if (strcasecmp(charsets[to].name, tocode) == 0) break;
+ }
+
+#ifdef HAVE_NATIVE_ICONV
+ if (!charsets[from].name) {
+ ret->pull = sys_iconv;
+ ret->cd_pull = iconv_open("UCS-2LE", fromcode);
+ if (ret->cd_pull == (iconv_t)-1) goto failed;
+ }
+ if (!charsets[to].name) {
+ ret->push = sys_iconv;
+ ret->cd_push = iconv_open(tocode, "UCS-2LE");
+ if (ret->cd_push == (iconv_t)-1) goto failed;
+ }
+#else
+ if (!charsets[from].name || !charsets[to].name) {
+ goto failed;
+ }
+#endif
+
+ /* check for conversion to/from ucs2 */
+ if (from == 0 && charsets[to].name) {
+ ret->direct = charsets[to].push;
+ return ret;
+ }
+ if (to == 0 && charsets[from].name) {
+ ret->direct = charsets[from].pull;
+ return ret;
+ }
+
+#ifdef HAVE_NATIVE_ICONV
+ if (from == 0) {
+ ret->direct = sys_iconv;
+ ret->cd_direct = ret->cd_push;
+ ret->cd_push = NULL;
+ return ret;
+ }
+ if (to == 0) {
+ ret->direct = sys_iconv;
+ ret->cd_direct = ret->cd_pull;
+ ret->cd_pull = NULL;
+ return ret;
+ }
+#endif
+
+ /* the general case has to go via a buffer */
+ if (!ret->pull) ret->pull = charsets[from].pull;
+ if (!ret->push) ret->push = charsets[to].push;
+ return ret;
+
+failed:
+ SAFE_FREE(ret);
+ errno = EINVAL;
+ return (smb_iconv_t)-1;
+}
+
+/*
+ simple iconv_close() wrapper
+*/
+int smb_iconv_close (smb_iconv_t cd)
+{
+#ifdef HAVE_NATIVE_ICONV
+ if (cd->cd_direct) iconv_close((iconv_t)cd->cd_direct);
+ if (cd->cd_pull) iconv_close((iconv_t)cd->cd_pull);
+ if (cd->cd_push) iconv_close((iconv_t)cd->cd_push);
+#endif
+
+ SAFE_FREE(cd->from_name);
+ SAFE_FREE(cd->to_name);
+
+ memset(cd, 0, sizeof(*cd));
+ SAFE_FREE(cd);
+ return 0;
+}
+
+
+/**********************************************************************
+ the following functions implement the builtin character sets in Samba
+ and also the "test" character sets that are designed to test
+ multi-byte character set support for english users
+***********************************************************************/
+
+static size_t ascii_pull(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+ (*outbuf)[0] = (*inbuf)[0];
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= 1;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 1;
+ (*outbuf) += 2;
+ }
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t ascii_push(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int ir_count=0;
+
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ (*outbuf)[0] = (*inbuf)[0] & 0x7F;
+ if ((*inbuf)[1]) ir_count++;
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 1;
+ (*inbuf) += 2;
+ (*outbuf) += 1;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return ir_count;
+}
+
+
+static size_t ucs2hex_pull(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+ unsigned v;
+
+ if ((*inbuf)[0] != '@') {
+ /* seven bit ascii case */
+ (*outbuf)[0] = (*inbuf)[0];
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= 1;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 1;
+ (*outbuf) += 2;
+ continue;
+ }
+ /* it's a hex character */
+ if (*inbytesleft < 5) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (sscanf(&(*inbuf)[1], "%04x", &v) != 1) {
+ errno = EILSEQ;
+ return -1;
+ }
+
+ (*outbuf)[0] = v&0xff;
+ (*outbuf)[1] = v>>8;
+ (*inbytesleft) -= 5;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 5;
+ (*outbuf) += 2;
+ }
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t ucs2hex_push(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ char buf[6];
+
+ if ((*inbuf)[1] == 0 &&
+ ((*inbuf)[0] & 0x80) == 0 &&
+ (*inbuf)[0] != '@') {
+ (*outbuf)[0] = (*inbuf)[0];
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 1;
+ (*inbuf) += 2;
+ (*outbuf) += 1;
+ continue;
+ }
+ if (*outbytesleft < 5) {
+ errno = E2BIG;
+ return -1;
+ }
+ snprintf(buf, 6, "@%04x", SVAL(*inbuf, 0));
+ memcpy(*outbuf, buf, 5);
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 5;
+ (*inbuf) += 2;
+ (*outbuf) += 5;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* the "weird" character set is very useful for testing multi-byte
+ support and finding bugs. Don't use on a production system!
+*/
+static struct {
+ char from;
+ char *to;
+ int len;
+} weird_table[] = {
+ {'q', "^q^", 3},
+ {'Q', "^Q^", 3},
+ {0, NULL}
+};
+
+static size_t weird_pull(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+ int i;
+ int done = 0;
+ for (i=0;weird_table[i].from;i++) {
+ if (strncmp((*inbuf),
+ weird_table[i].to,
+ weird_table[i].len) == 0) {
+ if (*inbytesleft < weird_table[i].len) {
+ DEBUG(0,("ERROR: truncated weird string\n"));
+ /* smb_panic("weird_pull"); */
+
+ } else {
+ (*outbuf)[0] = weird_table[i].from;
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= weird_table[i].len;
+ (*outbytesleft) -= 2;
+ (*inbuf) += weird_table[i].len;
+ (*outbuf) += 2;
+ done = 1;
+ break;
+ }
+ }
+ }
+ if (done) continue;
+ (*outbuf)[0] = (*inbuf)[0];
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= 1;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 1;
+ (*outbuf) += 2;
+ }
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t weird_push(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int ir_count=0;
+
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ int i;
+ int done=0;
+ for (i=0;weird_table[i].from;i++) {
+ if ((*inbuf)[0] == weird_table[i].from &&
+ (*inbuf)[1] == 0) {
+ if (*outbytesleft < weird_table[i].len) {
+ DEBUG(0,("No room for weird character\n"));
+ /* smb_panic("weird_push"); */
+ } else {
+ memcpy(*outbuf, weird_table[i].to,
+ weird_table[i].len);
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= weird_table[i].len;
+ (*inbuf) += 2;
+ (*outbuf) += weird_table[i].len;
+ done = 1;
+ break;
+ }
+ }
+ }
+ if (done) continue;
+
+ (*outbuf)[0] = (*inbuf)[0];
+ if ((*inbuf)[1]) ir_count++;
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 1;
+ (*inbuf) += 2;
+ (*outbuf) += 1;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return ir_count;
+}
+
+static size_t iconv_copy(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int n;
+
+ n = MIN(*inbytesleft, *outbytesleft);
+
+ memmove(*outbuf, *inbuf, n);
+
+ (*inbytesleft) -= n;
+ (*outbytesleft) -= n;
+ (*inbuf) += n;
+ (*outbuf) += n;
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t utf8_pull(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+ unsigned char *c = (unsigned char *)*inbuf;
+ unsigned char *uc = (unsigned char *)*outbuf;
+ int len = 1;
+
+ if ((c[0] & 0x80) == 0) {
+ uc[0] = c[0];
+ uc[1] = 0;
+ } else if ((c[0] & 0xf0) == 0xe0) {
+ if (*inbytesleft < 3) {
+ DEBUG(0,("short utf8 char\n"));
+ goto badseq;
+ }
+ uc[1] = ((c[0]&0xF)<<4) | ((c[1]>>2)&0xF);
+ uc[0] = (c[1]<<6) | (c[2]&0x3f);
+ len = 3;
+ } else if ((c[0] & 0xe0) == 0xc0) {
+ if (*inbytesleft < 2) {
+ DEBUG(0,("short utf8 char\n"));
+ goto badseq;
+ }
+ uc[1] = (c[0]>>2) & 0x7;
+ uc[0] = (c[0]<<6) | (c[1]&0x3f);
+ len = 2;
+ }
+
+ (*inbuf) += len;
+ (*inbytesleft) -= len;
+ (*outbytesleft) -= 2;
+ (*outbuf) += 2;
+ }
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+
+badseq:
+ errno = EINVAL;
+ return -1;
+}
+
+static size_t utf8_push(void *cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ unsigned char *c = (unsigned char *)*outbuf;
+ unsigned char *uc = (unsigned char *)*inbuf;
+ int len=1;
+
+ if (uc[1] & 0xf8) {
+ if (*outbytesleft < 3) {
+ DEBUG(0,("short utf8 write\n"));
+ goto toobig;
+ }
+ c[0] = 0xe0 | (uc[1]>>4);
+ c[1] = 0x80 | ((uc[1]&0xF)<<2) | (uc[0]>>6);
+ c[2] = 0x80 | (uc[0]&0x3f);
+ len = 3;
+ } else if (uc[1] | (uc[0] & 0x80)) {
+ if (*outbytesleft < 2) {
+ DEBUG(0,("short utf8 write\n"));
+ goto toobig;
+ }
+ c[0] = 0xc0 | (uc[1]<<2) | (uc[0]>>6);
+ c[1] = 0x80 | (uc[0]&0x3f);
+ len = 2;
+ } else {
+ c[0] = uc[0];
+ }
+
+
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= len;
+ (*inbuf) += 2;
+ (*outbuf) += len;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+
+toobig:
+ errno = E2BIG;
+ return -1;
+}
+
diff --git a/source3/lib/interface.c b/source3/lib/interface.c
new file mode 100644
index 0000000000..d43001342e
--- /dev/null
+++ b/source3/lib/interface.c
@@ -0,0 +1,370 @@
+/*
+ Unix SMB/CIFS implementation.
+ multiple interface handling
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static struct iface_struct *probed_ifaces;
+static int total_probed;
+
+struct in_addr allones_ip;
+struct in_addr loopback_ip;
+
+static struct interface *local_interfaces;
+
+#define ALLONES ((uint32)0xFFFFFFFF)
+#define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
+#define MKNETADDR(_IP, _NM) (_IP & _NM)
+
+/****************************************************************************
+Try and find an interface that matches an ip. If we cannot, return NULL
+ **************************************************************************/
+static struct interface *iface_find(struct in_addr ip, BOOL CheckMask)
+{
+ struct interface *i;
+ if (is_zero_ip(ip)) return local_interfaces;
+
+ for (i=local_interfaces;i;i=i->next)
+ if (CheckMask) {
+ if (same_net(i->ip,ip,i->nmask)) return i;
+ } else if ((i->ip).s_addr == ip.s_addr) return i;
+
+ return NULL;
+}
+
+
+/****************************************************************************
+add an interface to the linked list of interfaces
+****************************************************************************/
+static void add_interface(struct in_addr ip, struct in_addr nmask)
+{
+ struct interface *iface;
+ if (iface_find(ip, False)) {
+ DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip)));
+ return;
+ }
+
+ if (ip_equal(nmask, allones_ip)) {
+ DEBUG(3,("not adding non-broadcast interface %s\n",inet_ntoa(ip)));
+ return;
+ }
+
+ iface = (struct interface *)malloc(sizeof(*iface));
+ if (!iface) return;
+
+ ZERO_STRUCTPN(iface);
+
+ iface->ip = ip;
+ iface->nmask = nmask;
+ iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr);
+
+ DLIST_ADD(local_interfaces, iface);
+
+ DEBUG(2,("added interface ip=%s ",inet_ntoa(iface->ip)));
+ DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast)));
+ DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask)));
+}
+
+
+
+/****************************************************************************
+interpret a single element from a interfaces= config line
+
+This handles the following different forms:
+
+1) wildcard interface name
+2) DNS name
+3) IP/masklen
+4) ip/mask
+5) bcast/mask
+****************************************************************************/
+static void interpret_interface(char *token)
+{
+ struct in_addr ip, nmask;
+ char *p;
+ int i, added=0;
+
+ zero_ip(&ip);
+ zero_ip(&nmask);
+
+ /* first check if it is an interface name */
+ for (i=0;i<total_probed;i++) {
+ if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
+ add_interface(probed_ifaces[i].ip,
+ probed_ifaces[i].netmask);
+ added = 1;
+ }
+ }
+ if (added) return;
+
+ /* maybe it is a DNS name */
+ p = strchr_m(token,'/');
+ if (!p) {
+ ip = *interpret_addr2(token);
+ for (i=0;i<total_probed;i++) {
+ if (ip.s_addr == probed_ifaces[i].ip.s_addr &&
+ !ip_equal(allones_ip, probed_ifaces[i].netmask)) {
+ add_interface(probed_ifaces[i].ip,
+ probed_ifaces[i].netmask);
+ return;
+ }
+ }
+ DEBUG(2,("can't determine netmask for %s\n", token));
+ return;
+ }
+
+ /* parse it into an IP address/netmasklength pair */
+ *p++ = 0;
+
+ ip = *interpret_addr2(token);
+
+ if (strlen(p) > 2) {
+ nmask = *interpret_addr2(p);
+ } else {
+ nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
+ }
+
+ /* maybe the first component was a broadcast address */
+ if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) ||
+ ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) {
+ for (i=0;i<total_probed;i++) {
+ if (same_net(ip, probed_ifaces[i].ip, nmask)) {
+ add_interface(probed_ifaces[i].ip, nmask);
+ return;
+ }
+ }
+ DEBUG(2,("Can't determine ip for broadcast address %s\n", token));
+ return;
+ }
+
+ add_interface(ip, nmask);
+}
+
+
+/****************************************************************************
+load the list of network interfaces
+****************************************************************************/
+void load_interfaces(void)
+{
+ char **ptr;
+ int i;
+ struct iface_struct ifaces[MAX_INTERFACES];
+
+ ptr = lp_interfaces();
+
+ allones_ip = *interpret_addr2("255.255.255.255");
+ loopback_ip = *interpret_addr2("127.0.0.1");
+
+ SAFE_FREE(probed_ifaces);
+
+ /* dump the current interfaces if any */
+ while (local_interfaces) {
+ struct interface *iface = local_interfaces;
+ DLIST_REMOVE(local_interfaces, local_interfaces);
+ ZERO_STRUCTPN(iface);
+ SAFE_FREE(iface);
+ }
+
+ /* probe the kernel for interfaces */
+ total_probed = get_interfaces(ifaces, MAX_INTERFACES);
+
+ if (total_probed > 0) {
+ probed_ifaces = memdup(ifaces, sizeof(ifaces[0])*total_probed);
+ }
+
+ /* if we don't have a interfaces line then use all broadcast capable
+ interfaces except loopback */
+ if (!ptr || !*ptr || !**ptr) {
+ if (total_probed <= 0) {
+ DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
+ exit(1);
+ }
+ for (i=0;i<total_probed;i++) {
+ if (probed_ifaces[i].netmask.s_addr != allones_ip.s_addr &&
+ probed_ifaces[i].ip.s_addr != loopback_ip.s_addr) {
+ add_interface(probed_ifaces[i].ip,
+ probed_ifaces[i].netmask);
+ }
+ }
+ return;
+ }
+
+ if (ptr) {
+ while (*ptr) {
+ interpret_interface(*ptr);
+ ptr++;
+ }
+ }
+
+ if (!local_interfaces) {
+ DEBUG(0,("WARNING: no network interfaces found\n"));
+ }
+}
+
+
+/****************************************************************************
+return True if the list of probed interfaces has changed
+****************************************************************************/
+BOOL interfaces_changed(void)
+{
+ int n;
+ struct iface_struct ifaces[MAX_INTERFACES];
+
+ n = get_interfaces(ifaces, MAX_INTERFACES);
+
+ if ((n > 0 )&& (n != total_probed ||
+ memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
+ return True;
+ }
+
+ return False;
+}
+
+
+/****************************************************************************
+ check if an IP is one of mine
+ **************************************************************************/
+BOOL ismyip(struct in_addr ip)
+{
+ struct interface *i;
+ for (i=local_interfaces;i;i=i->next)
+ if (ip_equal(i->ip,ip)) return True;
+ return False;
+}
+
+/****************************************************************************
+ check if a packet is from a local (known) net
+ **************************************************************************/
+BOOL is_local_net(struct in_addr from)
+{
+ struct interface *i;
+ for (i=local_interfaces;i;i=i->next) {
+ if((from.s_addr & i->nmask.s_addr) ==
+ (i->ip.s_addr & i->nmask.s_addr))
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************************
+ how many interfaces do we have
+ **************************************************************************/
+int iface_count(void)
+{
+ int ret = 0;
+ struct interface *i;
+
+ for (i=local_interfaces;i;i=i->next)
+ ret++;
+ return ret;
+}
+
+/****************************************************************************
+ True if we have two or more interfaces.
+ **************************************************************************/
+BOOL we_are_multihomed(void)
+{
+ static int multi = -1;
+
+ if(multi == -1)
+ multi = (iface_count() > 1 ? True : False);
+
+ return multi;
+}
+
+/****************************************************************************
+ return the Nth interface
+ **************************************************************************/
+struct interface *get_interface(int n)
+{
+ struct interface *i;
+
+ for (i=local_interfaces;i && n;i=i->next)
+ n--;
+
+ if (i) return i;
+ return NULL;
+}
+
+/****************************************************************************
+ return IP of the Nth interface
+ **************************************************************************/
+struct in_addr *iface_n_ip(int n)
+{
+ struct interface *i;
+
+ for (i=local_interfaces;i && n;i=i->next)
+ n--;
+
+ if (i) return &i->ip;
+ return NULL;
+}
+
+/****************************************************************************
+ return bcast of the Nth interface
+ **************************************************************************/
+struct in_addr *iface_n_bcast(int n)
+{
+ struct interface *i;
+
+ for (i=local_interfaces;i && n;i=i->next)
+ n--;
+
+ if (i) return &i->bcast;
+ return NULL;
+}
+
+
+/****************************************************************************
+this function provides a simple hash of the configured interfaces. It is
+used to detect a change in interfaces to tell us whether to discard
+the current wins.dat file.
+Note that the result is independent of the order of the interfaces
+ **************************************************************************/
+unsigned iface_hash(void)
+{
+ unsigned ret = 0;
+ struct interface *i;
+
+ for (i=local_interfaces;i;i=i->next) {
+ unsigned x1 = (unsigned)str_checksum(inet_ntoa(i->ip));
+ unsigned x2 = (unsigned)str_checksum(inet_ntoa(i->nmask));
+ ret ^= (x1 ^ x2);
+ }
+
+ return ret;
+}
+
+
+/* these 3 functions return the ip/bcast/nmask for the interface
+ most appropriate for the given ip address. If they can't find
+ an appropriate interface they return the requested field of the
+ first known interface. */
+
+struct in_addr *iface_bcast(struct in_addr ip)
+{
+ struct interface *i = iface_find(ip, True);
+ return(i ? &i->bcast : &local_interfaces->bcast);
+}
+
+struct in_addr *iface_ip(struct in_addr ip)
+{
+ struct interface *i = iface_find(ip, True);
+ return(i ? &i->ip : &local_interfaces->ip);
+}
diff --git a/source3/lib/interfaces.c b/source3/lib/interfaces.c
new file mode 100644
index 0000000000..7b8ef0d0c1
--- /dev/null
+++ b/source3/lib/interfaces.c
@@ -0,0 +1,401 @@
+/*
+ Unix SMB/CIFS implementation.
+ return a list of network interfaces
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+/* working out the interfaces for a OS is an incredibly non-portable
+ thing. We have several possible implementations below, and autoconf
+ tries each of them to see what works
+
+ Note that this file does _not_ include includes.h. That is so this code
+ can be called directly from the autoconf tests. That also means
+ this code cannot use any of the normal Samba debug stuff or defines.
+ This is standalone code.
+
+*/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <net/if.h>
+
+#ifndef SIOCGIFCONF
+#include <sys/sockio.h>
+#endif
+
+#ifdef AUTOCONF_TEST
+struct iface_struct {
+ char name[16];
+ struct in_addr ip;
+ struct in_addr netmask;
+};
+#else
+#include "config.h"
+#include "interfaces.h"
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#ifdef __COMPAR_FN_T
+#define QSORT_CAST (__compar_fn_t)
+#endif
+
+#ifndef QSORT_CAST
+#define QSORT_CAST (int (*)(const void *, const void *))
+#endif
+
+#if HAVE_IFACE_IFCONF
+
+/* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
+ V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
+
+ It probably also works on any BSD style system. */
+
+/****************************************************************************
+ get the netmask address for a local interface
+****************************************************************************/
+static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
+{
+ struct ifconf ifc;
+ char buff[8192];
+ int fd, i, n;
+ struct ifreq *ifr=NULL;
+ int total = 0;
+ struct in_addr ipaddr;
+ struct in_addr nmask;
+ char *iname;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ return -1;
+ }
+
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+
+ if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
+ close(fd);
+ return -1;
+ }
+
+ ifr = ifc.ifc_req;
+
+ n = ifc.ifc_len / sizeof(struct ifreq);
+
+ /* Loop through interfaces, looking for given IP address */
+ for (i=n-1;i>=0 && total < max_interfaces;i--) {
+ if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
+ continue;
+ }
+
+ iname = ifr[i].ifr_name;
+ ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr;
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
+ continue;
+ }
+
+ if (!(ifr[i].ifr_flags & IFF_UP)) {
+ continue;
+ }
+
+ if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
+ continue;
+ }
+
+ nmask = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr;
+
+ strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
+ ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
+ ifaces[total].ip = ipaddr;
+ ifaces[total].netmask = nmask;
+ total++;
+ }
+
+ close(fd);
+
+ return total;
+}
+
+#elif HAVE_IFACE_IFREQ
+
+#ifndef I_STR
+#include <sys/stropts.h>
+#endif
+
+/****************************************************************************
+this should cover most of the streams based systems
+Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
+****************************************************************************/
+static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
+{
+ struct ifreq ifreq;
+ struct strioctl strioctl;
+ char buff[8192];
+ int fd, i, n;
+ struct ifreq *ifr=NULL;
+ int total = 0;
+ struct in_addr ipaddr;
+ struct in_addr nmask;
+ char *iname;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ return -1;
+ }
+
+ strioctl.ic_cmd = SIOCGIFCONF;
+ strioctl.ic_dp = buff;
+ strioctl.ic_len = sizeof(buff);
+ if (ioctl(fd, I_STR, &strioctl) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ /* we can ignore the possible sizeof(int) here as the resulting
+ number of interface structures won't change */
+ n = strioctl.ic_len / sizeof(struct ifreq);
+
+ /* we will assume that the kernel returns the length as an int
+ at the start of the buffer if the offered size is a
+ multiple of the structure size plus an int */
+ if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
+ ifr = (struct ifreq *)(buff + sizeof(int));
+ } else {
+ ifr = (struct ifreq *)buff;
+ }
+
+ /* Loop through interfaces */
+
+ for (i = 0; i<n && total < max_interfaces; i++) {
+ ifreq = ifr[i];
+
+ strioctl.ic_cmd = SIOCGIFFLAGS;
+ strioctl.ic_dp = (char *)&ifreq;
+ strioctl.ic_len = sizeof(struct ifreq);
+ if (ioctl(fd, I_STR, &strioctl) != 0) {
+ continue;
+ }
+
+ if (!(ifreq.ifr_flags & IFF_UP)) {
+ continue;
+ }
+
+ strioctl.ic_cmd = SIOCGIFADDR;
+ strioctl.ic_dp = (char *)&ifreq;
+ strioctl.ic_len = sizeof(struct ifreq);
+ if (ioctl(fd, I_STR, &strioctl) != 0) {
+ continue;
+ }
+
+ ipaddr = (*(struct sockaddr_in *) &ifreq.ifr_addr).sin_addr;
+ iname = ifreq.ifr_name;
+
+ strioctl.ic_cmd = SIOCGIFNETMASK;
+ strioctl.ic_dp = (char *)&ifreq;
+ strioctl.ic_len = sizeof(struct ifreq);
+ if (ioctl(fd, I_STR, &strioctl) != 0) {
+ continue;
+ }
+
+ nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
+
+ strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
+ ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
+ ifaces[total].ip = ipaddr;
+ ifaces[total].netmask = nmask;
+
+ total++;
+ }
+
+ close(fd);
+
+ return total;
+}
+
+#elif HAVE_IFACE_AIX
+
+/****************************************************************************
+this one is for AIX (tested on 4.2)
+****************************************************************************/
+static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
+{
+ char buff[8192];
+ int fd, i;
+ struct ifconf ifc;
+ struct ifreq *ifr=NULL;
+ struct in_addr ipaddr;
+ struct in_addr nmask;
+ char *iname;
+ int total = 0;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ return -1;
+ }
+
+
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+
+ if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
+ close(fd);
+ return -1;
+ }
+
+ ifr = ifc.ifc_req;
+
+ /* Loop through interfaces */
+ i = ifc.ifc_len;
+
+ while (i > 0 && total < max_interfaces) {
+ unsigned inc;
+
+ inc = ifr->ifr_addr.sa_len;
+
+ if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
+ goto next;
+ }
+
+ ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
+ iname = ifr->ifr_name;
+
+ if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
+ goto next;
+ }
+
+ if (!(ifr->ifr_flags & IFF_UP)) {
+ goto next;
+ }
+
+ if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
+ goto next;
+ }
+
+ nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
+
+ strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
+ ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
+ ifaces[total].ip = ipaddr;
+ ifaces[total].netmask = nmask;
+
+ total++;
+
+ next:
+ /*
+ * Patch from Archie Cobbs (archie@whistle.com). The
+ * addresses in the SIOCGIFCONF interface list have a
+ * minimum size. Usually this doesn't matter, but if
+ * your machine has tunnel interfaces, etc. that have
+ * a zero length "link address", this does matter. */
+
+ if (inc < sizeof(ifr->ifr_addr))
+ inc = sizeof(ifr->ifr_addr);
+ inc += IFNAMSIZ;
+
+ ifr = (struct ifreq*) (((char*) ifr) + inc);
+ i -= inc;
+ }
+
+
+ close(fd);
+ return total;
+}
+
+#else /* a dummy version */
+static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
+{
+ return -1;
+}
+#endif
+
+
+static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
+{
+ int r;
+ r = strcmp(i1->name, i2->name);
+ if (r) return r;
+ r = ntohl(i1->ip.s_addr) - ntohl(i2->ip.s_addr);
+ if (r) return r;
+ r = ntohl(i1->netmask.s_addr) - ntohl(i2->netmask.s_addr);
+ return r;
+}
+
+/* this wrapper is used to remove duplicates from the interface list generated
+ above */
+int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
+{
+ int total, i, j;
+
+ total = _get_interfaces(ifaces, max_interfaces);
+ if (total <= 0) return total;
+
+ /* now we need to remove duplicates */
+ qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
+
+ for (i=1;i<total;) {
+ if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
+ for (j=i-1;j<total-1;j++) {
+ ifaces[j] = ifaces[j+1];
+ }
+ total--;
+ } else {
+ i++;
+ }
+ }
+
+ return total;
+}
+
+
+#ifdef AUTOCONF_TEST
+/* this is the autoconf driver to test get_interfaces() */
+
+#define MAX_INTERFACES 128
+
+ int main()
+{
+ struct iface_struct ifaces[MAX_INTERFACES];
+ int total = get_interfaces(ifaces, MAX_INTERFACES);
+ int i;
+
+ printf("got %d interfaces:\n", total);
+ if (total <= 0) exit(1);
+
+ for (i=0;i<total;i++) {
+ printf("%-10s ", ifaces[i].name);
+ printf("IP=%s ", inet_ntoa(ifaces[i].ip));
+ printf("NETMASK=%s\n", inet_ntoa(ifaces[i].netmask));
+ }
+ return 0;
+}
+#endif
diff --git a/source3/lib/kanji.c b/source3/lib/kanji.c
deleted file mode 100644
index 0af476eb15..0000000000
--- a/source3/lib/kanji.c
+++ /dev/null
@@ -1,895 +0,0 @@
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- Kanji Extensions
- Copyright (C) Andrew Tridgell 1992-1994
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Adding for Japanese language by <fujita@ainix.isac.co.jp> 1994.9.5
- and extend coding system to EUC/SJIS/JIS/HEX at 1994.10.11
- and add all jis codes sequence type at 1995.8.16
- Notes: Hexadecimal code by <ohki@gssm.otuka.tsukuba.ac.jp>
-*/
-#ifdef KANJI
-
-#define _KANJI_C_
-#include "includes.h"
-
-/* coding system keep in */
-int coding_system = SJIS_CODE;
-
-/* jis si/so sequence */
-char jis_kso = JIS_KSO;
-char jis_ksi = JIS_KSI;
-char hex_tag = HEXTAG;
-
-/*******************************************************************
- SHIFT JIS functions
-********************************************************************/
-/*******************************************************************
- search token from S1 separated any char of S2
- S1 contain SHIFT JIS chars.
-********************************************************************/
-char *
-sj_strtok (char *s1, const char *s2)
-{
- static char *s = NULL;
- char *q;
- if (!s1) {
- if (!s) {
- return NULL;
- }
- s1 = s;
- }
- for (q = s1; *s1; ) {
- if (is_shift_jis (*s1)) {
- s1 += 2;
- } else if (is_kana (*s1)) {
- s1++;
- } else {
- char *p = strchr (s2, *s1);
- if (p) {
- if (s1 != q) {
- s = s1 + 1;
- *s1 = '\0';
- return q;
- }
- q = s1 + 1;
- }
- s1++;
- }
- }
- s = NULL;
- if (*q) {
- return q;
- }
- return NULL;
-}
-
-/*******************************************************************
- search string S2 from S1
- S1 contain SHIFT JIS chars.
-********************************************************************/
-char *
-sj_strstr (const char *s1, const char *s2)
-{
- register int len = strlen ((char *) s2);
- if (!*s2)
- return (char *) s1;
- for (;*s1;) {
- if (*s1 == *s2) {
- if (strncmp (s1, s2, len) == 0)
- return (char *) s1;
- }
- if (is_shift_jis (*s1)) {
- s1 += 2;
- } else {
- s1++;
- }
- }
- return 0;
-}
-
-/*******************************************************************
- Search char C from beginning of S.
- S contain SHIFT JIS chars.
-********************************************************************/
-char *
-sj_strchr (const char *s, int c)
-{
- for (; *s; ) {
- if (*s == c)
- return (char *) s;
- if (is_shift_jis (*s)) {
- s += 2;
- } else {
- s++;
- }
- }
- return 0;
-}
-
-/*******************************************************************
- Search char C end of S.
- S contain SHIFT JIS chars.
-********************************************************************/
-char *
-sj_strrchr (const char *s, int c)
-{
- register char *q;
-
- for (q = 0; *s; ) {
- if (*s == c) {
- q = (char *) s;
- }
- if (is_shift_jis (*s)) {
- s += 2;
- } else {
- s++;
- }
- }
- return q;
-}
-
-/*******************************************************************
- Code conversion
-********************************************************************/
-/* convesion buffer */
-static char cvtbuf[1024];
-
-/*******************************************************************
- EUC <-> SJIS
-********************************************************************/
-static int
-euc2sjis (register int hi, register int lo)
-{
- if (hi & 1)
- return ((hi / 2 + (hi < 0xdf ? 0x31 : 0x71)) << 8) |
- (lo - (lo >= 0xe0 ? 0x60 : 0x61));
- else
- return ((hi / 2 + (hi < 0xdf ? 0x30 : 0x70)) << 8) | (lo - 2);
-}
-
-static int
-sjis2euc (register int hi, register int lo)
-{
- if (lo >= 0x9f)
- return ((hi * 2 - (hi >= 0xe0 ? 0xe0 : 0x60)) << 8) | (lo + 2);
- else
- return ((hi * 2 - (hi >= 0xe0 ? 0xe1 : 0x61)) << 8) |
- (lo + (lo >= 0x7f ? 0x60 : 0x61));
-}
-
-/*******************************************************************
- Convert FROM contain SHIFT JIS codes to EUC codes
- return converted buffer
-********************************************************************/
-static char *
-sj_to_euc (const char *from, BOOL overwrite)
-{
- register char *out;
- char *save;
-
- save = (char *) from;
- for (out = cvtbuf; *from;) {
- if (is_shift_jis (*from)) {
- int code = sjis2euc ((int) from[0] & 0xff, (int) from[1] & 0xff);
- *out++ = (code >> 8) & 0xff;
- *out++ = code;
- from += 2;
- } else if (is_kana (*from)) {
- *out++ = euc_kana;
- *out++ = *from++;
- } else {
- *out++ = *from++;
- }
- }
- *out = 0;
- if (overwrite) {
- strcpy((char *) save, (char *) cvtbuf);
- return (char *) save;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- Convert FROM contain EUC codes to SHIFT JIS codes
- return converted buffer
-********************************************************************/
-static char *
-euc_to_sj (const char *from, BOOL overwrite)
-{
- register char *out;
- char *save;
-
- save = (char *) from;
- for (out = cvtbuf; *from; ) {
- if (is_euc (*from)) {
- int code = euc2sjis ((int) from[0] & 0xff, (int) from[1] & 0xff);
- *out++ = (code >> 8) & 0xff;
- *out++ = code;
- from += 2;
- } else if (is_euc_kana (*from)) {
- *out++ = from[1];
- from += 2;
- } else {
- *out++ = *from++;
- }
- }
- *out = 0;
- if (overwrite) {
- strcpy(save, (char *) cvtbuf);
- return save;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- JIS7,JIS8,JUNET <-> SJIS
-********************************************************************/
-static int
-sjis2jis (register int hi, register int lo)
-{
- if (lo >= 0x9f)
- return ((hi * 2 - (hi >= 0xe0 ? 0x160 : 0xe0)) << 8) | (lo - 0x7e);
- else
- return ((hi * 2 - (hi >= 0xe0 ? 0x161 : 0xe1)) << 8) |
- (lo - (lo >= 0x7f ? 0x20 : 0x1f));
-}
-
-static int
-jis2sjis (register int hi, register int lo)
-{
- if (hi & 1)
- return ((hi / 2 + (hi < 0x5f ? 0x71 : 0xb1)) << 8) |
- (lo + (lo >= 0x60 ? 0x20 : 0x1f));
- else
- return ((hi / 2 + (hi < 0x5f ? 0x70 : 0xb0)) << 8) | (lo + 0x7e);
-}
-
-/*******************************************************************
- Convert FROM contain JIS codes to SHIFT JIS codes
- return converted buffer
-********************************************************************/
-static char *
-jis8_to_sj (const char *from, BOOL overwrite)
-{
- register char *out;
- register int shifted;
- char *save;
-
- shifted = _KJ_ROMAN;
- save = (char *) from;
- for (out = cvtbuf; *from;) {
- if (is_esc (*from)) {
- if (is_so1 (from[1]) && is_so2 (from[2])) {
- shifted = _KJ_KANJI;
- from += 3;
- } else if (is_si1 (from[1]) && is_si2 (from[2])) {
- shifted = _KJ_ROMAN;
- from += 3;
- } else { /* sequence error */
- goto normal;
- }
- } else {
- normal:
- switch (shifted) {
- default:
- case _KJ_ROMAN:
- *out++ = *from++;
- break;
- case _KJ_KANJI:
- {
- int code = jis2sjis ((int) from[0] & 0xff, (int) from[1] & 0xff);
- *out++ = (code >> 8) & 0xff;
- *out++ = code;
- from += 2;
- }
- break;
- }
- }
- }
- *out = 0;
- if (overwrite) {
- strcpy (save, (char *) cvtbuf);
- return save;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- Convert FROM contain SHIFT JIS codes to JIS codes
- return converted buffer
-********************************************************************/
-static char *
-sj_to_jis8 (const char *from, BOOL overwrite)
-{
- register char *out;
- register int shifted;
- char *save;
-
- shifted = _KJ_ROMAN;
- save = (char *) from;
- for (out = cvtbuf; *from; ) {
- if (is_shift_jis (*from)) {
- int code;
- switch (shifted) {
- case _KJ_ROMAN: /* to KANJI */
- *out++ = jis_esc;
- *out++ = jis_so1;
- *out++ = jis_kso;
- shifted = _KJ_KANJI;
- break;
- }
- code = sjis2jis ((int) from[0] & 0xff, (int) from[1] & 0xff);
- *out++ = (code >> 8) & 0xff;
- *out++ = code;
- from += 2;
- } else {
- switch (shifted) {
- case _KJ_KANJI: /* to ROMAN/KANA */
- *out++ = jis_esc;
- *out++ = jis_si1;
- *out++ = jis_ksi;
- shifted = _KJ_ROMAN;
- break;
- }
- *out++ = *from++;
- }
- }
- switch (shifted) {
- case _KJ_KANJI: /* to ROMAN/KANA */
- *out++ = jis_esc;
- *out++ = jis_si1;
- *out++ = jis_ksi;
- shifted = _KJ_ROMAN;
- break;
- }
- *out = 0;
- if (overwrite) {
- strcpy (save, (char *) cvtbuf);
- return save;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- Convert FROM contain 7 bits JIS codes to SHIFT JIS codes
- return converted buffer
-********************************************************************/
-static char *
-jis7_to_sj (const char *from, BOOL overwrite)
-{
- register char *out;
- register int shifted;
- char *save;
-
- shifted = _KJ_ROMAN;
- save = (char *) from;
- for (out = cvtbuf; *from;) {
- if (is_esc (*from)) {
- if (is_so1 (from[1]) && is_so2 (from[2])) {
- shifted = _KJ_KANJI;
- from += 3;
- } else if (is_si1 (from[1]) && is_si2 (from[2])) {
- shifted = _KJ_ROMAN;
- from += 3;
- } else { /* sequence error */
- goto normal;
- }
- } else if (is_so (*from)) {
- shifted = _KJ_KANA; /* to KANA */
- from++;
- } else if (is_si (*from)) {
- shifted = _KJ_ROMAN; /* to ROMAN */
- from++;
- } else {
- normal:
- switch (shifted) {
- default:
- case _KJ_ROMAN:
- *out++ = *from++;
- break;
- case _KJ_KANJI:
- {
- int code = jis2sjis ((int) from[0] & 0xff, (int) from[1] & 0xff);
- *out++ = (code >> 8) & 0xff;
- *out++ = code;
- from += 2;
- }
- break;
- case _KJ_KANA:
- *out++ = ((int) from[0]) + 0x80;
- break;
- }
- }
- }
- *out = 0;
- if (overwrite) {
- strcpy (save, (char *) cvtbuf);
- return save;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- Convert FROM contain SHIFT JIS codes to 7 bits JIS codes
- return converted buffer
-********************************************************************/
-static char *
-sj_to_jis7 (const char *from, BOOL overwrite)
-{
- register char *out;
- register int shifted;
- char *save;
-
- shifted = _KJ_ROMAN;
- save = (char *) from;
- for (out = cvtbuf; *from; ) {
- if (is_shift_jis (*from)) {
- int code;
- switch (shifted) {
- case _KJ_KANA:
- *out++ = jis_si; /* to ROMAN and through down */
- case _KJ_ROMAN: /* to KANJI */
- *out++ = jis_esc;
- *out++ = jis_so1;
- *out++ = jis_kso;
- shifted = _KJ_KANJI;
- break;
- }
- code = sjis2jis ((int) from[0] & 0xff, (int) from[1] & 0xff);
- *out++ = (code >> 8) & 0xff;
- *out++ = code;
- from += 2;
- } else if (is_kana (from[0])) {
- switch (shifted) {
- case _KJ_KANJI: /* to ROMAN */
- *out++ = jis_esc;
- *out++ = jis_si1;
- *out++ = jis_ksi;
- case _KJ_ROMAN: /* to KANA */
- *out++ = jis_so;
- shifted = _KJ_KANA;
- break;
- }
- *out++ = ((int) *from++) - 0x80;
- } else {
- switch (shifted) {
- case _KJ_KANA:
- *out++ = jis_si; /* to ROMAN */
- shifted = _KJ_ROMAN;
- break;
- case _KJ_KANJI: /* to ROMAN */
- *out++ = jis_esc;
- *out++ = jis_si1;
- *out++ = jis_ksi;
- shifted = _KJ_ROMAN;
- break;
- }
- *out++ = *from++;
- }
- }
- switch (shifted) {
- case _KJ_KANA:
- *out++ = jis_si; /* to ROMAN */
- break;
- case _KJ_KANJI: /* to ROMAN */
- *out++ = jis_esc;
- *out++ = jis_si1;
- *out++ = jis_ksi;
- break;
- }
- *out = 0;
- if (overwrite) {
- strcpy (save, (char *) cvtbuf);
- return save;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- Convert FROM contain 7 bits JIS(junet) codes to SHIFT JIS codes
- return converted buffer
-********************************************************************/
-static char *
-junet_to_sj (const char *from, BOOL overwrite)
-{
- register char *out;
- register int shifted;
- char *save;
-
- shifted = _KJ_ROMAN;
- save = (char *) from;
- for (out = cvtbuf; *from;) {
- if (is_esc (*from)) {
- if (is_so1 (from[1]) && is_so2 (from[2])) {
- shifted = _KJ_KANJI;
- from += 3;
- } else if (is_si1 (from[1]) && is_si2 (from[2])) {
- shifted = _KJ_ROMAN;
- from += 3;
- } else if (is_juk1(from[1]) && is_juk2 (from[2])) {
- shifted = _KJ_KANA;
- from += 3;
- } else { /* sequence error */
- goto normal;
- }
- } else {
- normal:
- switch (shifted) {
- default:
- case _KJ_ROMAN:
- *out++ = *from++;
- break;
- case _KJ_KANJI:
- {
- int code = jis2sjis ((int) from[0] & 0xff, (int) from[1] & 0xff);
- *out++ = (code >> 8) & 0xff;
- *out++ = code;
- from += 2;
- }
- break;
- case _KJ_KANA:
- *out++ = ((int) from[0]) + 0x80;
- break;
- }
- }
- }
- *out = 0;
- if (overwrite) {
- strcpy (save, (char *) cvtbuf);
- return save;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- Convert FROM contain SHIFT JIS codes to 7 bits JIS(junet) codes
- return converted buffer
-********************************************************************/
-static char *
-sj_to_junet (const char *from, BOOL overwrite)
-{
- register char *out;
- register int shifted;
- char *save;
-
- shifted = _KJ_ROMAN;
- save = (char *) from;
- for (out = cvtbuf; *from; ) {
- if (is_shift_jis (*from)) {
- int code;
- switch (shifted) {
- case _KJ_KANA:
- case _KJ_ROMAN: /* to KANJI */
- *out++ = jis_esc;
- *out++ = jis_so1;
- *out++ = jis_so2;
- shifted = _KJ_KANJI;
- break;
- }
- code = sjis2jis ((int) from[0] & 0xff, (int) from[1] & 0xff);
- *out++ = (code >> 8) & 0xff;
- *out++ = code;
- from += 2;
- } else if (is_kana (from[0])) {
- switch (shifted) {
- case _KJ_KANJI: /* to ROMAN */
- case _KJ_ROMAN: /* to KANA */
- *out++ = jis_esc;
- *out++ = junet_kana1;
- *out++ = junet_kana2;
- shifted = _KJ_KANA;
- break;
- }
- *out++ = ((int) *from++) - 0x80;
- } else {
- switch (shifted) {
- case _KJ_KANA:
- case _KJ_KANJI: /* to ROMAN */
- *out++ = jis_esc;
- *out++ = jis_si1;
- *out++ = jis_si2;
- shifted = _KJ_ROMAN;
- break;
- }
- *out++ = *from++;
- }
- }
- switch (shifted) {
- case _KJ_KANA:
- case _KJ_KANJI: /* to ROMAN */
- *out++ = jis_esc;
- *out++ = jis_si1;
- *out++ = jis_si2;
- break;
- }
- *out = 0;
- if (overwrite) {
- strcpy (save, (char *) cvtbuf);
- return save;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- HEX <-> SJIS
-********************************************************************/
-/* ":xx" -> a byte */
-static char *
-hex_to_sj (const char *from, BOOL overwrite)
-{
- char *sp, *dp;
-
- sp = (char *) from;
- dp = cvtbuf;
- while (*sp) {
- if (*sp == hex_tag && isxdigit (sp[1]) && isxdigit (sp[2])) {
- *dp++ = (hex2bin (sp[1])<<4) | (hex2bin (sp[2]));
- sp += 3;
- } else
- *dp++ = *sp++;
- }
- *dp = '\0';
- if (overwrite) {
- strcpy ((char *) from, (char *) cvtbuf);
- return (char *) from;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- kanji/kana -> ":xx"
-********************************************************************/
-static char *
-sj_to_hex (const char *from, BOOL overwrite)
-{
- unsigned char *sp, *dp;
-
- sp = (unsigned char*) from;
- dp = (unsigned char*) cvtbuf;
- while (*sp) {
- if (is_kana(*sp)) {
- *dp++ = hex_tag;
- *dp++ = bin2hex (((*sp)>>4)&0x0f);
- *dp++ = bin2hex ((*sp)&0x0f);
- sp++;
- } else if (is_shift_jis (*sp) && is_shift_jis2 (sp[1])) {
- *dp++ = hex_tag;
- *dp++ = bin2hex (((*sp)>>4)&0x0f);
- *dp++ = bin2hex ((*sp)&0x0f);
- sp++;
- *dp++ = hex_tag;
- *dp++ = bin2hex (((*sp)>>4)&0x0f);
- *dp++ = bin2hex ((*sp)&0x0f);
- sp++;
- } else
- *dp++ = *sp++;
- }
- *dp = '\0';
- if (overwrite) {
- strcpy ((char *) from, (char *) cvtbuf);
- return (char *) from;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- kanji/kana -> ":xx"
-********************************************************************/
-static char *
-sj_to_cap (const char *from, BOOL overwrite)
-{
- unsigned char *sp, *dp;
-
- sp = (unsigned char*) from;
- dp = (unsigned char*) cvtbuf;
- while (*sp) {
- if (*sp >= 0x80) {
- *dp++ = hex_tag;
- *dp++ = bin2hex (((*sp)>>4)&0x0f);
- *dp++ = bin2hex ((*sp)&0x0f);
- sp++;
- } else {
- *dp++ = *sp++;
- }
- }
- *dp = '\0';
- if (overwrite) {
- strcpy ((char *) from, (char *) cvtbuf);
- return (char *) from;
- } else {
- return cvtbuf;
- }
-}
-
-/*******************************************************************
- sj to sj
-********************************************************************/
-static char *
-sj_to_sj (const char *from, BOOL overwrite)
-{
- if (!overwrite) {
- strcpy (cvtbuf, (char *) from);
- return cvtbuf;
- } else {
- return (char *) from;
- }
-}
-
-/************************************************************************
- conversion:
- _dos_to_unix _unix_to_dos
-************************************************************************/
-
-char* (*_dos_to_unix) (const char *str, BOOL overwrite) = sj_to_sj;
-char* (*_unix_to_dos) (const char *str, BOOL overwrite) = sj_to_sj;
-
-static int
-setup_string_function (int codes)
-{
- switch (codes) {
- default:
- case SJIS_CODE:
- _dos_to_unix = sj_to_sj;
- _unix_to_dos = sj_to_sj;
-
- break;
-
- case EUC_CODE:
- _dos_to_unix = sj_to_euc;
- _unix_to_dos = euc_to_sj;
- break;
-
- case JIS7_CODE:
- _dos_to_unix = sj_to_jis7;
- _unix_to_dos = jis7_to_sj;
- break;
-
- case JIS8_CODE:
- _dos_to_unix = sj_to_jis8;
- _unix_to_dos = jis8_to_sj;
- break;
-
- case JUNET_CODE:
- _dos_to_unix = sj_to_junet;
- _unix_to_dos = junet_to_sj;
- break;
-
- case HEX_CODE:
- _dos_to_unix = sj_to_hex;
- _unix_to_dos = hex_to_sj;
- break;
-
- case CAP_CODE:
- _dos_to_unix = sj_to_cap;
- _unix_to_dos = hex_to_sj;
- break;
- }
- return codes;
-}
-
-/*
- * Interpret coding system.
- */
-int
-interpret_coding_system (char *str, int def)
-{
- int codes = def;
-
- if (strequal (str, "sjis")) {
- codes = SJIS_CODE;
- } else if (strequal (str, "euc")) {
- codes = EUC_CODE;
- } else if (strequal (str, "cap")) {
- codes = CAP_CODE;
- hex_tag = HEXTAG;
- } else if (strequal (str, "hex")) {
- codes = HEX_CODE;
- hex_tag = HEXTAG;
- } else if (strncasecmp (str, "hex", 3)) {
- codes = HEX_CODE;
- hex_tag = (str[3] ? str[3] : HEXTAG);
- } else if (strequal (str, "j8bb")) {
- codes = JIS8_CODE;
- jis_kso = 'B';
- jis_ksi = 'B';
- } else if (strequal (str, "j8bj") || strequal (str, "jis8")) {
- codes = JIS8_CODE;
- jis_kso = 'B';
- jis_ksi = 'J';
- } else if (strequal (str, "j8bh")) {
- codes = JIS8_CODE;
- jis_kso = 'B';
- jis_ksi = 'H';
- } else if (strequal (str, "j8@b")) {
- codes = JIS8_CODE;
- jis_kso = '@';
- jis_ksi = 'B';
- } else if (strequal (str, "j8@j")) {
- codes = JIS8_CODE;
- jis_kso = '@';
- jis_ksi = 'J';
- } else if (strequal (str, "j8@h")) {
- codes = JIS8_CODE;
- jis_kso = '@';
- jis_ksi = 'H';
- } else if (strequal (str, "j7bb")) {
- codes = JIS7_CODE;
- jis_kso = 'B';
- jis_ksi = 'B';
- } else if (strequal (str, "j7bj") || strequal (str, "jis7")) {
- codes = JIS7_CODE;
- jis_kso = 'B';
- jis_ksi = 'J';
- } else if (strequal (str, "j7bh")) {
- codes = JIS7_CODE;
- jis_kso = 'B';
- jis_ksi = 'H';
- } else if (strequal (str, "j7@b")) {
- codes = JIS7_CODE;
- jis_kso = '@';
- jis_ksi = 'B';
- } else if (strequal (str, "j7@j")) {
- codes = JIS7_CODE;
- jis_kso = '@';
- jis_ksi = 'J';
- } else if (strequal (str, "j7@h")) {
- codes = JIS7_CODE;
- jis_kso = '@';
- jis_ksi = 'H';
- } else if (strequal (str, "jubb")) {
- codes = JUNET_CODE;
- jis_kso = 'B';
- jis_ksi = 'B';
- } else if (strequal (str, "jubj") || strequal (str, "junet")) {
- codes = JUNET_CODE;
- jis_kso = 'B';
- jis_ksi = 'J';
- } else if (strequal (str, "jubh")) {
- codes = JUNET_CODE;
- jis_kso = 'B';
- jis_ksi = 'H';
- } else if (strequal (str, "ju@b")) {
- codes = JUNET_CODE;
- jis_kso = '@';
- jis_ksi = 'B';
- } else if (strequal (str, "ju@j")) {
- codes = JUNET_CODE;
- jis_kso = '@';
- jis_ksi = 'J';
- } else if (strequal (str, "ju@h")) {
- codes = JUNET_CODE;
- jis_kso = '@';
- jis_ksi = 'H';
- }
- return setup_string_function (codes);
-}
-#else
-int kanji_dummy_procedure(void)
-{return 0;}
-#endif /* KANJI */
diff --git a/source3/lib/md4.c b/source3/lib/md4.c
index 485e231a78..6803b7e883 100644
--- a/source3/lib/md4.c
+++ b/source3/lib/md4.c
@@ -1,299 +1,169 @@
-#ifdef SMB_PASSWD
-/*
- This code is from rfc1186.
+/*
+ Unix SMB/CIFS implementation.
+ a implementation of MD4 designed for use in the SMB authentication protocol
+ Copyright (C) Andrew Tridgell 1997-1998.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
- /*
- ** ********************************************************************
- ** md4.c -- Implementation of MD4 Message Digest Algorithm **
- ** Updated: 2/16/90 by Ronald L. Rivest **
- ** (C) 1990 RSA Data Security, Inc. **
- ** ********************************************************************
- */
+#include "includes.h"
- /*
- ** To use MD4:
- ** -- Include md4.h in your program
- ** -- Declare an MDstruct MD to hold the state of the digest
- ** computation.
- ** -- Initialize MD using MDbegin(&MD)
- ** -- For each full block (64 bytes) X you wish to process, call
- ** MDupdate(&MD,X,512)
- ** (512 is the number of bits in a full block.)
- ** -- For the last block (less than 64 bytes) you wish to process,
- ** MDupdate(&MD,X,n)
- ** where n is the number of bits in the partial block. A partial
- ** block terminates the computation, so every MD computation
- ** should terminate by processing a partial block, even if it
- ** has n = 0.
- ** -- The message digest is available in MD.buffer[0] ...
- ** MD.buffer[3]. (Least-significant byte of each word
- ** should be output first.)
- ** -- You can print out the digest using MDprint(&MD)
- */
+/* NOTE: This code makes no attempt to be fast!
- /* Implementation notes:
- ** This implementation assumes that ints are 32-bit quantities.
- ** If the machine stores the least-significant byte of an int in the
- ** least-addressed byte (e.g., VAX and 8086), then LOWBYTEFIRST
- ** should be set to TRUE. Otherwise (e.g., SUNS), LOWBYTEFIRST
- ** should be set to FALSE. Note that on machines with LOWBYTEFIRST
- ** FALSE the routine MDupdate modifies has a side-effect on its input
- ** array (the order of bytes in each word are reversed). If this is
- ** undesired a call to MDreverse(X) can reverse the bytes of X back
- ** into order after each call to MDupdate.
- */
-
-#define TRUE 1
-#define FALSE 0
-
- /* Compile-time includes
- */
-
-#include <stdio.h>
-#include "md4.h"
-
-#define uchar unsigned char
-#define int16 unsigned short
-#define uint32 unsigned int
-
-#include "byteorder.h"
-
- /* Compile-time declarations of MD4 "magic constants".
- */
-#define I0 0x67452301 /* Initial values for MD buffer */
-#define I1 0xefcdab89
-#define I2 0x98badcfe
-#define I3 0x10325476
-#define C2 013240474631 /* round 2 constant = sqrt(2) in octal */
-#define C3 015666365641 /* round 3 constant = sqrt(3) in octal */
- /* C2 and C3 are from Knuth, The Art of Programming, Volume 2
- ** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley.
- ** Table 2, page 660.
- */
-
-#define fs1 3 /* round 1 shift amounts */
-#define fs2 7
-#define fs3 11
-#define fs4 19
-#define gs1 3 /* round 2 shift amounts */
-#define gs2 5
-#define gs3 9
-#define gs4 13
-#define hs1 3 /* round 3 shift amounts */
-#define hs2 9
-#define hs3 11
-#define hs4 15
-
- /* Compile-time macro declarations for MD4.
- ** Note: The "rot" operator uses the variable "tmp".
- ** It assumes tmp is declared as unsigned int, so that the >>
- ** operator will shift in zeros rather than extending the sign bit.
- */
-#define f(X,Y,Z) ((X&Y) | ((~X)&Z))
-#define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z))
-#define h(X,Y,Z) (X^Y^Z)
-#define rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S)))
-#define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s)
-#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s)
-#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s)
+ It assumes that a int is at least 32 bits long
+*/
- /* MDprint(MDp)
- ** Print message digest buffer MDp as 32 hexadecimal digits.
- ** Order is from low-order byte of buffer[0] to high-order byte of
- ** buffer[3].
- ** Each byte is printed with high-order hexadecimal digit first.
- ** This is a user-callable routine.
- */
- void
- MDprint(MDp)
- MDptr MDp;
- { int i,j;
- for (i=0;i<4;i++)
- for (j=0;j<32;j=j+8)
- printf("%02x",(MDp->buffer[i]>>j) & 0xFF);
- }
+static uint32 A, B, C, D;
+
+static uint32 F(uint32 X, uint32 Y, uint32 Z)
+{
+ return (X&Y) | ((~X)&Z);
+}
+
+static uint32 G(uint32 X, uint32 Y, uint32 Z)
+{
+ return (X&Y) | (X&Z) | (Y&Z);
+}
+
+static uint32 H(uint32 X, uint32 Y, uint32 Z)
+{
+ return X^Y^Z;
+}
+
+static uint32 lshift(uint32 x, int s)
+{
+ x &= 0xFFFFFFFF;
+ return ((x<<s)&0xFFFFFFFF) | (x>>(32-s));
+}
+
+#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
+#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + (uint32)0x5A827999,s)
+#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + (uint32)0x6ED9EBA1,s)
+
+/* this applies md4 to 64 byte chunks */
+static void mdfour64(uint32 *M)
+{
+ int j;
+ uint32 AA, BB, CC, DD;
+ uint32 X[16];
+
+ for (j=0;j<16;j++)
+ X[j] = M[j];
+
+ AA = A; BB = B; CC = C; DD = D;
+
+ ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
+ ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
+ ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
+ ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
+ ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
+ ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
+ ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
+ ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
+
+ ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
+ ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
+ ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
+ ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
+ ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
+ ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
+ ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
+ ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
+
+ ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
+ ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
+ ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
+ ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
+ ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
+ ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
+ ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
+ ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
+
+ A += AA; B += BB; C += CC; D += DD;
+
+ A &= 0xFFFFFFFF; B &= 0xFFFFFFFF;
+ C &= 0xFFFFFFFF; D &= 0xFFFFFFFF;
+
+ for (j=0;j<16;j++)
+ X[j] = 0;
+}
+
+static void copy64(uint32 *M, const unsigned char *in)
+{
+ int i;
+
+ for (i=0;i<16;i++)
+ M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
+ (in[i*4+1]<<8) | (in[i*4+0]<<0);
+}
+
+static void copy4(unsigned char *out, uint32 x)
+{
+ out[0] = x&0xFF;
+ out[1] = (x>>8)&0xFF;
+ out[2] = (x>>16)&0xFF;
+ out[3] = (x>>24)&0xFF;
+}
+
+/* produce a md4 message digest from data of length n bytes */
+void mdfour(unsigned char *out, const unsigned char *in, int n)
+{
+ unsigned char buf[128];
+ uint32 M[16];
+ uint32 b = n * 8;
+ int i;
+
+ A = 0x67452301;
+ B = 0xefcdab89;
+ C = 0x98badcfe;
+ D = 0x10325476;
+
+ while (n > 64) {
+ copy64(M, in);
+ mdfour64(M);
+ in += 64;
+ n -= 64;
+ }
- /* MDbegin(MDp)
- ** Initialize message digest buffer MDp.
- ** This is a user-callable routine.
- */
- void
- MDbegin(MDp)
- MDptr MDp;
- { int i;
- MDp->buffer[0] = I0;
- MDp->buffer[1] = I1;
- MDp->buffer[2] = I2;
- MDp->buffer[3] = I3;
- for (i=0;i<8;i++) MDp->count[i] = 0;
- MDp->done = 0;
- }
+ for (i=0;i<128;i++)
+ buf[i] = 0;
+ memcpy(buf, in, n);
+ buf[n] = 0x80;
+
+ if (n <= 55) {
+ copy4(buf+56, b);
+ copy64(M, buf);
+ mdfour64(M);
+ } else {
+ copy4(buf+120, b);
+ copy64(M, buf);
+ mdfour64(M);
+ copy64(M, buf+64);
+ mdfour64(M);
+ }
- /* MDreverse(X)
- ** Reverse the byte-ordering of every int in X.
- ** Assumes X is an array of 16 ints.
- ** The macro revx reverses the byte-ordering of the next word of X.
- */
- void MDreverse(X)
- unsigned int *X;
- { register unsigned int t;
- register unsigned int i;
+ for (i=0;i<128;i++)
+ buf[i] = 0;
+ copy64(M, buf);
- for(i = 0; i < 16; i++) {
- t = X[i];
- SIVAL(X,i*4,t);
- }
- }
+ copy4(out, A);
+ copy4(out+4, B);
+ copy4(out+8, C);
+ copy4(out+12, D);
- /* MDblock(MDp,X)
- ** Update message digest buffer MDp->buffer using 16-word data block X.
- ** Assumes all 16 words of X are full of data.
- ** Does not update MDp->count.
- ** This routine is not user-callable.
- */
- static void
- MDblock(MDp,X)
- MDptr MDp;
- unsigned int *X;
- {
- register unsigned int tmp, A, B, C, D;
- MDreverse(X);
- A = MDp->buffer[0];
- B = MDp->buffer[1];
- C = MDp->buffer[2];
- D = MDp->buffer[3];
- /* Update the message digest buffer */
- ff(A , B , C , D , 0 , fs1); /* Round 1 */
- ff(D , A , B , C , 1 , fs2);
- ff(C , D , A , B , 2 , fs3);
- ff(B , C , D , A , 3 , fs4);
- ff(A , B , C , D , 4 , fs1);
- ff(D , A , B , C , 5 , fs2);
- ff(C , D , A , B , 6 , fs3);
- ff(B , C , D , A , 7 , fs4);
- ff(A , B , C , D , 8 , fs1);
- ff(D , A , B , C , 9 , fs2);
- ff(C , D , A , B , 10 , fs3);
- ff(B , C , D , A , 11 , fs4);
- ff(A , B , C , D , 12 , fs1);
- ff(D , A , B , C , 13 , fs2);
- ff(C , D , A , B , 14 , fs3);
- ff(B , C , D , A , 15 , fs4);
- gg(A , B , C , D , 0 , gs1); /* Round 2 */
- gg(D , A , B , C , 4 , gs2);
- gg(C , D , A , B , 8 , gs3);
- gg(B , C , D , A , 12 , gs4);
- gg(A , B , C , D , 1 , gs1);
- gg(D , A , B , C , 5 , gs2);
- gg(C , D , A , B , 9 , gs3);
- gg(B , C , D , A , 13 , gs4);
- gg(A , B , C , D , 2 , gs1);
- gg(D , A , B , C , 6 , gs2);
- gg(C , D , A , B , 10 , gs3);
- gg(B , C , D , A , 14 , gs4);
- gg(A , B , C , D , 3 , gs1);
- gg(D , A , B , C , 7 , gs2);
- gg(C , D , A , B , 11 , gs3);
- gg(B , C , D , A , 15 , gs4);
- hh(A , B , C , D , 0 , hs1); /* Round 3 */
- hh(D , A , B , C , 8 , hs2);
- hh(C , D , A , B , 4 , hs3);
- hh(B , C , D , A , 12 , hs4);
- hh(A , B , C , D , 2 , hs1);
- hh(D , A , B , C , 10 , hs2);
- hh(C , D , A , B , 6 , hs3);
- hh(B , C , D , A , 14 , hs4);
- hh(A , B , C , D , 1 , hs1);
- hh(D , A , B , C , 9 , hs2);
- hh(C , D , A , B , 5 , hs3);
- hh(B , C , D , A , 13 , hs4);
- hh(A , B , C , D , 3 , hs1);
- hh(D , A , B , C , 11 , hs2);
- hh(C , D , A , B , 7 , hs3);
- hh(B , C , D , A , 15 , hs4);
- MDp->buffer[0] += A;
- MDp->buffer[1] += B;
- MDp->buffer[2] += C;
- MDp->buffer[3] += D;
- }
+ A = B = C = D = 0;
+}
- /* MDupdate(MDp,X,count)
- ** Input: MDp -- an MDptr
- ** X -- a pointer to an array of unsigned characters.
- ** count -- the number of bits of X to use.
- ** (if not a multiple of 8, uses high bits of last byte.)
- ** Update MDp using the number of bits of X given by count.
- ** This is the basic input routine for an MD4 user.
- ** The routine completes the MD computation when count < 512, so
- ** every MD computation should end with one call to MDupdate with a
- ** count less than 512. A call with count 0 will be ignored if the
- ** MD has already been terminated (done != 0), so an extra call with
- ** count 0 can be given as a "courtesy close" to force termination
- ** if desired.
- */
- void
- MDupdate(MDp,X,count)
- MDptr MDp;
- unsigned char *X;
- unsigned int count;
- { unsigned int i, tmp, bit, byte, mask;
- unsigned char XX[64];
- unsigned char *p;
- /* return with no error if this is a courtesy close with count
- ** zero and MDp->done is true.
- */
- if (count == 0 && MDp->done) return;
- /* check to see if MD is already done and report error */
- if (MDp->done)
- { printf("\nError: MDupdate MD already done."); return; }
- /* Add count to MDp->count */
- tmp = count;
- p = MDp->count;
- while (tmp)
- { tmp += *p;
- *p++ = tmp;
- tmp = tmp >> 8;
- }
- /* Process data */
- if (count == 512)
- { /* Full block of data to handle */
- MDblock(MDp,(unsigned int *)X);
- }
- else if (count > 512) /* Check for count too large */
- { printf("\nError: MDupdate called with illegal count value %d."
- ,count);
- return;
- }
- else /* partial block -- must be last block so finish up */
- { /* Find out how many bytes and residual bits there are */
- byte = count >> 3;
- bit = count & 7;
- /* Copy X into XX since we need to modify it */
- for (i=0;i<=byte;i++) XX[i] = X[i];
- for (i=byte+1;i<64;i++) XX[i] = 0;
- /* Add padding '1' bit and low-order zeros in last byte */
- mask = 1 << (7 - bit);
- XX[byte] = (XX[byte] | mask) & ~( mask - 1);
- /* If room for bit count, finish up with this block */
- if (byte <= 55)
- { for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
- MDblock(MDp,(unsigned int *)XX);
- }
- else /* need to do two blocks to finish up */
- { MDblock(MDp,(unsigned int *)XX);
- for (i=0;i<56;i++) XX[i] = 0;
- for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
- MDblock(MDp,(unsigned int *)XX);
- }
- /* Set flag saying we're done with MD computation */
- MDp->done = 1;
- }
- }
- /*
- ** End of md4.c
- */
-#else
-void md4_dummy() {;}
-#endif
diff --git a/source3/lib/md5.c b/source3/lib/md5.c
new file mode 100644
index 0000000000..627725bb25
--- /dev/null
+++ b/source3/lib/md5.c
@@ -0,0 +1,245 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/* This code slightly modified to fit into Samba by
+ abartlet@samba.org Jun 2001 */
+
+#include "includes.h"
+
+#include "md5.h"
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+ uint32 t;
+ do {
+ t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(uint32 *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+ register uint32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memmove(p, buf, len);
+ return;
+ }
+ memmove(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memmove(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memmove(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+ unsigned int count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32 *) ctx->in)[14] = ctx->bits[0];
+ ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+ memmove(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(uint32 buf[4], uint32 const in[16])
+{
+ register uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
diff --git a/source3/lib/messages.c b/source3/lib/messages.c
new file mode 100644
index 0000000000..8602c2f32d
--- /dev/null
+++ b/source3/lib/messages.c
@@ -0,0 +1,534 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba internal messaging functions
+ Copyright (C) Andrew Tridgell 2000
+ Copyright (C) 2001 by Martin Pool
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/**
+ @defgroups messages Internal messaging framework
+ @{
+ @file messages.c
+
+ This module is used for internal messaging between Samba daemons.
+
+ The idea is that if a part of Samba wants to do communication with
+ another Samba process then it will do a message_register() of a
+ dispatch function, and use message_send_pid() to send messages to
+ that process.
+
+ The dispatch function is given the pid of the sender, and it can
+ use that to reply by message_send_pid(). See ping_message() for a
+ simple example.
+
+ This system doesn't have any inherent size limitations but is not
+ very efficient for large messages or when messages are sent in very
+ quick succession.
+
+*/
+
+#include "includes.h"
+
+/* the locking database handle */
+static TDB_CONTEXT *tdb;
+static int received_signal;
+
+/* change the message version with any incompatible changes in the protocol */
+#define MESSAGE_VERSION 1
+
+struct message_rec {
+ int msg_version;
+ int msg_type;
+ pid_t dest;
+ pid_t src;
+ size_t len;
+};
+
+/* we have a linked list of dispatch handlers */
+static struct dispatch_fns {
+ struct dispatch_fns *next, *prev;
+ int msg_type;
+ void (*fn)(int msg_type, pid_t pid, void *buf, size_t len);
+} *dispatch_fns;
+
+/****************************************************************************
+ Notifications come in as signals.
+****************************************************************************/
+
+static void sig_usr1(void)
+{
+ received_signal = 1;
+ sys_select_signal();
+}
+
+/****************************************************************************
+ A useful function for testing the message system.
+****************************************************************************/
+
+void ping_message(int msg_type, pid_t src, void *buf, size_t len)
+{
+ char *msg = buf ? buf : "none";
+ DEBUG(1,("INFO: Received PING message from PID %u [%s]\n",(unsigned int)src, msg));
+ message_send_pid(src, MSG_PONG, buf, len, True);
+}
+
+/****************************************************************************
+ Return current debug level.
+****************************************************************************/
+
+void debuglevel_message(int msg_type, pid_t src, void *buf, size_t len)
+{
+ DEBUG(1,("INFO: Received REQ_DEBUGLEVEL message from PID %u\n",(unsigned int)src));
+ message_send_pid(src, MSG_DEBUGLEVEL, DEBUGLEVEL_CLASS, sizeof(DEBUGLEVEL_CLASS), True);
+}
+
+/****************************************************************************
+ Initialise the messaging functions.
+****************************************************************************/
+
+BOOL message_init(void)
+{
+ if (tdb) return True;
+
+ tdb = tdb_open_log(lock_path("messages.tdb"),
+ 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
+ O_RDWR|O_CREAT,0600);
+
+ if (!tdb) {
+ DEBUG(0,("ERROR: Failed to initialise messages database\n"));
+ return False;
+ }
+
+ CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1);
+
+ message_register(MSG_PING, ping_message);
+ message_register(MSG_REQ_DEBUGLEVEL, debuglevel_message);
+
+ return True;
+}
+
+/*******************************************************************
+ Form a static tdb key from a pid.
+******************************************************************/
+
+static TDB_DATA message_key_pid(pid_t pid)
+{
+ static char key[20];
+ TDB_DATA kbuf;
+
+ slprintf(key, sizeof(key)-1, "PID/%d", (int)pid);
+
+ kbuf.dptr = (char *)key;
+ kbuf.dsize = strlen(key)+1;
+ return kbuf;
+}
+
+/****************************************************************************
+ Notify a process that it has a message. If the process doesn't exist
+ then delete its record in the database.
+****************************************************************************/
+
+static BOOL message_notify(pid_t pid)
+{
+ /* Doing kill with a non-positive pid causes messages to be
+ * sent to places we don't want. */
+ SMB_ASSERT(pid > 0);
+ if (kill(pid, SIGUSR1) == -1) {
+ if (errno == ESRCH) {
+ DEBUG(2,("pid %d doesn't exist - deleting messages record\n", (int)pid));
+ tdb_delete(tdb, message_key_pid(pid));
+ } else {
+ DEBUG(2,("message to process %d failed - %s\n", (int)pid, strerror(errno)));
+ }
+ return False;
+ }
+ return True;
+}
+
+/****************************************************************************
+ Send a message to a particular pid.
+****************************************************************************/
+
+BOOL message_send_pid(pid_t pid, int msg_type, const void *buf, size_t len,
+ BOOL duplicates_allowed)
+{
+ TDB_DATA kbuf;
+ TDB_DATA dbuf;
+ struct message_rec rec;
+ void *p;
+
+ rec.msg_version = MESSAGE_VERSION;
+ rec.msg_type = msg_type;
+ rec.dest = pid;
+ rec.src = sys_getpid();
+ rec.len = len;
+
+ /* Doing kill with a non-positive pid causes messages to be
+ * sent to places we don't want. */
+ SMB_ASSERT(pid > 0);
+
+ kbuf = message_key_pid(pid);
+
+ /* lock the record for the destination */
+ tdb_chainlock(tdb, kbuf);
+
+ dbuf = tdb_fetch(tdb, kbuf);
+
+ if (!dbuf.dptr) {
+ /* its a new record */
+ p = (void *)malloc(len + sizeof(rec));
+ if (!p) goto failed;
+
+ memcpy(p, &rec, sizeof(rec));
+ if (len > 0) memcpy((void *)((char*)p+sizeof(rec)), buf, len);
+
+ dbuf.dptr = p;
+ dbuf.dsize = len + sizeof(rec);
+ tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
+ SAFE_FREE(p);
+ goto ok;
+ }
+
+ if (!duplicates_allowed) {
+ char *ptr;
+ struct message_rec prec;
+
+ for(ptr = (char *)dbuf.dptr; ptr < dbuf.dptr + dbuf.dsize; ) {
+ /*
+ * First check if the message header matches, then, if it's a non-zero
+ * sized message, check if the data matches. If so it's a duplicate and
+ * we can discard it. JRA.
+ */
+
+ if (!memcmp(ptr, &rec, sizeof(rec))) {
+ if (!len || (len && !memcmp( ptr + sizeof(rec), buf, len))) {
+ DEBUG(10,("message_send_pid: discarding duplicate message.\n"));
+ SAFE_FREE(dbuf.dptr);
+ tdb_chainunlock(tdb, kbuf);
+ return True;
+ }
+ }
+ memcpy(&prec, ptr, sizeof(prec));
+ ptr += sizeof(rec) + prec.len;
+ }
+ }
+
+ /* we're adding to an existing entry */
+ p = (void *)malloc(dbuf.dsize + len + sizeof(rec));
+ if (!p) goto failed;
+
+ memcpy(p, dbuf.dptr, dbuf.dsize);
+ memcpy((void *)((char*)p+dbuf.dsize), &rec, sizeof(rec));
+ if (len > 0) memcpy((void *)((char*)p+dbuf.dsize+sizeof(rec)), buf, len);
+
+ SAFE_FREE(dbuf.dptr);
+ dbuf.dptr = p;
+ dbuf.dsize += len + sizeof(rec);
+ tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
+ SAFE_FREE(dbuf.dptr);
+
+ ok:
+ tdb_chainunlock(tdb, kbuf);
+ errno = 0; /* paranoia */
+ return message_notify(pid);
+
+ failed:
+ tdb_chainunlock(tdb, kbuf);
+ errno = 0; /* paranoia */
+ return False;
+}
+
+/****************************************************************************
+ Retrieve the next message for the current process.
+****************************************************************************/
+
+static BOOL message_recv(int *msg_type, pid_t *src, void **buf, size_t *len)
+{
+ TDB_DATA kbuf;
+ TDB_DATA dbuf;
+ struct message_rec rec;
+
+ kbuf = message_key_pid(sys_getpid());
+
+ tdb_chainlock(tdb, kbuf);
+
+ dbuf = tdb_fetch(tdb, kbuf);
+ if (dbuf.dptr == NULL || dbuf.dsize == 0) goto failed;
+
+ memcpy(&rec, dbuf.dptr, sizeof(rec));
+
+ if (rec.msg_version != MESSAGE_VERSION) {
+ DEBUG(0,("message version %d received (expected %d)\n", rec.msg_version, MESSAGE_VERSION));
+ goto failed;
+ }
+
+ if (rec.len > 0) {
+ (*buf) = (void *)malloc(rec.len);
+ if (!(*buf)) goto failed;
+
+ memcpy(*buf, dbuf.dptr+sizeof(rec), rec.len);
+ } else {
+ *buf = NULL;
+ }
+
+ *len = rec.len;
+ *msg_type = rec.msg_type;
+ *src = rec.src;
+
+ if (dbuf.dsize - (sizeof(rec)+rec.len) > 0)
+ memmove(dbuf.dptr, dbuf.dptr+sizeof(rec)+rec.len, dbuf.dsize - (sizeof(rec)+rec.len));
+ dbuf.dsize -= sizeof(rec)+rec.len;
+
+ if (dbuf.dsize == 0)
+ tdb_delete(tdb, kbuf);
+ else
+ tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
+
+ SAFE_FREE(dbuf.dptr);
+ tdb_chainunlock(tdb, kbuf);
+ return True;
+
+ failed:
+ tdb_chainunlock(tdb, kbuf);
+ return False;
+}
+
+/****************************************************************************
+ Receive and dispatch any messages pending for this process.
+ Notice that all dispatch handlers for a particular msg_type get called,
+ so you can register multiple handlers for a message.
+****************************************************************************/
+
+void message_dispatch(void)
+{
+ int msg_type;
+ pid_t src;
+ void *buf;
+ size_t len;
+ struct dispatch_fns *dfn;
+ int n_handled;
+
+ if (!received_signal) return;
+
+ DEBUG(10,("message_dispatch: received_signal = %d\n", received_signal));
+
+ received_signal = 0;
+
+ while (message_recv(&msg_type, &src, &buf, &len)) {
+ DEBUG(10,("message_dispatch: received msg_type=%d src_pid=%d\n",
+ msg_type, (int) src));
+ n_handled = 0;
+ for (dfn = dispatch_fns; dfn; dfn = dfn->next) {
+ if (dfn->msg_type == msg_type) {
+ DEBUG(10,("message_dispatch: processing message of type %d.\n", msg_type));
+ dfn->fn(msg_type, src, buf, len);
+ n_handled++;
+ }
+ }
+ if (!n_handled) {
+ DEBUG(5,("message_dispatch: warning: no handlers registed for "
+ "msg_type %d in pid%d\n",
+ msg_type, sys_getpid()));
+ }
+ SAFE_FREE(buf);
+ }
+}
+
+/****************************************************************************
+ Register a dispatch function for a particular message type.
+****************************************************************************/
+
+void message_register(int msg_type,
+ void (*fn)(int msg_type, pid_t pid, void *buf, size_t len))
+{
+ struct dispatch_fns *dfn;
+
+ dfn = (struct dispatch_fns *)malloc(sizeof(*dfn));
+
+ if (dfn != NULL) {
+
+ ZERO_STRUCTPN(dfn);
+
+ dfn->msg_type = msg_type;
+ dfn->fn = fn;
+
+ DLIST_ADD(dispatch_fns, dfn);
+ }
+ else {
+
+ DEBUG(0,("message_register: Not enough memory. malloc failed!\n"));
+ }
+}
+
+/****************************************************************************
+ De-register the function for a particular message type.
+****************************************************************************/
+
+void message_deregister(int msg_type)
+{
+ struct dispatch_fns *dfn, *next;
+
+ for (dfn = dispatch_fns; dfn; dfn = next) {
+ next = dfn->next;
+ if (dfn->msg_type == msg_type) {
+ DLIST_REMOVE(dispatch_fns, dfn);
+ SAFE_FREE(dfn);
+ }
+ }
+}
+
+struct msg_all {
+ int msg_type;
+ const void *buf;
+ size_t len;
+ BOOL duplicates;
+ int n_sent;
+};
+
+/****************************************************************************
+ Send one of the messages for the broadcast.
+****************************************************************************/
+
+static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct connections_data crec;
+ struct msg_all *msg_all = (struct msg_all *)state;
+
+ if (dbuf.dsize != sizeof(crec))
+ return 0;
+
+ memcpy(&crec, dbuf.dptr, sizeof(crec));
+
+ if (crec.cnum != -1)
+ return 0;
+
+ /* if the msg send fails because the pid was not found (i.e. smbd died),
+ * the msg has already been deleted from the messages.tdb.*/
+ if (!message_send_pid(crec.pid, msg_all->msg_type,
+ msg_all->buf, msg_all->len,
+ msg_all->duplicates)) {
+
+ /* if the pid was not found delete the entry from connections.tdb */
+ if (errno == ESRCH) {
+ DEBUG(2,("pid %u doesn't exist - deleting connections %d [%s]\n",
+ (unsigned int)crec.pid, crec.cnum, crec.name));
+ tdb_delete(the_tdb, kbuf);
+ }
+ }
+ msg_all->n_sent++;
+ return 0;
+}
+
+/**
+ * Send a message to all smbd processes.
+ *
+ * It isn't very efficient, but should be OK for the sorts of
+ * applications that use it. When we need efficient broadcast we can add
+ * it.
+ *
+ * @param n_sent Set to the number of messages sent. This should be
+ * equal to the number of processes, but be careful for races.
+ *
+ * @return True for success.
+ **/
+BOOL message_send_all(TDB_CONTEXT *conn_tdb, int msg_type,
+ const void *buf, size_t len,
+ BOOL duplicates_allowed,
+ int *n_sent)
+{
+ struct msg_all msg_all;
+
+ msg_all.msg_type = msg_type;
+ msg_all.buf = buf;
+ msg_all.len = len;
+ msg_all.duplicates = duplicates_allowed;
+ msg_all.n_sent = 0;
+
+ tdb_traverse(conn_tdb, traverse_fn, &msg_all);
+ if (n_sent)
+ *n_sent = msg_all.n_sent;
+ return True;
+}
+
+static VOLATILE sig_atomic_t gotalarm;
+
+/***************************************************************
+ Signal function to tell us we timed out.
+****************************************************************/
+
+static void gotalarm_sig(void)
+{
+ gotalarm = 1;
+}
+
+/**
+ * Lock the messaging tdb based on a string - this is used as a primitive
+ * form of mutex between smbd instances.
+ *
+ * @param name A string identifying the name of the mutex.
+ */
+
+BOOL message_named_mutex(char *name, unsigned int timeout)
+{
+ TDB_DATA key;
+ int ret;
+
+ if (!message_init())
+ return False;
+
+ key.dptr = name;
+ key.dsize = strlen(name)+1;
+
+ if (timeout) {
+ gotalarm = 0;
+ CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+ alarm(timeout);
+ }
+
+ ret = tdb_chainlock(tdb, key);
+
+ if (timeout) {
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
+ if (gotalarm)
+ return False;
+ }
+
+ if (ret == 0)
+ DEBUG(10,("message_named_mutex: got mutex for %s\n", name ));
+
+ return (ret == 0);
+}
+
+/**
+ * Unlock a named mutex.
+ *
+ * @param name A string identifying the name of the mutex.
+ */
+
+void message_named_mutex_release(char *name)
+{
+ TDB_DATA key;
+
+ key.dptr = name;
+ key.dsize = strlen(name)+1;
+
+ tdb_chainunlock(tdb, key);
+ DEBUG(10,("message_named_mutex: released mutex for %s\n", name ));
+}
+
+/** @} **/
diff --git a/source3/lib/ms_fnmatch.c b/source3/lib/ms_fnmatch.c
new file mode 100644
index 0000000000..106efa5bbc
--- /dev/null
+++ b/source3/lib/ms_fnmatch.c
@@ -0,0 +1,225 @@
+/*
+ Unix SMB/CIFS implementation.
+ filename matching routine
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ This module was originally based on fnmatch.c copyright by the Free
+ Software Foundation. It bears little resemblence to that code now
+*/
+
+
+#if FNMATCH_TEST
+#include <stdio.h>
+#include <stdlib.h>
+#else
+#include "includes.h"
+#endif
+
+/*
+ bugger. we need a separate wildcard routine for older versions
+ of the protocol. This is not yet perfect, but its a lot
+ better than what we had */
+static int ms_fnmatch_lanman_core(const smb_ucs2_t *pattern,
+ const smb_ucs2_t *string)
+{
+ const smb_ucs2_t *p = pattern, *n = string;
+ smb_ucs2_t c;
+
+ if (strcmp_wa(p, "?")==0 && strcmp_wa(n, ".")) goto match;
+
+ while ((c = *p++)) {
+ switch (c) {
+ case UCS2_CHAR('.'):
+ if (! *n) goto next;
+ if (*n != UCS2_CHAR('.')) goto nomatch;
+ n++;
+ break;
+
+ case UCS2_CHAR('?'):
+ if (! *n) goto next;
+ if ((*n == UCS2_CHAR('.') &&
+ n[1] != UCS2_CHAR('.')) || ! *n)
+ goto next;
+ n++;
+ break;
+
+ case UCS2_CHAR('>'):
+ if (! *n) goto next;
+ if (n[0] == UCS2_CHAR('.')) {
+ if (! n[1] && ms_fnmatch_lanman_core(p, n+1) == 0) goto match;
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ goto nomatch;
+ }
+ n++;
+ break;
+
+ case UCS2_CHAR('*'):
+ if (! *n) goto next;
+ if (! *p) goto match;
+ for (; *n; n++) {
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ }
+ break;
+
+ case UCS2_CHAR('<'):
+ for (; *n; n++) {
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ if (*n == UCS2_CHAR('.') &&
+ !strchr_w(n+1,UCS2_CHAR('.'))) {
+ n++;
+ break;
+ }
+ }
+ break;
+
+ case UCS2_CHAR('"'):
+ if (*n == 0 && ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ if (*n != UCS2_CHAR('.')) goto nomatch;
+ n++;
+ break;
+
+ default:
+ if (c != *n) goto nomatch;
+ n++;
+ }
+ }
+
+ if (! *n) goto match;
+
+ nomatch:
+ /*
+ if (verbose) printf("NOMATCH pattern=[%s] string=[%s]\n", pattern, string);
+ */
+ return -1;
+
+next:
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
+ goto nomatch;
+
+ match:
+ /*
+ if (verbose) printf("MATCH pattern=[%s] string=[%s]\n", pattern, string);
+ */
+ return 0;
+}
+
+static int ms_fnmatch_lanman1(const smb_ucs2_t *pattern, const smb_ucs2_t *string)
+{
+ if (!strpbrk_wa(pattern, "?*<>\"")) {
+ smb_ucs2_t s[] = {UCS2_CHAR('.'), 0};
+ if (strcmp_wa(string,"..") == 0) string = s;
+ return strcasecmp_w(pattern, string);
+ }
+
+ if (strcmp_wa(string,"..") == 0 || strcmp_wa(string,".") == 0) {
+ smb_ucs2_t dot[] = {UCS2_CHAR('.'), 0};
+ smb_ucs2_t dotdot[] = {UCS2_CHAR('.'), UCS2_CHAR('.'), 0};
+ return ms_fnmatch_lanman_core(pattern, dotdot) &&
+ ms_fnmatch_lanman_core(pattern, dot);
+ }
+
+ return ms_fnmatch_lanman_core(pattern, string);
+}
+
+
+/* the following function was derived using the masktest utility -
+ after years of effort we finally have a perfect MS wildcard
+ matching routine!
+
+ NOTE: this matches only filenames with no directory component
+
+ Returns 0 on match, -1 on fail.
+*/
+static int ms_fnmatch_w(const smb_ucs2_t *pattern, const smb_ucs2_t *string, int protocol)
+{
+ const smb_ucs2_t *p = pattern, *n = string;
+ smb_ucs2_t c;
+
+ if (protocol <= PROTOCOL_LANMAN2) {
+ return ms_fnmatch_lanman1(pattern, string);
+ }
+
+ while ((c = *p++)) {
+ switch (c) {
+ case UCS2_CHAR('?'):
+ if (! *n) return -1;
+ n++;
+ break;
+
+ case UCS2_CHAR('>'):
+ if (n[0] == UCS2_CHAR('.')) {
+ if (! n[1] && ms_fnmatch_w(p, n+1, protocol) == 0) return 0;
+ if (ms_fnmatch_w(p, n, protocol) == 0) return 0;
+ return -1;
+ }
+ if (! *n) return ms_fnmatch_w(p, n, protocol);
+ n++;
+ break;
+
+ case UCS2_CHAR('*'):
+ for (; *n; n++) {
+ if (ms_fnmatch_w(p, n, protocol) == 0) return 0;
+ }
+ break;
+
+ case UCS2_CHAR('<'):
+ for (; *n; n++) {
+ if (ms_fnmatch_w(p, n, protocol) == 0) return 0;
+ if (*n == UCS2_CHAR('.') && !strchr_wa(n+1,'.')) {
+ n++;
+ break;
+ }
+ }
+ break;
+
+ case UCS2_CHAR('"'):
+ if (*n == 0 && ms_fnmatch_w(p, n, protocol) == 0) return 0;
+ if (*n != UCS2_CHAR('.')) return -1;
+ n++;
+ break;
+
+ default:
+ if (c != *n) return -1;
+ n++;
+ }
+ }
+
+ if (! *n) return 0;
+
+ return -1;
+}
+
+
+int ms_fnmatch(const char *pattern, const char *string, int protocol)
+{
+ wpstring p, s;
+ int ret;
+
+ pstrcpy_wa(p, pattern);
+ pstrcpy_wa(s, string);
+
+ ret = ms_fnmatch_w(p, s, protocol);
+/* DEBUG(0,("ms_fnmatch(%s,%s) -> %d\n", pattern, string, ret)); */
+ return ret;
+}
+
+/* a generic fnmatch function - uses for non-CIFS pattern matching */
+int gen_fnmatch(const char *pattern, const char *string)
+{
+ return ms_fnmatch(pattern, string, PROTOCOL_NT1);
+}
diff --git a/source3/lib/netatalk.c b/source3/lib/netatalk.c
new file mode 100644
index 0000000000..035f3794a0
--- /dev/null
+++ b/source3/lib/netatalk.c
@@ -0,0 +1,155 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ netatalk.c : routines for improving interaction between Samba and netatalk.
+ Copyright (C) John D. Blair <jdblair@cobaltnet.com> 1998
+ Cobalt Networks, Inc.
+*/
+
+#include "includes.h"
+
+#ifdef WITH_NETATALK
+
+/*****************
+ ntalk_resourcepath: creates the path to the netatalk resource fork for
+ a given file
+
+ fname: normal filename
+ doublename: buffer that will contain the location of the resource fork
+ length: length of this buffer (to prevent overflows)
+
+ NOTE: doesn't currently gracefully deal with buffer overflows- it just
+ doesn't allow them to occur.
+******************/
+void ntalk_resourcepath(const char *fname, char *doublename, const int length)
+{
+ int i;
+ int charnum;
+ int lastslash;
+ char appledouble[] = APPLEDOUBLE;
+
+ /* copy fname to doublename and find last slash */
+ for (i = 0; (fname[i] != 0) && (i <= length); i++) {
+ if (fname[i] == '/') {
+ lastslash = i;
+ }
+ doublename[i] = fname[i];
+ }
+ lastslash++; /* location just after last slash */
+
+ /* insert .AppleDouble */
+ charnum = lastslash;
+ for (i = 0; (appledouble[i] != 0) && (i <= length); i++) {
+ doublename[charnum] = appledouble[i];
+ charnum++;
+ }
+
+ /* append last part of file name */
+ for (i = lastslash; (fname[i] != 0) && (i <= length); i++) {
+ doublename[charnum] = fname[i];
+ charnum++;
+ }
+
+ doublename[charnum] = 0;
+}
+
+/**********************
+ ntalk_mkresdir: creates a new .AppleDouble directory (if necessary)
+ for the resource fork of a specified file
+**********************/
+int ntalk_mkresdir(const char *fname)
+{
+ char fdir[255];
+ int i;
+ int lastslash;
+ SMB_STRUCT_STAT dirstats;
+ char appledouble[] = APPLEDOUBLE;
+
+ /* find directory containing fname */
+ for (i = 0; (fname[i] != 0) && (i <= 254); i++) {
+ fdir[i] = fname[i];
+ if (fdir[i] == '/') {
+ lastslash = i;
+ }
+ }
+ lastslash++;
+ fdir[lastslash] = 0;
+ sys_lstat(fdir, &dirstats);
+
+ /* append .AppleDouble */
+ for (i = 0; (appledouble[i] != 0) && (lastslash <= 254); i++) {
+ fdir[lastslash] = appledouble[i];
+ lastslash++;
+ }
+ fdir[lastslash] = 0;
+
+ /* create this directory */
+ /* silently ignore EEXIST error */
+ if ((mkdir(fdir, dirstats.st_mode) < 0) && (errno != EEXIST)) {
+ return errno;
+ }
+
+ /* set ownership of this dir to the same as its parent */
+ /* holy race condition, batman! */
+ /* warning: this doesn't check for errors */
+ chown(fdir, dirstats.st_uid, dirstats.st_gid);
+
+ printf("%s\n", fdir);
+
+ return 1;
+}
+
+/**********************
+ ntalk_unlink: unlink a file and its resource fork
+**********************/
+int ntalk_unlink(const char *fname)
+{
+ char buf[255];
+
+ ntalk_resourcepath(fname, buf, 255);
+ unlink(buf);
+ return unlink(fname);
+}
+
+/**********************
+ ntalk_chown: chown a file and its resource fork
+**********************/
+int ntalk_chown(const char *fname, const uid_t uid, const gid_t gid)
+{
+ char buf[255];
+
+ ntalk_resourcepath(fname, buf, 255);
+ chown(buf, uid, gid);
+ return chown(fname, uid, gid);
+}
+
+/**********************
+ ntalk_chmod: chmod a file and its resource fork
+**********************/
+int ntalk_chmod(const char *fname, mode_t perms)
+{
+ char buf[255];
+
+ ntalk_resourcepath(fname, buf, 255);
+ chmod(buf, perms);
+ return chmod(fname, perms);
+}
+
+#endif /* WITH_NETATALK */
diff --git a/source3/lib/pam_errors.c b/source3/lib/pam_errors.c
new file mode 100644
index 0000000000..f74e4bf176
--- /dev/null
+++ b/source3/lib/pam_errors.c
@@ -0,0 +1,125 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * PAM error mapping functions
+ * Copyright (C) Andrew Bartlett 2002
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+#ifdef WITH_PAM
+#include <security/pam_appl.h>
+
+#if defined(PAM_AUTHTOK_RECOVERY_ERR) && !defined(PAM_AUTHTOK_RECOVER_ERR)
+#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR
+#endif
+
+/* PAM -> NT_STATUS map */
+const static struct {
+ int pam_code;
+ NTSTATUS ntstatus;
+} pam_to_nt_status_map[] = {
+ {PAM_OPEN_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_SYMBOL_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_SERVICE_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_SYSTEM_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_BUF_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_PERM_DENIED, NT_STATUS_ACCESS_DENIED},
+ {PAM_AUTH_ERR, NT_STATUS_WRONG_PASSWORD},
+ {PAM_CRED_INSUFFICIENT, NT_STATUS_INSUFFICIENT_LOGON_INFO}, /* FIXME: Is this correct? */
+ {PAM_AUTHINFO_UNAVAIL, NT_STATUS_LOGON_FAILURE},
+ {PAM_USER_UNKNOWN, NT_STATUS_NO_SUCH_USER},
+ {PAM_MAXTRIES, NT_STATUS_REMOTE_SESSION_LIMIT}, /* FIXME: Is this correct? */
+ {PAM_NEW_AUTHTOK_REQD, NT_STATUS_PASSWORD_MUST_CHANGE},
+ {PAM_ACCT_EXPIRED, NT_STATUS_ACCOUNT_EXPIRED},
+ {PAM_SESSION_ERR, NT_STATUS_INSUFFICIENT_RESOURCES},
+ {PAM_CRED_UNAVAIL, NT_STATUS_NO_TOKEN}, /* FIXME: Is this correct? */
+ {PAM_CRED_EXPIRED, NT_STATUS_PASSWORD_EXPIRED}, /* FIXME: Is this correct? */
+ {PAM_CRED_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_AUTHTOK_ERR, NT_STATUS_UNSUCCESSFUL},
+#ifdef PAM_AUTHTOK_RECOVER_ERR
+ {PAM_AUTHTOK_RECOVER_ERR, NT_STATUS_UNSUCCESSFUL},
+#endif
+ {PAM_AUTHTOK_EXPIRED, NT_STATUS_PASSWORD_EXPIRED},
+ {PAM_SUCCESS, NT_STATUS_OK}
+};
+
+/* NT_STATUS -> PAM map */
+const static struct {
+ NTSTATUS ntstatus;
+ int pam_code;
+} nt_status_to_pam_map[] = {
+ {NT_STATUS_UNSUCCESSFUL, PAM_SYSTEM_ERR},
+ {NT_STATUS_NO_SUCH_USER, PAM_USER_UNKNOWN},
+ {NT_STATUS_WRONG_PASSWORD, PAM_AUTH_ERR},
+ {NT_STATUS_LOGON_FAILURE, PAM_AUTH_ERR},
+ {NT_STATUS_ACCOUNT_EXPIRED, PAM_ACCT_EXPIRED},
+ {NT_STATUS_PASSWORD_MUST_CHANGE, PAM_NEW_AUTHTOK_REQD},
+ {NT_STATUS_OK, PAM_SUCCESS}
+};
+
+/*****************************************************************************
+convert a PAM error to a NT status32 code
+ *****************************************************************************/
+NTSTATUS pam_to_nt_status(int pam_error)
+{
+ int i;
+ if (pam_error == 0) return NT_STATUS_OK;
+
+ for (i=0; NT_STATUS_V(pam_to_nt_status_map[i].ntstatus); i++) {
+ if (pam_error == pam_to_nt_status_map[i].pam_code)
+ return pam_to_nt_status_map[i].ntstatus;
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/*****************************************************************************
+convert an NT status32 code to a PAM error
+ *****************************************************************************/
+int nt_status_to_pam(NTSTATUS nt_status)
+{
+ int i;
+ if NT_STATUS_IS_OK(nt_status) return PAM_SUCCESS;
+
+ for (i=0; NT_STATUS_V(nt_status_to_pam_map[i].ntstatus); i++) {
+ if (NT_STATUS_EQUAL(nt_status,nt_status_to_pam_map[i].ntstatus))
+ return nt_status_to_pam_map[i].pam_code;
+ }
+ return PAM_SYSTEM_ERR;
+}
+
+#else
+
+/*****************************************************************************
+convert a PAM error to a NT status32 code
+ *****************************************************************************/
+NTSTATUS pam_to_nt_status(int pam_error)
+{
+ if (pam_error == 0) return NT_STATUS_OK;
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/*****************************************************************************
+convert an NT status32 code to a PAM error
+ *****************************************************************************/
+int nt_status_to_pam(NTSTATUS nt_status)
+{
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_OK)) return 0;
+ return 4; /* PAM_SYSTEM_ERR */
+}
+
+#endif
+
diff --git a/source3/lib/pidfile.c b/source3/lib/pidfile.c
new file mode 100644
index 0000000000..28fd959b54
--- /dev/null
+++ b/source3/lib/pidfile.c
@@ -0,0 +1,112 @@
+/* this code is broken - there is a race condition with the unlink (tridge) */
+
+/*
+ Unix SMB/CIFS implementation.
+ pidfile handling
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK
+#endif
+
+/* return the pid in a pidfile. return 0 if the process (or pidfile)
+ does not exist */
+pid_t pidfile_pid(char *name)
+{
+ int fd;
+ char pidstr[20];
+ unsigned ret;
+ pstring pidFile;
+
+ slprintf(pidFile, sizeof(pidFile)-1, "%s/%s.pid", lp_lockdir(), name);
+
+ fd = sys_open(pidFile, O_NONBLOCK | O_RDONLY, 0644);
+ if (fd == -1) {
+ return 0;
+ }
+
+ ZERO_ARRAY(pidstr);
+
+ if (read(fd, pidstr, sizeof(pidstr)-1) <= 0) {
+ goto noproc;
+ }
+
+ ret = atoi(pidstr);
+
+ if (!process_exists((pid_t)ret)) {
+ goto noproc;
+ }
+
+ if (fcntl_lock(fd,SMB_F_SETLK,0,1,F_RDLCK)) {
+ /* we could get the lock - it can't be a Samba process */
+ goto noproc;
+ }
+
+ close(fd);
+ return (pid_t)ret;
+
+ noproc:
+ close(fd);
+ unlink(pidFile);
+ return 0;
+}
+
+/* Create a pid file in the lock directory. open it and leave it locked.
+ This must be done after a call to lp_load() as it uses the lp_lockdir()
+ function to generate the path to the pidfile. */
+
+void pidfile_create(char *name)
+{
+ int fd;
+ char buf[20];
+ pstring pidFile;
+ pid_t pid;
+
+ slprintf(pidFile, sizeof(pidFile)-1, "%s/%s.pid", lp_lockdir(), name);
+
+ pid = pidfile_pid(name);
+ if (pid != 0) {
+ DEBUG(0,("ERROR: %s is already running. File %s exists and process id %d is running.\n",
+ name, pidFile, (int)pid));
+ exit(1);
+ }
+
+ fd = sys_open(pidFile, O_NONBLOCK | O_CREAT | O_WRONLY | O_EXCL, 0644);
+ if (fd == -1) {
+ DEBUG(0,("ERROR: can't open %s: Error was %s\n", pidFile,
+ strerror(errno)));
+ exit(1);
+ }
+
+ if (fcntl_lock(fd,SMB_F_SETLK,0,1,F_WRLCK)==False) {
+ DEBUG(0,("ERROR: %s : fcntl lock of file %s failed. Error was %s\n",
+ name, pidFile, strerror(errno)));
+ exit(1);
+ }
+
+ memset(buf, 0, sizeof(buf));
+ slprintf(buf, sizeof(buf) - 1, "%u\n", (unsigned int) sys_getpid());
+ if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
+ DEBUG(0,("ERROR: can't write to file %s: %s\n",
+ pidFile, strerror(errno)));
+ exit(1);
+ }
+ /* Leave pid file open & locked for the duration... */
+}
diff --git a/source3/lib/readline.c b/source3/lib/readline.c
new file mode 100644
index 0000000000..d80c571dd3
--- /dev/null
+++ b/source3/lib/readline.c
@@ -0,0 +1,119 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba readline wrapper implementation
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_NEW_LIBREADLINE
+# define RL_COMPLETION_CAST (rl_completion_func_t *)
+#else
+/* This type is missing from libreadline<4.0 (approximately) */
+# define RL_COMPLETION_CAST
+#endif /* HAVE_NEW_LIBREADLINE */
+
+/****************************************************************************
+ Display the prompt and wait for input. Call callback() regularly
+****************************************************************************/
+
+static char *smb_readline_replacement(char *prompt, void (*callback)(void),
+ char **(completion_fn)(char *text, int start, int end))
+{
+ fd_set fds;
+ static pstring line;
+ struct timeval timeout;
+ int fd = fileno(stdin);
+ char *ret;
+
+ x_fprintf(dbf, "%s", prompt);
+ x_fflush(dbf);
+
+ while (1) {
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+
+ FD_ZERO(&fds);
+ FD_SET(fd,&fds);
+
+ if (sys_select_intr(fd+1,&fds,NULL,NULL,&timeout) == 1) {
+ ret = fgets(line, sizeof(line), stdin);
+ return ret;
+ }
+ if (callback)
+ callback();
+ }
+}
+
+/****************************************************************************
+ Display the prompt and wait for input. Call callback() regularly.
+****************************************************************************/
+
+char *smb_readline(char *prompt, void (*callback)(void),
+ char **(completion_fn)(char *text, int start, int end))
+{
+#if HAVE_LIBREADLINE
+ if (isatty(fileno(stdin))) {
+ char *ret;
+
+ /* Aargh! Readline does bizzare things with the terminal width
+ that mucks up expect(1). Set CLI_NO_READLINE in the environment
+ to force readline not to be used. */
+
+ if (getenv("CLI_NO_READLINE"))
+ return smb_readline_replacement(prompt, callback, completion_fn);
+
+ if (completion_fn) {
+ /* The callback prototype has changed slightly between
+ different versions of Readline, so the same function
+ works in all of them to date, but we get compiler
+ warnings in some. */
+ rl_attempted_completion_function = RL_COMPLETION_CAST completion_fn;
+ }
+
+ if (callback)
+ rl_event_hook = (Function *)callback;
+ ret = readline(prompt);
+ if (ret && *ret)
+ add_history(ret);
+ return ret;
+ } else
+#endif
+ return smb_readline_replacement(prompt, callback, completion_fn);
+}
+
+/****************************************************************************
+history
+****************************************************************************/
+int cmd_history(void)
+{
+#if defined(HAVE_LIBREADLINE)
+ HIST_ENTRY **hlist;
+ int i;
+
+ hlist = history_list();
+
+ for (i = 0; hlist && hlist[i]; i++) {
+ DEBUG(0, ("%d: %s\n", i, hlist[i]->line));
+ }
+#else
+ DEBUG(0,("no history without readline support\n"));
+#endif
+
+ return 0;
+}
diff --git a/source3/lib/replace.c b/source3/lib/replace.c
new file mode 100644
index 0000000000..dd50ff035e
--- /dev/null
+++ b/source3/lib/replace.c
@@ -0,0 +1,416 @@
+/*
+ Unix SMB/CIFS implementation.
+ replacement routines for broken systems
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+ void replace_dummy(void);
+ void replace_dummy(void) {}
+
+#ifndef HAVE_FTRUNCATE
+ /*******************************************************************
+ftruncate for operating systems that don't have it
+********************************************************************/
+ int ftruncate(int f,SMB_OFF_T l)
+{
+ struct flock fl;
+
+ fl.l_whence = 0;
+ fl.l_len = 0;
+ fl.l_start = l;
+ fl.l_type = F_WRLCK;
+ return fcntl(f, F_FREESP, &fl);
+}
+#endif /* HAVE_FTRUNCATE */
+
+
+#ifndef HAVE_STRLCPY
+/* like strncpy but does not 0 fill the buffer and always null
+ terminates. bufsize is the size of the destination buffer */
+ size_t strlcpy(char *d, const char *s, size_t bufsize)
+{
+ size_t len = strlen(s);
+ size_t ret = len;
+ if (bufsize <= 0) return 0;
+ if (len >= bufsize) len = bufsize-1;
+ memcpy(d, s, len);
+ d[len] = 0;
+ return ret;
+}
+#endif
+
+#ifndef HAVE_STRLCAT
+/* like strncat but does not 0 fill the buffer and always null
+ terminates. bufsize is the length of the buffer, which should
+ be one more than the maximum resulting string length */
+ size_t strlcat(char *d, const char *s, size_t bufsize)
+{
+ size_t len1 = strlen(d);
+ size_t len2 = strlen(s);
+ size_t ret = len1 + len2;
+
+ if (len1+len2 >= bufsize) {
+ len2 = bufsize - (len1+1);
+ }
+ if (len2 > 0) {
+ memcpy(d+len1, s, len2);
+ d[len1+len2] = 0;
+ }
+ return ret;
+}
+#endif
+
+#ifndef HAVE_MKTIME
+/*******************************************************************
+a mktime() replacement for those who don't have it - contributed by
+C.A. Lademann <cal@zls.com>
+Corrections by richard.kettlewell@kewill.com
+********************************************************************/
+
+#define MINUTE 60
+#define HOUR 60*MINUTE
+#define DAY 24*HOUR
+#define YEAR 365*DAY
+ time_t mktime(struct tm *t)
+{
+ struct tm *u;
+ time_t epoch = 0;
+ int n;
+ int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ y, m, i;
+
+ if(t->tm_year < 70)
+ return((time_t)-1);
+
+ n = t->tm_year + 1900 - 1;
+ epoch = (t->tm_year - 70) * YEAR +
+ ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
+
+ y = t->tm_year + 1900;
+ m = 0;
+
+ for(i = 0; i < t->tm_mon; i++) {
+ epoch += mon [m] * DAY;
+ if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
+ epoch += DAY;
+
+ if(++m > 11) {
+ m = 0;
+ y++;
+ }
+ }
+
+ epoch += (t->tm_mday - 1) * DAY;
+ epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
+
+ if((u = localtime(&epoch)) != NULL) {
+ t->tm_sec = u->tm_sec;
+ t->tm_min = u->tm_min;
+ t->tm_hour = u->tm_hour;
+ t->tm_mday = u->tm_mday;
+ t->tm_mon = u->tm_mon;
+ t->tm_year = u->tm_year;
+ t->tm_wday = u->tm_wday;
+ t->tm_yday = u->tm_yday;
+ t->tm_isdst = u->tm_isdst;
+ }
+
+ return(epoch);
+}
+#endif /* !HAVE_MKTIME */
+
+
+
+#ifndef HAVE_RENAME
+/* Rename a file. (from libiberty in GNU binutils) */
+ int rename(const char *zfrom, const char *zto)
+{
+ if (link (zfrom, zto) < 0)
+ {
+ if (errno != EEXIST)
+ return -1;
+ if (unlink (zto) < 0
+ || link (zfrom, zto) < 0)
+ return -1;
+ }
+ return unlink (zfrom);
+}
+#endif /* HAVE_RENAME */
+
+
+#ifndef HAVE_INNETGR
+#if defined(HAVE_SETNETGRENT) && defined(HAVE_GETNETGRENT) && defined(HAVE_ENDNETGRENT)
+/*
+ * Search for a match in a netgroup. This replaces it on broken systems.
+ */
+ int innetgr(const char *group,const char *host,const char *user,const char *dom)
+{
+ char *hst, *usr, *dm;
+
+ setnetgrent(group);
+ while (getnetgrent(&hst, &usr, &dm)) {
+ if (((host == 0) || (hst == 0) || !strcmp(host, hst)) &&
+ ((user == 0) || (usr == 0) || !strcmp(user, usr)) &&
+ ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) {
+ endnetgrent();
+ return (1);
+ }
+ }
+ endnetgrent();
+ return (0);
+}
+#endif /* HAVE_SETNETGRENT HAVE_GETNETGRENT HAVE_ENDNETGRENT */
+#endif /* HAVE_INNETGR */
+
+
+
+#ifndef HAVE_INITGROUPS
+/****************************************************************************
+ some systems don't have an initgroups call
+****************************************************************************/
+ int initgroups(char *name,gid_t id)
+{
+#ifndef HAVE_SETGROUPS
+ static int done;
+ if (!done) {
+ DEBUG(1,("WARNING: running without setgroups\n"));
+ done=1;
+ }
+ /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
+ return(0);
+#else /* HAVE_SETGROUPS */
+ gid_t *grouplst = NULL;
+ int max_gr = groups_max();
+ int ret;
+ int i,j;
+ struct group *g;
+ char *gr;
+
+ if((grouplst = (gid_t *)malloc(sizeof(gid_t) * max_gr)) == NULL) {
+ DEBUG(0,("initgroups: malloc fail !\n"));
+ return -1;
+ }
+
+ grouplst[0] = id;
+ i = 1;
+ while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
+ if (g->gr_gid == id)
+ continue;
+ j = 0;
+ gr = g->gr_mem[0];
+ while (gr && (*gr != (char)NULL)) {
+ if (strcmp(name,gr) == 0) {
+ grouplst[i] = g->gr_gid;
+ i++;
+ gr = (char *)NULL;
+ break;
+ }
+ gr = g->gr_mem[++j];
+ }
+ }
+ endgrent();
+ ret = sys_setgroups(i,grouplst);
+ SAFE_FREE(grouplst);
+ return ret;
+#endif /* HAVE_SETGROUPS */
+}
+#endif /* HAVE_INITGROUPS */
+
+
+#if (defined(SecureWare) && defined(SCO))
+/* This is needed due to needing the nap() function but we don't want
+ to include the Xenix libraries since that will break other things...
+ BTW: system call # 0x0c28 is the same as calling nap() */
+ long nap(long milliseconds) {
+ return syscall(0x0c28, milliseconds);
+ }
+#endif
+
+
+#ifndef HAVE_MEMMOVE
+/*******************************************************************
+safely copies memory, ensuring no overlap problems.
+this is only used if the machine does not have it's own memmove().
+this is not the fastest algorithm in town, but it will do for our
+needs.
+********************************************************************/
+ void *memmove(void *dest,const void *src,int size)
+{
+ unsigned long d,s;
+ int i;
+ if (dest==src || !size) return(dest);
+
+ d = (unsigned long)dest;
+ s = (unsigned long)src;
+
+ if ((d >= (s+size)) || (s >= (d+size))) {
+ /* no overlap */
+ memcpy(dest,src,size);
+ return(dest);
+ }
+
+ if (d < s) {
+ /* we can forward copy */
+ if (s-d >= sizeof(int) &&
+ !(s%sizeof(int)) &&
+ !(d%sizeof(int)) &&
+ !(size%sizeof(int))) {
+ /* do it all as words */
+ int *idest = (int *)dest;
+ int *isrc = (int *)src;
+ size /= sizeof(int);
+ for (i=0;i<size;i++) idest[i] = isrc[i];
+ } else {
+ /* simplest */
+ char *cdest = (char *)dest;
+ char *csrc = (char *)src;
+ for (i=0;i<size;i++) cdest[i] = csrc[i];
+ }
+ } else {
+ /* must backward copy */
+ if (d-s >= sizeof(int) &&
+ !(s%sizeof(int)) &&
+ !(d%sizeof(int)) &&
+ !(size%sizeof(int))) {
+ /* do it all as words */
+ int *idest = (int *)dest;
+ int *isrc = (int *)src;
+ size /= sizeof(int);
+ for (i=size-1;i>=0;i--) idest[i] = isrc[i];
+ } else {
+ /* simplest */
+ char *cdest = (char *)dest;
+ char *csrc = (char *)src;
+ for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
+ }
+ }
+ return(dest);
+}
+#endif /* HAVE_MEMMOVE */
+
+#ifndef HAVE_STRDUP
+/****************************************************************************
+duplicate a string
+****************************************************************************/
+ char *strdup(const char *s)
+{
+ size_t len;
+ char *ret;
+
+ if (!s) return(NULL);
+
+ len = strlen(s)+1;
+ ret = (char *)malloc(len);
+ if (!ret) return(NULL);
+ memcpy(ret,s,len);
+ return(ret);
+}
+#endif /* HAVE_STRDUP */
+
+#ifdef REPLACE_INET_NTOA
+char *rep_inet_ntoa(struct in_addr ip)
+{
+ unsigned char *p = (unsigned char *)&ip.s_addr;
+ static char buf[18];
+#if WORDS_BIGENDIAN
+ slprintf(buf, 17, "%d.%d.%d.%d",
+ (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
+#else /* WORDS_BIGENDIAN */
+ slprintf(buf, 17, "%d.%d.%d.%d",
+ (int)p[3], (int)p[2], (int)p[1], (int)p[0]);
+#endif /* WORDS_BIGENDIAN */
+ return buf;
+}
+#endif /* REPLACE_INET_NTOA */
+
+#ifndef HAVE_STRTOUL
+#ifndef ULONG_MAX
+#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF */
+#endif
+
+/*
+ * Convert a string to an unsigned long integer.
+ * Taken from libg++ - libiberty code.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+ unsigned long strtoul(const char *nptr, char **endptr, int base)
+{
+ const char *s = nptr;
+ unsigned long acc;
+ int c;
+ unsigned long cutoff;
+ int neg = 0, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ do {
+ c = *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else if (c == '+')
+ c = *s++;
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
+ cutlim = (int)((unsigned long)ULONG_MAX % (unsigned long)base);
+ for (acc = 0, any = 0;; c = *s++) {
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULONG_MAX;
+ errno = ERANGE;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != 0)
+ *endptr = (char *) (any ? s - 1 : nptr);
+ return (acc);
+}
+#endif /* HAVE_STRTOUL */
+
+#ifndef HAVE_SETLINEBUF
+ int setlinebuf(FILE *stream)
+{
+ return setvbuf(stream, (char *)NULL, _IOLBF, 0);
+}
+#endif /* HAVE_SETLINEBUF */
diff --git a/source3/lib/select.c b/source3/lib/select.c
new file mode 100644
index 0000000000..550941ba77
--- /dev/null
+++ b/source3/lib/select.c
@@ -0,0 +1,159 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba select/poll implementation
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* This is here because it allows us to avoid a nasty race in signal handling.
+ We need to guarantee that when we get a signal we get out of a select immediately
+ but doing that involves a race condition. We can avoid the race by getting the
+ signal handler to write to a pipe that is in the select/poll list
+
+ This means all Samba signal handlers should call sys_select_signal().
+*/
+
+static pid_t initialised;
+static int select_pipe[2];
+static VOLATILE unsigned pipe_written, pipe_read;
+
+/*******************************************************************
+ Call this from all Samba signal handlers if you want to avoid a
+ nasty signal race condition.
+********************************************************************/
+
+void sys_select_signal(void)
+{
+ char c = 1;
+ if (!initialised) return;
+
+ if (pipe_written > pipe_read+256) return;
+
+ if (write(select_pipe[1], &c, 1) == 1) pipe_written++;
+}
+
+/*******************************************************************
+ Like select() but avoids the signal race using a pipe
+ it also guuarantees that fds on return only ever contains bits set
+ for file descriptors that were readable.
+********************************************************************/
+
+int sys_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval)
+{
+ int ret, saved_errno;
+ fd_set *readfds2, readfds_buf;
+
+ if (initialised != sys_getpid()) {
+ pipe(select_pipe);
+
+ /*
+ * These next two lines seem to fix a bug with the Linux
+ * 2.0.x kernel (and probably other UNIXes as well) where
+ * the one byte read below can block even though the
+ * select returned that there is data in the pipe and
+ * the pipe_written variable was incremented. Thanks to
+ * HP for finding this one. JRA.
+ */
+
+ if(set_blocking(select_pipe[0],0)==-1)
+ smb_panic("select_pipe[0]: O_NONBLOCK failed.\n");
+ if(set_blocking(select_pipe[1],0)==-1)
+ smb_panic("select_pipe[1]: O_NONBLOCK failed.\n");
+
+ initialised = sys_getpid();
+ }
+
+ maxfd = MAX(select_pipe[0]+1, maxfd);
+
+ /* If readfds is NULL we need to provide our own set. */
+ if (readfds) {
+ readfds2 = readfds;
+ } else {
+ readfds2 = &readfds_buf;
+ FD_ZERO(readfds2);
+ }
+ FD_SET(select_pipe[0], readfds2);
+
+ errno = 0;
+ ret = select(maxfd,readfds2,writefds,errorfds,tval);
+
+ if (ret <= 0) {
+ FD_ZERO(readfds2);
+ if (writefds)
+ FD_ZERO(writefds);
+ if (errorfds)
+ FD_ZERO(errorfds);
+ }
+
+ if (FD_ISSET(select_pipe[0], readfds2)) {
+ FD_CLR(select_pipe[0], readfds2);
+ ret--;
+ if (ret == 0) {
+ ret = -1;
+ errno = EINTR;
+ }
+ }
+
+ saved_errno = errno;
+
+ while (pipe_written != pipe_read) {
+ char c;
+ /* Due to the linux kernel bug in 2.0.x, we
+ * always increment here even if the read failed... */
+ read(select_pipe[0], &c, 1);
+ pipe_read++;
+ }
+
+ errno = saved_errno;
+
+ return ret;
+}
+
+/*******************************************************************
+ Similar to sys_select() but catch EINTR and continue.
+ This is what sys_select() used to do in Samba.
+********************************************************************/
+
+int sys_select_intr(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval)
+{
+ int ret;
+ fd_set *readfds2, readfds_buf, *writefds2, writefds_buf, *errorfds2, errorfds_buf;
+
+ readfds2 = (readfds ? &readfds_buf : NULL);
+ writefds2 = (writefds ? &writefds_buf : NULL);
+ errorfds2 = (errorfds ? &errorfds_buf : NULL);
+
+ do {
+ if (readfds)
+ readfds_buf = *readfds;
+ if (writefds)
+ writefds_buf = *writefds;
+ if (errorfds)
+ errorfds_buf = *errorfds;
+ ret = sys_select(maxfd, readfds2, writefds2, errorfds2, tval);
+ } while (ret == -1 && errno == EINTR);
+
+ if (readfds)
+ *readfds = readfds_buf;
+ if (writefds)
+ *writefds = writefds_buf;
+ if (errorfds)
+ *errorfds = errorfds_buf;
+
+ return ret;
+}
diff --git a/source3/lib/signal.c b/source3/lib/signal.c
new file mode 100644
index 0000000000..99f908235c
--- /dev/null
+++ b/source3/lib/signal.c
@@ -0,0 +1,139 @@
+/*
+ Unix SMB/CIFS implementation.
+ signal handling functions
+
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Catch child exits and reap the child zombie status.
+****************************************************************************/
+
+static void sig_cld(int signum)
+{
+ while (sys_waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0)
+ ;
+
+ /*
+ * Turns out it's *really* important not to
+ * restore the signal handler here if we have real POSIX
+ * signal handling. If we do, then we get the signal re-delivered
+ * immediately - hey presto - instant loop ! JRA.
+ */
+
+#if !defined(HAVE_SIGACTION)
+ CatchSignal(SIGCLD, sig_cld);
+#endif
+}
+
+/****************************************************************************
+catch child exits - leave status;
+****************************************************************************/
+
+static void sig_cld_leave_status(int signum)
+{
+ /*
+ * Turns out it's *really* important not to
+ * restore the signal handler here if we have real POSIX
+ * signal handling. If we do, then we get the signal re-delivered
+ * immediately - hey presto - instant loop ! JRA.
+ */
+
+#if !defined(HAVE_SIGACTION)
+ CatchSignal(SIGCLD, sig_cld_leave_status);
+#else
+ ;
+#endif
+}
+
+/*******************************************************************
+ Block sigs.
+********************************************************************/
+
+void BlockSignals(BOOL block,int signum)
+{
+#ifdef HAVE_SIGPROCMASK
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set,signum);
+ sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL);
+#elif defined(HAVE_SIGBLOCK)
+ if (block) {
+ sigblock(sigmask(signum));
+ } else {
+ sigsetmask(siggetmask() & ~sigmask(signum));
+ }
+#else
+ /* yikes! This platform can't block signals? */
+ static int done;
+ if (!done) {
+ DEBUG(0,("WARNING: No signal blocking available\n"));
+ done=1;
+ }
+#endif
+}
+
+/*******************************************************************
+ Catch a signal. This should implement the following semantics:
+
+ 1) The handler remains installed after being called.
+ 2) The signal should be blocked during handler execution.
+********************************************************************/
+
+void CatchSignal(int signum,void (*handler)(int ))
+{
+#ifdef HAVE_SIGACTION
+ struct sigaction act;
+
+ ZERO_STRUCT(act);
+
+ act.sa_handler = handler;
+#ifdef SA_RESTART
+ /*
+ * We *want* SIGALRM to interrupt a system call.
+ */
+ if(signum != SIGALRM)
+ act.sa_flags = SA_RESTART;
+#endif
+ sigemptyset(&act.sa_mask);
+ sigaddset(&act.sa_mask,signum);
+ sigaction(signum,&act,NULL);
+#else /* !HAVE_SIGACTION */
+ /* FIXME: need to handle sigvec and systems with broken signal() */
+ signal(signum, handler);
+#endif
+}
+
+/*******************************************************************
+ Ignore SIGCLD via whatever means is necessary for this OS.
+********************************************************************/
+
+void CatchChild(void)
+{
+ CatchSignal(SIGCLD, sig_cld);
+}
+
+/*******************************************************************
+ Catch SIGCLD but leave the child around so it's status can be reaped.
+********************************************************************/
+
+void CatchChildLeaveStatus(void)
+{
+ CatchSignal(SIGCLD, sig_cld_leave_status);
+}
diff --git a/source3/lib/smbpasswd.c b/source3/lib/smbpasswd.c
new file mode 100644
index 0000000000..c27af5540b
--- /dev/null
+++ b/source3/lib/smbpasswd.c
@@ -0,0 +1,200 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ smbpasswd file format routines
+
+ Copyright (C) Andrew Tridgell 1992-1998
+ Modified by Jeremy Allison 1995.
+ Modified by Gerald (Jerry) Carter 2000-2001
+ Copyright (C) Tim Potter 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*! \file lib/smbpasswd.c
+
+ The smbpasswd file is used to store encrypted passwords in a similar
+ fashion to the /etc/passwd file. The format is colon separated fields
+ with one user per line like so:
+
+ <username>:<uid>:<lanman hash>:<nt hash>:<acb info>:<last change time>
+
+ The username and uid must correspond to an entry in the /etc/passwd
+ file. The lanman and nt password hashes are 32 hex digits corresponding
+ to the 16-byte lanman and nt hashes respectively.
+
+ The password last change time is stored as a string of the format
+ LCD-<change time> where the change time is expressed as an
+
+ 'N' No password
+ 'D' Disabled
+ 'H' Homedir required
+ 'T' Temp account.
+ 'U' User account (normal)
+ 'M' MNS logon user account - what is this ?
+ 'W' Workstation account
+ 'S' Server account
+ 'L' Locked account
+ 'X' No Xpiry on password
+ 'I' Interdomain trust account
+
+*/
+
+#include "includes.h"
+
+/*! Convert 32 hex characters into a 16 byte array. */
+
+BOOL smbpasswd_gethexpwd(char *p, unsigned char *pwd)
+{
+ int i;
+ unsigned char lonybble, hinybble;
+ char *hexchars = "0123456789ABCDEF";
+ char *p1, *p2;
+
+ if (!p) return (False);
+
+ for (i = 0; i < 32; i += 2)
+ {
+ hinybble = toupper(p[i]);
+ lonybble = toupper(p[i + 1]);
+
+ p1 = strchr_m(hexchars, hinybble);
+ p2 = strchr_m(hexchars, lonybble);
+
+ if (!p1 || !p2)
+ {
+ return (False);
+ }
+
+ hinybble = PTR_DIFF(p1, hexchars);
+ lonybble = PTR_DIFF(p2, hexchars);
+
+ pwd[i / 2] = (hinybble << 4) | lonybble;
+ }
+ return (True);
+}
+
+/*! Convert a 16-byte array into 32 hex characters. */
+
+void smbpasswd_sethexpwd(fstring p, unsigned char *pwd, uint16 acb_info)
+{
+ if (pwd != NULL) {
+ int i;
+ for (i = 0; i < 16; i++)
+ slprintf(&p[i*2], 3, "%02X", pwd[i]);
+ } else {
+ if (acb_info & ACB_PWNOTREQ)
+ safe_strcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33);
+ else
+ safe_strcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33);
+ }
+}
+
+/*! Decode the account control bits (ACB) info from a string. */
+
+uint16 smbpasswd_decode_acb_info(const char *p)
+{
+ uint16 acb_info = 0;
+ BOOL finished = False;
+
+ /*
+ * Check if the account type bits have been encoded after the
+ * NT password (in the form [NDHTUWSLXI]).
+ */
+
+ if (*p != '[') return 0;
+
+ for (p++; *p && !finished; p++)
+ {
+ switch (*p) {
+ case 'N': /* 'N'o password. */
+ acb_info |= ACB_PWNOTREQ;
+ break;
+ case 'D': /* 'D'isabled. */
+ acb_info |= ACB_DISABLED;
+ break;
+ case 'H': /* 'H'omedir required. */
+ acb_info |= ACB_HOMDIRREQ;
+ break;
+ case 'T': /* 'T'emp account. */
+ acb_info |= ACB_TEMPDUP;
+ break;
+ case 'U': /* 'U'ser account (normal). */
+ acb_info |= ACB_NORMAL;
+ break;
+ case 'M': /* 'M'NS logon user account. What is this ? */
+ acb_info |= ACB_MNS;
+ break;
+ case 'W': /* 'W'orkstation account. */
+ acb_info |= ACB_WSTRUST;
+ break;
+ case 'S': /* 'S'erver account. */
+ acb_info |= ACB_SVRTRUST;
+ break;
+ case 'L': /* 'L'ocked account. */
+ acb_info |= ACB_AUTOLOCK;
+ break;
+ case 'X': /* No 'X'piry on password */
+ acb_info |= ACB_PWNOEXP;
+ break;
+ case 'I': /* 'I'nterdomain trust account. */
+ acb_info |= ACB_DOMTRUST;
+ break;
+
+ case ' ':
+ break;
+ case ':':
+ case '\n':
+ case '\0':
+ case ']':
+ default:
+ finished = True;
+ break;
+ }
+ }
+
+ return acb_info;
+}
+
+/*! Encode account control bits (ACBs) into a string. */
+
+char *smbpasswd_encode_acb_info(uint16 acb_info)
+{
+ static fstring acct_str;
+ size_t i = 0;
+
+ acct_str[i++] = '[';
+
+ if (acb_info & ACB_PWNOTREQ ) acct_str[i++] = 'N';
+ if (acb_info & ACB_DISABLED ) acct_str[i++] = 'D';
+ if (acb_info & ACB_HOMDIRREQ) acct_str[i++] = 'H';
+ if (acb_info & ACB_TEMPDUP ) acct_str[i++] = 'T';
+ if (acb_info & ACB_NORMAL ) acct_str[i++] = 'U';
+ if (acb_info & ACB_MNS ) acct_str[i++] = 'M';
+ if (acb_info & ACB_WSTRUST ) acct_str[i++] = 'W';
+ if (acb_info & ACB_SVRTRUST ) acct_str[i++] = 'S';
+ if (acb_info & ACB_AUTOLOCK ) acct_str[i++] = 'L';
+ if (acb_info & ACB_PWNOEXP ) acct_str[i++] = 'X';
+ if (acb_info & ACB_DOMTRUST ) acct_str[i++] = 'I';
+
+ for ( ; i < NEW_PW_FORMAT_SPACE_PADDED_LEN - 2 ; i++ )
+ acct_str[i] = ' ';
+
+ i = NEW_PW_FORMAT_SPACE_PADDED_LEN - 2;
+ acct_str[i++] = ']';
+ acct_str[i++] = '\0';
+
+ return acct_str;
+}
diff --git a/source3/lib/smbrun.c b/source3/lib/smbrun.c
new file mode 100644
index 0000000000..67f82ed0ad
--- /dev/null
+++ b/source3/lib/smbrun.c
@@ -0,0 +1,180 @@
+/*
+ Unix SMB/CIFS implementation.
+ run a command as a specified user
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* need to move this from here!! need some sleep ... */
+struct current_user current_user;
+
+/****************************************************************************
+This is a utility function of smbrun().
+****************************************************************************/
+
+static int setup_out_fd(void)
+{
+ int fd;
+ pstring path;
+
+ slprintf(path, sizeof(path)-1, "%s/smb.XXXXXX", tmpdir());
+
+ /* now create the file */
+ fd = smb_mkstemp(path);
+
+ if (fd == -1) {
+ DEBUG(0,("setup_out_fd: Failed to create file %s. (%s)\n",
+ path, strerror(errno) ));
+ return -1;
+ }
+
+ DEBUG(10,("setup_out_fd: Created tmp file %s\n", path ));
+
+ /* Ensure file only kept around by open fd. */
+ unlink(path);
+ return fd;
+}
+
+/****************************************************************************
+run a command being careful about uid/gid handling and putting the output in
+outfd (or discard it if outfd is NULL).
+****************************************************************************/
+
+int smbrun(char *cmd, int *outfd)
+{
+ pid_t pid;
+ uid_t uid = current_user.uid;
+ gid_t gid = current_user.gid;
+
+ /*
+ * Lose any kernel oplock capabilities we may have.
+ */
+ oplock_set_capability(False, False);
+
+ /* point our stdout at the file we want output to go into */
+
+ if (outfd && ((*outfd = setup_out_fd()) == -1)) {
+ return -1;
+ }
+
+ /* in this method we will exec /bin/sh with the correct
+ arguments, after first setting stdout to point at the file */
+
+ /*
+ * We need to temporarily stop CatchChild from eating
+ * SIGCLD signals as it also eats the exit status code. JRA.
+ */
+
+ CatchChildLeaveStatus();
+
+ if ((pid=sys_fork()) < 0) {
+ DEBUG(0,("smbrun: fork failed with error %s\n", strerror(errno) ));
+ CatchChild();
+ if (outfd) {
+ close(*outfd);
+ *outfd = -1;
+ }
+ return errno;
+ }
+
+ if (pid) {
+ /*
+ * Parent.
+ */
+ int status=0;
+ pid_t wpid;
+
+
+ /* the parent just waits for the child to exit */
+ while((wpid = sys_waitpid(pid,&status,0)) < 0) {
+ if(errno == EINTR) {
+ errno = 0;
+ continue;
+ }
+ break;
+ }
+
+ CatchChild();
+
+ if (wpid != pid) {
+ DEBUG(2,("waitpid(%d) : %s\n",(int)pid,strerror(errno)));
+ if (outfd) {
+ close(*outfd);
+ *outfd = -1;
+ }
+ return -1;
+ }
+
+ /* Reset the seek pointer. */
+ if (outfd) {
+ sys_lseek(*outfd, 0, SEEK_SET);
+ }
+
+#if defined(WIFEXITED) && defined(WEXITSTATUS)
+ if (WIFEXITED(status)) {
+ return WEXITSTATUS(status);
+ }
+#endif
+
+ return status;
+ }
+
+ CatchChild();
+
+ /* we are in the child. we exec /bin/sh to do the work for us. we
+ don't directly exec the command we want because it may be a
+ pipeline or anything else the config file specifies */
+
+ /* point our stdout at the file we want output to go into */
+ if (outfd) {
+ close(1);
+ if (dup2(*outfd,1) != 1) {
+ DEBUG(2,("Failed to create stdout file descriptor\n"));
+ close(*outfd);
+ exit(80);
+ }
+ }
+
+ /* now completely lose our privileges. This is a fairly paranoid
+ way of doing it, but it does work on all systems that I know of */
+
+ become_user_permanently(uid, gid);
+
+ if (getuid() != uid || geteuid() != uid ||
+ getgid() != gid || getegid() != gid) {
+ /* we failed to lose our privileges - do not execute
+ the command */
+ exit(81); /* we can't print stuff at this stage,
+ instead use exit codes for debugging */
+ }
+
+#ifndef __INSURE__
+ /* close all other file descriptors, leaving only 0, 1 and 2. 0 and
+ 2 point to /dev/null from the startup code */
+ {
+ int fd;
+ for (fd=3;fd<256;fd++) close(fd);
+ }
+#endif
+
+ execl("/bin/sh","sh","-c",cmd,NULL);
+
+ /* not reached */
+ exit(82);
+ return 1;
+}
diff --git a/source3/lib/snprintf.c b/source3/lib/snprintf.c
new file mode 100644
index 0000000000..9a9dcdbae1
--- /dev/null
+++ b/source3/lib/snprintf.c
@@ -0,0 +1,962 @@
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell@astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh. This sort of thing is always nasty do deal with. Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length. This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ *
+ * More Recently:
+ * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
+ * This was ugly. It is still ugly. I opted out of floating point
+ * numbers, but the formatter understands just about everything
+ * from the normal C string format, at least as far as I can tell from
+ * the Solaris 2.5 printf(3S) man page.
+ *
+ * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
+ * Ok, added some minimal floating point support, which means this
+ * probably requires libm on most operating systems. Don't yet
+ * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
+ * was pretty badly broken, it just wasn't being exercised in ways
+ * which showed it, so that's been fixed. Also, formated the code
+ * to mutt conventions, and removed dead code left over from the
+ * original. Also, there is now a builtin-test, just compile with:
+ * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
+ * and run snprintf for results.
+ *
+ * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
+ * The PGP code was using unsigned hexadecimal formats.
+ * Unfortunately, unsigned formats simply didn't work.
+ *
+ * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
+ * The original code assumed that both snprintf() and vsnprintf() were
+ * missing. Some systems only have snprintf() but not vsnprintf(), so
+ * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ * Andrew Tridgell (tridge@samba.org) Oct 1998
+ * fixed handling of %.0f
+ * added test for HAVE_LONG_DOUBLE
+ *
+ * tridge@samba.org, idra@samba.org, April 2001
+ * got rid of fcvt code (twas buggy and made testing harder)
+ * added C99 semantics
+ *
+ **************************************************************/
+
+#ifndef NO_CONFIG_H /* for some tests */
+#include "config.h"
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#include <sys/types.h>
+#include <stdarg.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
+/* only include stdio.h if we are not re-defining snprintf or vsnprintf */
+#include <stdio.h>
+ /* make the compiler happy with an empty file */
+ void dummy_snprintf(void) {}
+#else
+
+#ifdef HAVE_LONG_DOUBLE
+#define LDOUBLE long double
+#else
+#define LDOUBLE double
+#endif
+
+#ifdef HAVE_LONG_LONG
+#define LLONG long long
+#else
+#define LLONG long
+#endif
+
+static size_t dopr(char *buffer, size_t maxlen, const char *format,
+ va_list args);
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+ char *value, int flags, int min, int max);
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
+ long value, int base, int min, int max, int flags);
+static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
+ LDOUBLE fvalue, int min, int max, int flags);
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS 1
+#define DP_S_MIN 2
+#define DP_S_DOT 3
+#define DP_S_MAX 4
+#define DP_S_MOD 5
+#define DP_S_CONV 6
+#define DP_S_DONE 7
+
+/* format flags - Bits */
+#define DP_F_MINUS (1 << 0)
+#define DP_F_PLUS (1 << 1)
+#define DP_F_SPACE (1 << 2)
+#define DP_F_NUM (1 << 3)
+#define DP_F_ZERO (1 << 4)
+#define DP_F_UP (1 << 5)
+#define DP_F_UNSIGNED (1 << 6)
+
+/* Conversion Flags */
+#define DP_C_SHORT 1
+#define DP_C_LONG 2
+#define DP_C_LDOUBLE 3
+#define DP_C_LLONG 4
+
+#define char_to_int(p) ((p)- '0')
+#ifndef MAX
+#define MAX(p,q) (((p) >= (q)) ? (p) : (q))
+#endif
+
+static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args)
+{
+ char ch;
+ LLONG value;
+ LDOUBLE fvalue;
+ char *strvalue;
+ int min;
+ int max;
+ int state;
+ int flags;
+ int cflags;
+ size_t currlen;
+
+ state = DP_S_DEFAULT;
+ currlen = flags = cflags = min = 0;
+ max = -1;
+ ch = *format++;
+
+ while (state != DP_S_DONE) {
+ if (ch == '\0')
+ state = DP_S_DONE;
+
+ switch(state) {
+ case DP_S_DEFAULT:
+ if (ch == '%')
+ state = DP_S_FLAGS;
+ else
+ dopr_outch (buffer, &currlen, maxlen, ch);
+ ch = *format++;
+ break;
+ case DP_S_FLAGS:
+ switch (ch) {
+ case '-':
+ flags |= DP_F_MINUS;
+ ch = *format++;
+ break;
+ case '+':
+ flags |= DP_F_PLUS;
+ ch = *format++;
+ break;
+ case ' ':
+ flags |= DP_F_SPACE;
+ ch = *format++;
+ break;
+ case '#':
+ flags |= DP_F_NUM;
+ ch = *format++;
+ break;
+ case '0':
+ flags |= DP_F_ZERO;
+ ch = *format++;
+ break;
+ default:
+ state = DP_S_MIN;
+ break;
+ }
+ break;
+ case DP_S_MIN:
+ if (isdigit((unsigned char)ch)) {
+ min = 10*min + char_to_int (ch);
+ ch = *format++;
+ } else if (ch == '*') {
+ min = va_arg (args, int);
+ ch = *format++;
+ state = DP_S_DOT;
+ } else {
+ state = DP_S_DOT;
+ }
+ break;
+ case DP_S_DOT:
+ if (ch == '.') {
+ state = DP_S_MAX;
+ ch = *format++;
+ } else {
+ state = DP_S_MOD;
+ }
+ break;
+ case DP_S_MAX:
+ if (isdigit((unsigned char)ch)) {
+ if (max < 0)
+ max = 0;
+ max = 10*max + char_to_int (ch);
+ ch = *format++;
+ } else if (ch == '*') {
+ max = va_arg (args, int);
+ ch = *format++;
+ state = DP_S_MOD;
+ } else {
+ state = DP_S_MOD;
+ }
+ break;
+ case DP_S_MOD:
+ switch (ch) {
+ case 'h':
+ cflags = DP_C_SHORT;
+ ch = *format++;
+ break;
+ case 'l':
+ cflags = DP_C_LONG;
+ ch = *format++;
+ if (ch == 'l') { /* It's a long long */
+ cflags = DP_C_LLONG;
+ ch = *format++;
+ }
+ break;
+ case 'L':
+ cflags = DP_C_LDOUBLE;
+ ch = *format++;
+ break;
+ default:
+ break;
+ }
+ state = DP_S_CONV;
+ break;
+ case DP_S_CONV:
+ switch (ch) {
+ case 'd':
+ case 'i':
+ if (cflags == DP_C_SHORT)
+ value = va_arg (args, int);
+ else if (cflags == DP_C_LONG)
+ value = va_arg (args, long int);
+ else if (cflags == DP_C_LLONG)
+ value = va_arg (args, LLONG);
+ else
+ value = va_arg (args, int);
+ fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+ break;
+ case 'o':
+ flags |= DP_F_UNSIGNED;
+ if (cflags == DP_C_SHORT)
+ value = va_arg (args, unsigned int);
+ else if (cflags == DP_C_LONG)
+ value = (long)va_arg (args, unsigned long int);
+ else if (cflags == DP_C_LLONG)
+ value = (long)va_arg (args, unsigned LLONG);
+ else
+ value = (long)va_arg (args, unsigned int);
+ fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
+ break;
+ case 'u':
+ flags |= DP_F_UNSIGNED;
+ if (cflags == DP_C_SHORT)
+ value = va_arg (args, unsigned int);
+ else if (cflags == DP_C_LONG)
+ value = (long)va_arg (args, unsigned long int);
+ else if (cflags == DP_C_LLONG)
+ value = (LLONG)va_arg (args, unsigned LLONG);
+ else
+ value = (long)va_arg (args, unsigned int);
+ fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+ break;
+ case 'X':
+ flags |= DP_F_UP;
+ case 'x':
+ flags |= DP_F_UNSIGNED;
+ if (cflags == DP_C_SHORT)
+ value = va_arg (args, unsigned int);
+ else if (cflags == DP_C_LONG)
+ value = (long)va_arg (args, unsigned long int);
+ else if (cflags == DP_C_LLONG)
+ value = (LLONG)va_arg (args, unsigned LLONG);
+ else
+ value = (long)va_arg (args, unsigned int);
+ fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
+ break;
+ case 'f':
+ if (cflags == DP_C_LDOUBLE)
+ fvalue = va_arg (args, LDOUBLE);
+ else
+ fvalue = va_arg (args, double);
+ /* um, floating point? */
+ fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
+ break;
+ case 'E':
+ flags |= DP_F_UP;
+ case 'e':
+ if (cflags == DP_C_LDOUBLE)
+ fvalue = va_arg (args, LDOUBLE);
+ else
+ fvalue = va_arg (args, double);
+ break;
+ case 'G':
+ flags |= DP_F_UP;
+ case 'g':
+ if (cflags == DP_C_LDOUBLE)
+ fvalue = va_arg (args, LDOUBLE);
+ else
+ fvalue = va_arg (args, double);
+ break;
+ case 'c':
+ dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
+ break;
+ case 's':
+ strvalue = va_arg (args, char *);
+ if (!strvalue) strvalue = "(NULL)";
+ if (max == -1) {
+ max = strlen(strvalue);
+ }
+ if (min > 0 && max >= 0 && min > max) max = min;
+ fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
+ break;
+ case 'p':
+ strvalue = va_arg (args, void *);
+ fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
+ break;
+ case 'n':
+ if (cflags == DP_C_SHORT) {
+ short int *num;
+ num = va_arg (args, short int *);
+ *num = currlen;
+ } else if (cflags == DP_C_LONG) {
+ long int *num;
+ num = va_arg (args, long int *);
+ *num = (long int)currlen;
+ } else if (cflags == DP_C_LLONG) {
+ LLONG *num;
+ num = va_arg (args, LLONG *);
+ *num = (LLONG)currlen;
+ } else {
+ int *num;
+ num = va_arg (args, int *);
+ *num = currlen;
+ }
+ break;
+ case '%':
+ dopr_outch (buffer, &currlen, maxlen, ch);
+ break;
+ case 'w':
+ /* not supported yet, treat as next char */
+ ch = *format++;
+ break;
+ default:
+ /* Unknown, skip */
+ break;
+ }
+ ch = *format++;
+ state = DP_S_DEFAULT;
+ flags = cflags = min = 0;
+ max = -1;
+ break;
+ case DP_S_DONE:
+ break;
+ default:
+ /* hmm? */
+ break; /* some picky compilers need this */
+ }
+ }
+ if (maxlen != 0) {
+ if (currlen < maxlen - 1)
+ buffer[currlen] = '\0';
+ else if (maxlen > 0)
+ buffer[maxlen - 1] = '\0';
+ }
+
+ return currlen;
+}
+
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+ char *value, int flags, int min, int max)
+{
+ int padlen, strln; /* amount to pad */
+ int cnt = 0;
+
+#ifdef DEBUG_SNPRINTF
+ printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
+#endif
+ if (value == 0) {
+ value = "<NULL>";
+ }
+
+ for (strln = 0; value[strln]; ++strln); /* strlen */
+ padlen = min - strln;
+ if (padlen < 0)
+ padlen = 0;
+ if (flags & DP_F_MINUS)
+ padlen = -padlen; /* Left Justify */
+
+ while ((padlen > 0) && (cnt < max)) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ --padlen;
+ ++cnt;
+ }
+ while (*value && (cnt < max)) {
+ dopr_outch (buffer, currlen, maxlen, *value++);
+ ++cnt;
+ }
+ while ((padlen < 0) && (cnt < max)) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ ++padlen;
+ ++cnt;
+ }
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
+ long value, int base, int min, int max, int flags)
+{
+ int signvalue = 0;
+ unsigned long uvalue;
+ char convert[20];
+ int place = 0;
+ int spadlen = 0; /* amount to space pad */
+ int zpadlen = 0; /* amount to zero pad */
+ int caps = 0;
+
+ if (max < 0)
+ max = 0;
+
+ uvalue = value;
+
+ if(!(flags & DP_F_UNSIGNED)) {
+ if( value < 0 ) {
+ signvalue = '-';
+ uvalue = -value;
+ } else {
+ if (flags & DP_F_PLUS) /* Do a sign (+/i) */
+ signvalue = '+';
+ else if (flags & DP_F_SPACE)
+ signvalue = ' ';
+ }
+ }
+
+ if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+
+ do {
+ convert[place++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")
+ [uvalue % (unsigned)base ];
+ uvalue = (uvalue / (unsigned)base );
+ } while(uvalue && (place < 20));
+ if (place == 20) place--;
+ convert[place] = 0;
+
+ zpadlen = max - place;
+ spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
+ if (zpadlen < 0) zpadlen = 0;
+ if (spadlen < 0) spadlen = 0;
+ if (flags & DP_F_ZERO) {
+ zpadlen = MAX(zpadlen, spadlen);
+ spadlen = 0;
+ }
+ if (flags & DP_F_MINUS)
+ spadlen = -spadlen; /* Left Justifty */
+
+#ifdef DEBUG_SNPRINTF
+ printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
+ zpadlen, spadlen, min, max, place);
+#endif
+
+ /* Spaces */
+ while (spadlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ --spadlen;
+ }
+
+ /* Sign */
+ if (signvalue)
+ dopr_outch (buffer, currlen, maxlen, signvalue);
+
+ /* Zeros */
+ if (zpadlen > 0) {
+ while (zpadlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, '0');
+ --zpadlen;
+ }
+ }
+
+ /* Digits */
+ while (place > 0)
+ dopr_outch (buffer, currlen, maxlen, convert[--place]);
+
+ /* Left Justified spaces */
+ while (spadlen < 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ ++spadlen;
+ }
+}
+
+static LDOUBLE abs_val(LDOUBLE value)
+{
+ LDOUBLE result = value;
+
+ if (value < 0)
+ result = -value;
+
+ return result;
+}
+
+static LDOUBLE POW10(int exp)
+{
+ LDOUBLE result = 1;
+
+ while (exp) {
+ result *= 10;
+ exp--;
+ }
+
+ return result;
+}
+
+static LLONG ROUND(LDOUBLE value)
+{
+ LLONG intpart;
+
+ intpart = (LLONG)value;
+ value = value - intpart;
+ if (value >= 0.5) intpart++;
+
+ return intpart;
+}
+
+/* a replacement for modf that doesn't need the math library. Should
+ be portable, but slow */
+static double my_modf(double x0, double *iptr)
+{
+ int i;
+ long l;
+ double x = x0;
+ double f = 1.0;
+
+ for (i=0;i<100;i++) {
+ l = (long)x;
+ if (l <= (x+1) && l >= (x-1)) break;
+ x *= 0.1;
+ f *= 10.0;
+ }
+
+ if (i == 100) {
+ /* yikes! the number is beyond what we can handle. What do we do? */
+ (*iptr) = 0;
+ return 0;
+ }
+
+ if (i != 0) {
+ double i2;
+ double ret;
+
+ ret = my_modf(x0-l*f, &i2);
+ (*iptr) = l*f + i2;
+ return ret;
+ }
+
+ (*iptr) = l;
+ return x - (*iptr);
+}
+
+
+static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
+ LDOUBLE fvalue, int min, int max, int flags)
+{
+ int signvalue = 0;
+ double ufvalue;
+ char iconvert[311];
+ char fconvert[311];
+ int iplace = 0;
+ int fplace = 0;
+ int padlen = 0; /* amount to pad */
+ int zpadlen = 0;
+ int caps = 0;
+ int index;
+ double intpart;
+ double fracpart;
+ double temp;
+
+ /*
+ * AIX manpage says the default is 0, but Solaris says the default
+ * is 6, and sprintf on AIX defaults to 6
+ */
+ if (max < 0)
+ max = 6;
+
+ ufvalue = abs_val (fvalue);
+
+ if (fvalue < 0) {
+ signvalue = '-';
+ } else {
+ if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
+ signvalue = '+';
+ } else {
+ if (flags & DP_F_SPACE)
+ signvalue = ' ';
+ }
+ }
+
+#if 0
+ if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+#endif
+
+#if 0
+ if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
+#endif
+
+ /*
+ * Sorry, we only support 16 digits past the decimal because of our
+ * conversion method
+ */
+ if (max > 16)
+ max = 16;
+
+ /* We "cheat" by converting the fractional part to integer by
+ * multiplying by a factor of 10
+ */
+
+ temp = ufvalue;
+ my_modf(temp, &intpart);
+
+ fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
+
+ if (fracpart >= POW10(max)) {
+ intpart++;
+ fracpart -= POW10(max);
+ }
+
+
+ /* Convert integer part */
+ do {
+ temp = intpart;
+ my_modf(intpart*0.1, &intpart);
+ temp = temp*0.1;
+ index = (int) ((temp -intpart +0.05)* 10.0);
+ /* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
+ /* printf ("%llf, %f, %x\n", temp, intpart, index); */
+ iconvert[iplace++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
+ } while (intpart && (iplace < 311));
+ if (iplace == 311) iplace--;
+ iconvert[iplace] = 0;
+
+ /* Convert fractional part */
+ if (fracpart)
+ {
+ do {
+ temp = fracpart;
+ my_modf(fracpart*0.1, &fracpart);
+ temp = temp*0.1;
+ index = (int) ((temp -fracpart +0.05)* 10.0);
+ /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */
+ /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */
+ fconvert[fplace++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
+ } while(fracpart && (fplace < 311));
+ if (fplace == 311) fplace--;
+ }
+ fconvert[fplace] = 0;
+
+ /* -1 for decimal point, another -1 if we are printing a sign */
+ padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
+ zpadlen = max - fplace;
+ if (zpadlen < 0) zpadlen = 0;
+ if (padlen < 0)
+ padlen = 0;
+ if (flags & DP_F_MINUS)
+ padlen = -padlen; /* Left Justifty */
+
+ if ((flags & DP_F_ZERO) && (padlen > 0)) {
+ if (signvalue) {
+ dopr_outch (buffer, currlen, maxlen, signvalue);
+ --padlen;
+ signvalue = 0;
+ }
+ while (padlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, '0');
+ --padlen;
+ }
+ }
+ while (padlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ --padlen;
+ }
+ if (signvalue)
+ dopr_outch (buffer, currlen, maxlen, signvalue);
+
+ while (iplace > 0)
+ dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
+
+#ifdef DEBUG_SNPRINTF
+ printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
+#endif
+
+ /*
+ * Decimal point. This should probably use locale to find the correct
+ * char to print out.
+ */
+ if (max > 0) {
+ dopr_outch (buffer, currlen, maxlen, '.');
+
+ while (fplace > 0)
+ dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
+ }
+
+ while (zpadlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, '0');
+ --zpadlen;
+ }
+
+ while (padlen < 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ ++padlen;
+ }
+}
+
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
+{
+ if (*currlen < maxlen) {
+ buffer[(*currlen)] = c;
+ }
+ (*currlen)++;
+}
+
+/* yes this really must be a ||. Don't muck with this (tridge) */
+#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+ int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
+{
+ return dopr(str, count, fmt, args);
+}
+#endif
+
+/* yes this really must be a ||. Don't muck wiith this (tridge)
+ *
+ * The logic for these two is that we need our own definition if the
+ * OS *either* has no definition of *sprintf, or if it does have one
+ * that doesn't work properly according to the autoconf test. Perhaps
+ * these should really be smb_snprintf to avoid conflicts with buggy
+ * linkers? -- mbp
+ */
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_SNPRINTF)
+ int snprintf(char *str,size_t count,const char *fmt,...)
+{
+ size_t ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(str, count, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+#endif
+
+#endif
+
+#ifndef HAVE_VASPRINTF
+ int vasprintf(char **ptr, const char *format, va_list ap)
+{
+ int ret;
+
+ ret = vsnprintf(NULL, 0, format, ap);
+ if (ret <= 0) return ret;
+
+ (*ptr) = (char *)malloc(ret+1);
+ if (!*ptr) return -1;
+ ret = vsnprintf(*ptr, ret+1, format, ap);
+
+ return ret;
+}
+#endif
+
+
+#ifndef HAVE_ASPRINTF
+ int asprintf(char **ptr, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ *ptr = NULL;
+ va_start(ap, format);
+ ret = vasprintf(ptr, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+#endif
+
+#ifndef HAVE_VSYSLOG
+#ifdef HAVE_SYSLOG
+ void vsyslog (int facility_priority, char *format, va_list arglist)
+{
+ char *msg = NULL;
+ vasprintf(&msg, format, arglist);
+ if (!msg)
+ return;
+ syslog(facility_priority, "%s", msg);
+ free(msg);
+}
+#endif /* HAVE_SYSLOG */
+#endif /* HAVE_VSYSLOG */
+
+#ifdef TEST_SNPRINTF
+
+ int sprintf(char *str,const char *fmt,...);
+
+ int main (void)
+{
+ char buf1[1024];
+ char buf2[1024];
+ char *fp_fmt[] = {
+ "%1.1f",
+ "%-1.5f",
+ "%1.5f",
+ "%123.9f",
+ "%10.5f",
+ "% 10.5f",
+ "%+22.9f",
+ "%+4.9f",
+ "%01.3f",
+ "%4f",
+ "%3.1f",
+ "%3.2f",
+ "%.0f",
+ "%f",
+ "-16.16f",
+ NULL
+ };
+ double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
+ 0.9996, 1.996, 4.136, 0};
+ char *int_fmt[] = {
+ "%-1.5d",
+ "%1.5d",
+ "%123.9d",
+ "%5.5d",
+ "%10.5d",
+ "% 10.5d",
+ "%+22.33d",
+ "%01.3d",
+ "%4d",
+ "%d",
+ NULL
+ };
+ long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
+ char *str_fmt[] = {
+ "10.5s",
+ "5.10s",
+ "10.1s",
+ "0.10s",
+ "10.0s",
+ "1.10s",
+ "%s",
+ "%.1s",
+ "%.10s",
+ "%10s",
+ NULL
+ };
+ char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
+ int x, y;
+ int fail = 0;
+ int num = 0;
+
+ printf ("Testing snprintf format codes against system sprintf...\n");
+
+ for (x = 0; fp_fmt[x] ; x++) {
+ for (y = 0; fp_nums[y] != 0 ; y++) {
+ int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]);
+ int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
+ sprintf (buf2, fp_fmt[x], fp_nums[y]);
+ if (strcmp (buf1, buf2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
+ fp_fmt[x], buf1, buf2);
+ fail++;
+ }
+ if (l1 != l2) {
+ printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]);
+ fail++;
+ }
+ num++;
+ }
+ }
+
+ for (x = 0; int_fmt[x] ; x++) {
+ for (y = 0; int_nums[y] != 0 ; y++) {
+ int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]);
+ int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
+ sprintf (buf2, int_fmt[x], int_nums[y]);
+ if (strcmp (buf1, buf2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
+ int_fmt[x], buf1, buf2);
+ fail++;
+ }
+ if (l1 != l2) {
+ printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]);
+ fail++;
+ }
+ num++;
+ }
+ }
+
+ for (x = 0; str_fmt[x] ; x++) {
+ for (y = 0; str_vals[y] != 0 ; y++) {
+ int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]);
+ int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
+ sprintf (buf2, str_fmt[x], str_vals[y]);
+ if (strcmp (buf1, buf2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
+ str_fmt[x], buf1, buf2);
+ fail++;
+ }
+ if (l1 != l2) {
+ printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]);
+ fail++;
+ }
+ num++;
+ }
+ }
+
+ printf ("%d tests failed out of %d.\n", fail, num);
+
+ printf("seeing how many digits we support\n");
+ {
+ double v0 = 0.12345678901234567890123456789012345678901;
+ for (x=0; x<100; x++) {
+ snprintf(buf1, sizeof(buf1), "%1.1f", v0*pow(10, x));
+ sprintf(buf2, "%1.1f", v0*pow(10, x));
+ if (strcmp(buf1, buf2)) {
+ printf("we seem to support %d digits\n", x-1);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+#endif /* SNPRINTF_TEST */
diff --git a/source3/lib/substitute.c b/source3/lib/substitute.c
new file mode 100644
index 0000000000..e878ee8cbf
--- /dev/null
+++ b/source3/lib/substitute.c
@@ -0,0 +1,358 @@
+/*
+ Unix SMB/CIFS implementation.
+ string substitution functions
+ Copyright (C) Andrew Tridgell 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#include "includes.h"
+
+fstring local_machine="";
+fstring remote_arch="UNKNOWN";
+userdom_struct current_user_info;
+fstring remote_proto="UNKNOWN";
+fstring remote_machine="";
+extern pstring global_myname;
+
+/*******************************************************************
+ Given a pointer to a %$(NAME) expand it as an environment variable.
+ Return the number of characters by which the pointer should be advanced.
+ Based on code by Branko Cibej <branko.cibej@hermes.si>
+ When this is called p points at the '%' character.
+********************************************************************/
+
+static size_t expand_env_var(char *p, int len)
+{
+ fstring envname;
+ char *envval;
+ char *q, *r;
+ int copylen;
+
+ if (p[1] != '$')
+ return 1;
+
+ if (p[2] != '(')
+ return 2;
+
+ /*
+ * Look for the terminating ')'.
+ */
+
+ if ((q = strchr_m(p,')')) == NULL) {
+ DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p));
+ return 2;
+ }
+
+ /*
+ * Extract the name from within the %$(NAME) string.
+ */
+
+ r = p+3;
+ copylen = MIN((q-r),(sizeof(envname)-1));
+ strncpy(envname,r,copylen);
+ envname[copylen] = '\0';
+
+ if ((envval = getenv(envname)) == NULL) {
+ DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname));
+ return 2;
+ }
+
+ /*
+ * Copy the full %$(NAME) into envname so it
+ * can be replaced.
+ */
+
+ copylen = MIN((q+1-p),(sizeof(envname)-1));
+ strncpy(envname,p,copylen);
+ envname[copylen] = '\0';
+ string_sub(p,envname,envval,len);
+ return 0; /* Allow the environment contents to be parsed. */
+}
+
+/*******************************************************************
+ Patch from jkf@soton.ac.uk
+ Added this to implement %p (NIS auto-map version of %H)
+*******************************************************************/
+
+static char *automount_path(const char *user_name)
+{
+ static pstring server_path;
+
+ /* use the passwd entry as the default */
+ /* this will be the default if WITH_AUTOMOUNT is not used or fails */
+
+ pstrcpy(server_path, get_user_home_dir(user_name));
+
+#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
+
+ if (lp_nis_home_map()) {
+ char *home_path_start;
+ char *automount_value = automount_lookup(user_name);
+
+ if(strlen(automount_value) > 0) {
+ home_path_start = strchr_m(automount_value,':');
+ if (home_path_start != NULL) {
+ DEBUG(5, ("NIS lookup succeeded. Home path is: %s\n",
+ home_path_start?(home_path_start+1):""));
+ pstrcpy(server_path, home_path_start+1);
+ }
+ } else {
+ /* NIS key lookup failed: default to user home directory from password file */
+ DEBUG(5, ("NIS lookup failed. Using Home path from passwd file. Home path is: %s\n", server_path ));
+ }
+ }
+#endif
+
+ DEBUG(4,("Home server path: %s\n", server_path));
+
+ return server_path;
+}
+
+/*******************************************************************
+ Patch from jkf@soton.ac.uk
+ This is Luke's original function with the NIS lookup code
+ moved out to a separate function.
+*******************************************************************/
+
+static char *automount_server(const char *user_name)
+{
+ static pstring server_name;
+
+ /* use the local machine name as the default */
+ /* this will be the default if WITH_AUTOMOUNT is not used or fails */
+ if (*local_machine)
+ pstrcpy(server_name, local_machine);
+ else
+ pstrcpy(server_name, global_myname);
+
+#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
+
+ if (lp_nis_home_map()) {
+ int home_server_len;
+ char *automount_value = automount_lookup(user_name);
+ home_server_len = strcspn(automount_value,":");
+ DEBUG(5, ("NIS lookup succeeded. Home server length: %d\n",home_server_len));
+ if (home_server_len > sizeof(pstring))
+ home_server_len = sizeof(pstring);
+ strncpy(server_name, automount_value, home_server_len);
+ server_name[home_server_len] = '\0';
+ }
+#endif
+
+ DEBUG(4,("Home server: %s\n", server_name));
+
+ return server_name;
+}
+
+/****************************************************************************
+ Do some standard substitutions in a string.
+****************************************************************************/
+
+void standard_sub_basic(const char *smb_name, char *str)
+{
+ char *p, *s;
+ fstring pidstr;
+ struct passwd *pass;
+
+ for (s=str; (p=strchr_m(s, '%'));s=p) {
+ fstring tmp_str;
+
+ int l = sizeof(pstring) - (int)(p-str);
+
+ switch (*(p+1)) {
+ case 'U' :
+ fstrcpy(tmp_str, smb_name);
+ strlower(tmp_str);
+ string_sub(p,"%U",tmp_str,l);
+ break;
+ case 'G' :
+ fstrcpy(tmp_str, smb_name);
+ if ((pass = Get_Pwnam(tmp_str))!=NULL) {
+ string_sub(p,"%G",gidtoname(pass->pw_gid),l);
+ } else {
+ p += 2;
+ }
+ break;
+ case 'D' :
+ fstrcpy(tmp_str, current_user_info.domain);
+ strupper(tmp_str);
+ string_sub(p,"%D", tmp_str,l);
+ break;
+ case 'I' : string_sub(p,"%I", client_addr(),l); break;
+ case 'L' :
+ if (*local_machine) {
+ string_sub(p,"%L", local_machine,l);
+ } else {
+ string_sub(p,"%L", global_myname,l);
+ }
+ break;
+ case 'M' : string_sub(p,"%M", client_name(),l); break;
+ case 'R' : string_sub(p,"%R", remote_proto,l); break;
+ case 'T' : string_sub(p,"%T", timestring(False),l); break;
+ case 'a' : string_sub(p,"%a", remote_arch,l); break;
+ case 'd' :
+ slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)sys_getpid());
+ string_sub(p,"%d", pidstr,l);
+ break;
+ case 'h' : string_sub(p,"%h", myhostname(),l); break;
+ case 'm' : string_sub(p,"%m", remote_machine,l); break;
+ case 'v' : string_sub(p,"%v", VERSION,l); break;
+ case '$' : p += expand_env_var(p,l); break; /* Expand environment variables */
+ case '\0':
+ p++;
+ break; /* don't run off the end of the string */
+
+ default: p+=2;
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+ Do some standard substitutions in a string.
+****************************************************************************/
+
+void standard_sub_advanced(int snum, const char *user, const char *connectpath, gid_t gid, const char *smb_name, char *str)
+{
+ char *p, *s, *home;
+
+ for (s=str; (p=strchr_m(s, '%'));s=p) {
+ int l = sizeof(pstring) - (int)(p-str);
+
+ switch (*(p+1)) {
+ case 'N' : string_sub(p,"%N", automount_server(user),l); break;
+ case 'H':
+ if ((home = get_user_home_dir(user))) {
+ string_sub(p,"%H",home, l);
+ } else {
+ p += 2;
+ }
+ break;
+ case 'P':
+ string_sub(p,"%P", connectpath, l);
+ break;
+
+ case 'S':
+ string_sub(p,"%S", lp_servicename(snum), l);
+ break;
+
+ case 'g':
+ string_sub(p,"%g", gidtoname(gid), l);
+ break;
+ case 'u':
+ string_sub(p,"%u", user, l);
+ break;
+
+ /* Patch from jkf@soton.ac.uk Left the %N (NIS
+ * server name) in standard_sub_basic as it is
+ * a feature for logon servers, hence uses the
+ * username. The %p (NIS server path) code is
+ * here as it is used instead of the default
+ * "path =" string in [homes] and so needs the
+ * service name, not the username. */
+ case 'p':
+ string_sub(p,"%p", automount_path(lp_servicename(snum)), l);
+ break;
+ case '\0':
+ p++;
+ break; /* don't run off the end of the string */
+
+ default: p+=2;
+ break;
+ }
+ }
+
+ standard_sub_basic(smb_name, str);
+}
+
+/****************************************************************************
+ Do some standard substitutions in a string.
+****************************************************************************/
+
+void standard_sub_conn(connection_struct *conn, char *str)
+{
+ standard_sub_advanced(SNUM(conn), conn->user, conn->connectpath, conn->gid, current_user_info.smb_name, str);
+}
+
+/****************************************************************************
+ Like standard_sub but for a homes share where snum still points to the [homes]
+ share. No user specific snum created yet so servicename should be the username.
+****************************************************************************/
+
+void standard_sub_home(int snum, const char *user, char *str)
+{
+ char *p, *s;
+
+ for (s=str; (p=strchr_m(s, '%'));s=p) {
+ int l = sizeof(pstring) - (int)(p-str);
+
+ switch (*(p+1)) {
+ case 'S':
+ string_sub(p,"%S", user, l);
+ break;
+ case 'p':
+ string_sub(p,"%p", automount_path(user), l);
+ break;
+ case '\0':
+ p++;
+ break; /* don't run off the end of the string */
+
+ default: p+=2;
+ break;
+ }
+ }
+
+ standard_sub_advanced(snum, user, "", -1, current_user_info.smb_name, str);
+}
+
+/****************************************************************************
+ Like standard_sub but by snum.
+****************************************************************************/
+
+void standard_sub_snum(int snum, char *str)
+{
+ extern struct current_user current_user;
+ static uid_t cached_uid = -1;
+ static fstring cached_user;
+ /* calling uidtoname() on every substitute would be too expensive, so
+ we cache the result here as nearly every call is for the same uid */
+
+ if (cached_uid != current_user.uid) {
+ fstrcpy(cached_user, uidtoname(current_user.uid));
+ cached_uid = current_user.uid;
+ }
+
+ standard_sub_advanced(snum, cached_user, "", -1, current_user_info.smb_name, str);
+}
+
+/*******************************************************************
+ Substitute strings with useful parameters.
+********************************************************************/
+
+void standard_sub_vuser(char *str, user_struct *vuser)
+{
+ standard_sub_advanced(-1, vuser->user.unix_name, "", -1, current_user_info.smb_name, str);
+}
+
+/*******************************************************************
+ Substitute strings with useful parameters.
+********************************************************************/
+
+void standard_sub_vsnum(char *str, user_struct *vuser, int snum)
+{
+ standard_sub_advanced(snum, vuser->user.unix_name, "", -1, current_user_info.smb_name, str);
+}
diff --git a/source3/lib/sysacls.c b/source3/lib/sysacls.c
new file mode 100644
index 0000000000..22245992f5
--- /dev/null
+++ b/source3/lib/sysacls.c
@@ -0,0 +1,3210 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba system utilities for ACL support.
+ Copyright (C) Jeremy Allison 2000.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ This file wraps all differing system ACL interfaces into a consistent
+ one based on the POSIX interface. It also returns the correct errors
+ for older UNIX systems that don't support ACLs.
+
+ The interfaces that each ACL implementation must support are as follows :
+
+ int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+ int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
+ int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p
+ void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
+ SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
+ SMB_ACL_T sys_acl_get_fd(int fd)
+ int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset);
+ int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
+ char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen)
+ SMB_ACL_T sys_acl_init( int count)
+ int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
+ int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
+ int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
+ int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
+ int sys_acl_valid( SMB_ACL_T theacl )
+ int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
+ int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
+ int sys_acl_delete_def_file(const char *path)
+
+ This next one is not POSIX complient - but we *have* to have it !
+ More POSIX braindamage.
+
+ int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+
+ The generic POSIX free is the following call. We split this into
+ several different free functions as we may need to add tag info
+ to structures when emulating the POSIX interface.
+
+ int sys_acl_free( void *obj_p)
+
+ The calls we actually use are :
+
+ int sys_acl_free_text(char *text) - free acl_to_text
+ int sys_acl_free_acl(SMB_ACL_T posix_acl)
+ int sys_acl_free_qualifier(void *qualifier, SMB_ACL_TAG_T tagtype)
+
+*/
+
+#if defined(HAVE_POSIX_ACLS)
+
+/* Identity mapping - easy. */
+
+int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+{
+ return acl_get_entry( the_acl, entry_id, entry_p);
+}
+
+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
+{
+ return acl_get_tag_type( entry_d, tag_type_p);
+}
+
+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
+{
+ return acl_get_permset( entry_d, permset_p);
+}
+
+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
+{
+ return acl_get_qualifier( entry_d);
+}
+
+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
+{
+ return acl_get_file( path_p, type);
+}
+
+SMB_ACL_T sys_acl_get_fd(int fd)
+{
+ return acl_get_fd(fd);
+}
+
+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
+{
+ return acl_clear_perms(permset);
+}
+
+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+ return acl_add_perm(permset, perm);
+}
+
+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+#if defined(HAVE_ACL_GET_PERM_NP)
+ /*
+ * Required for TrustedBSD-based ACL implementations where
+ * non-POSIX.1e functions are denoted by a _np (non-portable)
+ * suffix.
+ */
+ return acl_get_perm_np(permset, perm);
+#else
+ return acl_get_perm(permset, perm);
+#endif
+}
+
+char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
+{
+ return acl_to_text( the_acl, plen);
+}
+
+SMB_ACL_T sys_acl_init( int count)
+{
+ return acl_init(count);
+}
+
+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
+{
+ return acl_create_entry(pacl, pentry);
+}
+
+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
+{
+ return acl_set_tag_type(entry, tagtype);
+}
+
+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
+{
+ return acl_set_qualifier(entry, qual);
+}
+
+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
+{
+ return acl_set_permset(entry, permset);
+}
+
+int sys_acl_valid( SMB_ACL_T theacl )
+{
+ return acl_valid(theacl);
+}
+
+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
+{
+ return acl_set_file(name, acltype, theacl);
+}
+
+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
+{
+ return acl_set_fd(fd, theacl);
+}
+
+int sys_acl_delete_def_file(const char *name)
+{
+ return acl_delete_def_file(name);
+}
+
+int sys_acl_free_text(char *text)
+{
+ return acl_free(text);
+}
+
+int sys_acl_free_acl(SMB_ACL_T the_acl)
+{
+ return acl_free(the_acl);
+}
+
+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
+{
+ return acl_free(qual);
+}
+
+#elif defined(HAVE_TRU64_ACLS)
+/*
+ * The interface to DEC/Compaq Tru64 UNIX ACLs
+ * is based on Draft 13 of the POSIX spec which is
+ * slightly different from the Draft 16 interface.
+ *
+ * Also, some of the permset manipulation functions
+ * such as acl_clear_perm() and acl_add_perm() appear
+ * to be broken on Tru64 so we have to manipulate
+ * the permission bits in the permset directly.
+ */
+int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+{
+ SMB_ACL_ENTRY_T entry;
+
+ if (entry_id == SMB_ACL_FIRST_ENTRY && acl_first_entry(the_acl) != 0) {
+ return -1;
+ }
+
+ errno = 0;
+ if ((entry = acl_get_entry(the_acl)) != NULL) {
+ *entry_p = entry;
+ return 1;
+ }
+
+ return errno ? -1 : 0;
+}
+
+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
+{
+ return acl_get_tag_type( entry_d, tag_type_p);
+}
+
+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
+{
+ return acl_get_permset( entry_d, permset_p);
+}
+
+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
+{
+ return acl_get_qualifier( entry_d);
+}
+
+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
+{
+ return acl_get_file((char *)path_p, type);
+}
+
+SMB_ACL_T sys_acl_get_fd(int fd)
+{
+ return acl_get_fd(fd, ACL_TYPE_ACCESS);
+}
+
+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
+{
+ *permset = 0; /* acl_clear_perm() is broken on Tru64 */
+
+ return 0;
+}
+
+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+ if (perm & ~(SMB_ACL_READ | SMB_ACL_WRITE | SMB_ACL_EXECUTE)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ *permset |= perm; /* acl_add_perm() is broken on Tru64 */
+
+ return 0;
+}
+
+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+ return *permset & perm; /* Tru64 doesn't have acl_get_perm() */
+}
+
+char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
+{
+ return acl_to_text( the_acl, plen);
+}
+
+SMB_ACL_T sys_acl_init( int count)
+{
+ return acl_init(count);
+}
+
+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
+{
+ SMB_ACL_ENTRY_T entry;
+
+ if ((entry = acl_create_entry(pacl)) == NULL) {
+ return -1;
+ }
+
+ *pentry = entry;
+ return 0;
+}
+
+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
+{
+ return acl_set_tag_type(entry, tagtype);
+}
+
+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
+{
+ return acl_set_qualifier(entry, qual);
+}
+
+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
+{
+ return acl_set_permset(entry, permset);
+}
+
+int sys_acl_valid( SMB_ACL_T theacl )
+{
+ acl_entry_t entry;
+
+ return acl_valid(theacl, &entry);
+}
+
+int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
+{
+ return acl_set_file((char *)name, acltype, theacl);
+}
+
+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
+{
+ return acl_set_fd(fd, ACL_TYPE_ACCESS, theacl);
+}
+
+int sys_acl_delete_def_file(const char *name)
+{
+ return acl_delete_def_file((char *)name);
+}
+
+int sys_acl_free_text(char *text)
+{
+ /*
+ * (void) cast and explicit return 0 are for DEC UNIX
+ * which just #defines acl_free_text() to be free()
+ */
+ (void) acl_free_text(text);
+ return 0;
+}
+
+int sys_acl_free_acl(SMB_ACL_T the_acl)
+{
+ return acl_free(the_acl);
+}
+
+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
+{
+ return acl_free_qualifier(qual, tagtype);
+}
+
+#elif defined(HAVE_UNIXWARE_ACLS) || defined(HAVE_SOLARIS_ACLS)
+
+/*
+ * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
+ * Modified by Toomas Soome <tsoome@ut.ee> for Solaris.
+ */
+
+/*
+ * Note that while this code implements sufficient functionality
+ * to support the sys_acl_* interfaces it does not provide all
+ * of the semantics of the POSIX ACL interfaces.
+ *
+ * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
+ * from a call to sys_acl_get_entry() should not be assumed to be
+ * valid after calling any of the following functions, which may
+ * reorder the entries in the ACL.
+ *
+ * sys_acl_valid()
+ * sys_acl_set_file()
+ * sys_acl_set_fd()
+ */
+
+/*
+ * The only difference between Solaris and UnixWare / OpenUNIX is
+ * that the #defines for the ACL operations have different names
+ */
+#if defined(HAVE_UNIXWARE_ACLS)
+
+#define SETACL ACL_SET
+#define GETACL ACL_GET
+#define GETACLCNT ACL_CNT
+
+#endif
+
+
+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+{
+ if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (entry_p == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
+ acl_d->next = 0;
+ }
+
+ if (acl_d->next < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_d->next >= acl_d->count) {
+ return 0;
+ }
+
+ *entry_p = &acl_d->acl[acl_d->next++];
+
+ return 1;
+}
+
+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
+{
+ *type_p = entry_d->a_type;
+
+ return 0;
+}
+
+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
+{
+ *permset_p = &entry_d->a_perm;
+
+ return 0;
+}
+
+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
+{
+ if (entry_d->a_type != SMB_ACL_USER
+ && entry_d->a_type != SMB_ACL_GROUP) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return &entry_d->a_id;
+}
+
+/*
+ * There is no way of knowing what size the ACL returned by
+ * GETACL will be unless you first call GETACLCNT which means
+ * making an additional system call.
+ *
+ * In the hope of avoiding the cost of the additional system
+ * call in most cases, we initially allocate enough space for
+ * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
+ * be too small then we use GETACLCNT to find out the actual
+ * size, reallocate the ACL buffer, and then call GETACL again.
+ */
+
+#define INITIAL_ACL_SIZE 16
+
+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
+{
+ SMB_ACL_T acl_d;
+ int count; /* # of ACL entries allocated */
+ int naccess; /* # of access ACL entries */
+ int ndefault; /* # of default ACL entries */
+
+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ count = INITIAL_ACL_SIZE;
+ if ((acl_d = sys_acl_init(count)) == NULL) {
+ return NULL;
+ }
+
+ /*
+ * If there isn't enough space for the ACL entries we use
+ * GETACLCNT to determine the actual number of ACL entries
+ * reallocate and try again. This is in a loop because it
+ * is possible that someone else could modify the ACL and
+ * increase the number of entries between the call to
+ * GETACLCNT and the call to GETACL.
+ */
+ while ((count = acl(path_p, GETACL, count, &acl_d->acl[0])) < 0
+ && errno == ENOSPC) {
+
+ sys_acl_free_acl(acl_d);
+
+ if ((count = acl(path_p, GETACLCNT, 0, NULL)) < 0) {
+ return NULL;
+ }
+
+ if ((acl_d = sys_acl_init(count)) == NULL) {
+ return NULL;
+ }
+ }
+
+ if (count < 0) {
+ sys_acl_free_acl(acl_d);
+ return NULL;
+ }
+
+ /*
+ * calculate the number of access and default ACL entries
+ *
+ * Note: we assume that the acl() system call returned a
+ * well formed ACL which is sorted so that all of the
+ * access ACL entries preceed any default ACL entries
+ */
+ for (naccess = 0; naccess < count; naccess++) {
+ if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
+ break;
+ }
+ ndefault = count - naccess;
+
+ /*
+ * if the caller wants the default ACL we have to copy
+ * the entries down to the start of the acl[] buffer
+ * and mask out the ACL_DEFAULT flag from the type field
+ */
+ if (type == SMB_ACL_TYPE_DEFAULT) {
+ int i, j;
+
+ for (i = 0, j = naccess; i < ndefault; i++, j++) {
+ acl_d->acl[i] = acl_d->acl[j];
+ acl_d->acl[i].a_type &= ~ACL_DEFAULT;
+ }
+
+ acl_d->count = ndefault;
+ } else {
+ acl_d->count = naccess;
+ }
+
+ return acl_d;
+}
+
+SMB_ACL_T sys_acl_get_fd(int fd)
+{
+ SMB_ACL_T acl_d;
+ int count; /* # of ACL entries allocated */
+ int naccess; /* # of access ACL entries */
+
+ count = INITIAL_ACL_SIZE;
+ if ((acl_d = sys_acl_init(count)) == NULL) {
+ return NULL;
+ }
+
+ while ((count = facl(fd, GETACL, count, &acl_d->acl[0])) < 0
+ && errno == ENOSPC) {
+
+ sys_acl_free_acl(acl_d);
+
+ if ((count = facl(fd, GETACLCNT, 0, NULL)) < 0) {
+ return NULL;
+ }
+
+ if ((acl_d = sys_acl_init(count)) == NULL) {
+ return NULL;
+ }
+ }
+
+ if (count < 0) {
+ sys_acl_free_acl(acl_d);
+ return NULL;
+ }
+
+ /*
+ * calculate the number of access ACL entries
+ */
+ for (naccess = 0; naccess < count; naccess++) {
+ if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
+ break;
+ }
+
+ acl_d->count = naccess;
+
+ return acl_d;
+}
+
+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
+{
+ *permset_d = 0;
+
+ return 0;
+}
+
+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
+{
+ if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
+ && perm != SMB_ACL_EXECUTE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (permset_d == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ *permset_d |= perm;
+
+ return 0;
+}
+
+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
+{
+ return *permset_d & perm;
+}
+
+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
+{
+ int i;
+ int len, maxlen;
+ char *text;
+
+ /*
+ * use an initial estimate of 20 bytes per ACL entry
+ * when allocating memory for the text representation
+ * of the ACL
+ */
+ len = 0;
+ maxlen = 20 * acl_d->count;
+ if ((text = malloc(maxlen)) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ for (i = 0; i < acl_d->count; i++) {
+ struct acl *ap = &acl_d->acl[i];
+ struct passwd *pw;
+ struct group *gr;
+ char tagbuf[12];
+ char idbuf[12];
+ char *tag;
+ char *id = "";
+ char perms[4];
+ int nbytes;
+
+ switch (ap->a_type) {
+ /*
+ * for debugging purposes it's probably more
+ * useful to dump unknown tag types rather
+ * than just returning an error
+ */
+ default:
+ slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
+ ap->a_type);
+ tag = tagbuf;
+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
+ (long)ap->a_id);
+ id = idbuf;
+ break;
+
+ case SMB_ACL_USER:
+ if ((pw = sys_getpwuid(ap->a_id)) == NULL) {
+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
+ (long)ap->a_id);
+ id = idbuf;
+ } else {
+ id = pw->pw_name;
+ }
+ case SMB_ACL_USER_OBJ:
+ tag = "user";
+ break;
+
+ case SMB_ACL_GROUP:
+ if ((gr = getgrgid(ap->a_id)) == NULL) {
+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
+ (long)ap->a_id);
+ id = idbuf;
+ } else {
+ id = gr->gr_name;
+ }
+ case SMB_ACL_GROUP_OBJ:
+ tag = "group";
+ break;
+
+ case SMB_ACL_OTHER:
+ tag = "other";
+ break;
+
+ case SMB_ACL_MASK:
+ tag = "mask";
+ break;
+
+ }
+
+ perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
+ perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
+ perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
+ perms[3] = '\0';
+
+ /* <tag> : <qualifier> : rwx \n \0 */
+ nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
+
+ /*
+ * If this entry would overflow the buffer
+ * allocate enough additional memory for this
+ * entry and an estimate of another 20 bytes
+ * for each entry still to be processed
+ */
+ if ((len + nbytes) > maxlen) {
+ char *oldtext = text;
+
+ maxlen += nbytes + 20 * (acl_d->count - i);
+
+ if ((text = Realloc(oldtext, maxlen)) == NULL) {
+ SAFE_FREE(oldtext);
+ errno = ENOMEM;
+ return NULL;
+ }
+ }
+
+ slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
+ len += nbytes - 1;
+ }
+
+ if (len_p)
+ *len_p = len;
+
+ return text;
+}
+
+SMB_ACL_T sys_acl_init(int count)
+{
+ SMB_ACL_T a;
+
+ if (count < 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /*
+ * note that since the definition of the structure pointed
+ * to by the SMB_ACL_T includes the first element of the
+ * acl[] array, this actually allocates an ACL with room
+ * for (count+1) entries
+ */
+ if ((a = malloc(sizeof(*a) + count * sizeof(struct acl))) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ a->size = count + 1;
+ a->count = 0;
+ a->next = -1;
+
+ return a;
+}
+
+
+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
+{
+ SMB_ACL_T acl_d;
+ SMB_ACL_ENTRY_T entry_d;
+
+ if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_d->count >= acl_d->size) {
+ errno = ENOSPC;
+ return -1;
+ }
+
+ entry_d = &acl_d->acl[acl_d->count++];
+ entry_d->a_type = 0;
+ entry_d->a_id = -1;
+ entry_d->a_perm = 0;
+ *entry_p = entry_d;
+
+ return 0;
+}
+
+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
+{
+ switch (tag_type) {
+ case SMB_ACL_USER:
+ case SMB_ACL_USER_OBJ:
+ case SMB_ACL_GROUP:
+ case SMB_ACL_GROUP_OBJ:
+ case SMB_ACL_OTHER:
+ case SMB_ACL_MASK:
+ entry_d->a_type = tag_type;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
+{
+ if (entry_d->a_type != SMB_ACL_GROUP
+ && entry_d->a_type != SMB_ACL_USER) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ entry_d->a_id = *((id_t *)qual_p);
+
+ return 0;
+}
+
+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
+{
+ if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
+ return EINVAL;
+ }
+
+ entry_d->a_perm = *permset_d;
+
+ return 0;
+}
+
+/*
+ * sort the ACL and check it for validity
+ *
+ * if it's a minimal ACL with only 4 entries then we
+ * need to recalculate the mask permissions to make
+ * sure that they are the same as the GROUP_OBJ
+ * permissions as required by the UnixWare acl() system call.
+ *
+ * (note: since POSIX allows minimal ACLs which only contain
+ * 3 entries - ie there is no mask entry - we should, in theory,
+ * check for this and add a mask entry if necessary - however
+ * we "know" that the caller of this interface always specifies
+ * a mask so, in practice "this never happens" (tm) - if it *does*
+ * happen aclsort() will fail and return an error and someone will
+ * have to fix it ...)
+ */
+
+static int acl_sort(SMB_ACL_T acl_d)
+{
+ int fixmask = (acl_d->count <= 4);
+
+ if (aclsort(acl_d->count, fixmask, acl_d->acl) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+int sys_acl_valid(SMB_ACL_T acl_d)
+{
+ return acl_sort(acl_d);
+}
+
+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
+{
+ struct stat s;
+ struct acl *acl_p;
+ int acl_count;
+ struct acl *acl_buf = NULL;
+ int ret;
+
+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_sort(acl_d) != 0) {
+ return -1;
+ }
+
+ acl_p = &acl_d->acl[0];
+ acl_count = acl_d->count;
+
+ /*
+ * if it's a directory there is extra work to do
+ * since the acl() system call will replace both
+ * the access ACLs and the default ACLs (if any)
+ */
+ if (stat(name, &s) != 0) {
+ return -1;
+ }
+ if (S_ISDIR(s.st_mode)) {
+ SMB_ACL_T acc_acl;
+ SMB_ACL_T def_acl;
+ SMB_ACL_T tmp_acl;
+ int i;
+
+ if (type == SMB_ACL_TYPE_ACCESS) {
+ acc_acl = acl_d;
+ def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
+
+ } else {
+ def_acl = acl_d;
+ acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
+ }
+
+ if (tmp_acl == NULL) {
+ return -1;
+ }
+
+ /*
+ * allocate a temporary buffer for the complete ACL
+ */
+ acl_count = acc_acl->count + def_acl->count;
+ acl_p = acl_buf = malloc(acl_count * sizeof(acl_buf[0]));
+
+ if (acl_buf == NULL) {
+ sys_acl_free_acl(tmp_acl);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /*
+ * copy the access control and default entries into the buffer
+ */
+ memcpy(&acl_buf[0], &acc_acl->acl[0],
+ acc_acl->count * sizeof(acl_buf[0]));
+
+ memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
+ def_acl->count * sizeof(acl_buf[0]));
+
+ /*
+ * set the ACL_DEFAULT flag on the default entries
+ */
+ for (i = acc_acl->count; i < acl_count; i++) {
+ acl_buf[i].a_type |= ACL_DEFAULT;
+ }
+
+ sys_acl_free_acl(tmp_acl);
+
+ } else if (type != SMB_ACL_TYPE_ACCESS) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = acl(name, SETACL, acl_count, acl_p);
+
+ SAFE_FREE(acl_buf);
+
+ return ret;
+}
+
+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
+{
+ if (acl_sort(acl_d) != 0) {
+ return -1;
+ }
+
+ return facl(fd, SETACL, acl_d->count, &acl_d->acl[0]);
+}
+
+int sys_acl_delete_def_file(const char *path)
+{
+ SMB_ACL_T acl_d;
+ int ret;
+
+ /*
+ * fetching the access ACL and rewriting it has
+ * the effect of deleting the default ACL
+ */
+ if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
+ return -1;
+ }
+
+ ret = acl(path, SETACL, acl_d->count, acl_d->acl);
+
+ sys_acl_free_acl(acl_d);
+
+ return ret;
+}
+
+int sys_acl_free_text(char *text)
+{
+ SAFE_FREE(text);
+ return 0;
+}
+
+int sys_acl_free_acl(SMB_ACL_T acl_d)
+{
+ SAFE_FREE(acl_d);
+ return 0;
+}
+
+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
+{
+ return 0;
+}
+
+#elif defined(HAVE_HPUX_ACLS)
+#include <dl.h>
+
+/*
+ * Based on the Solaris/SCO code - with modifications.
+ */
+
+/*
+ * Note that while this code implements sufficient functionality
+ * to support the sys_acl_* interfaces it does not provide all
+ * of the semantics of the POSIX ACL interfaces.
+ *
+ * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
+ * from a call to sys_acl_get_entry() should not be assumed to be
+ * valid after calling any of the following functions, which may
+ * reorder the entries in the ACL.
+ *
+ * sys_acl_valid()
+ * sys_acl_set_file()
+ * sys_acl_set_fd()
+ */
+
+/* This checks if the POSIX ACL system call is defined */
+/* which basically corresponds to whether JFS 3.3 or */
+/* higher is installed. If acl() was called when it */
+/* isn't defined, it causes the process to core dump */
+/* so it is important to check this and avoid acl() */
+/* calls if it isn't there. */
+
+static BOOL hpux_acl_call_presence(void)
+{
+
+ shl_t handle = NULL;
+ void *value;
+ int ret_val=0;
+ static BOOL already_checked=0;
+
+ if(already_checked)
+ return True;
+
+
+ ret_val = shl_findsym(&handle, "acl", TYPE_PROCEDURE, &value);
+
+ if(ret_val != 0) {
+ DEBUG(5, ("hpux_acl_call_presence: shl_findsym() returned %d, errno = %d, error %s\n",
+ ret_val, errno, strerror(errno)));
+ DEBUG(5,("hpux_acl_call_presence: acl() system call is not present. Check if you have JFS 3.3 and above?\n"));
+ return False;
+ }
+
+ DEBUG(10,("hpux_acl_call_presence: acl() system call is present. We have JFS 3.3 or above \n"));
+
+ already_checked = True;
+ return True;
+}
+
+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+{
+ if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (entry_p == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
+ acl_d->next = 0;
+ }
+
+ if (acl_d->next < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_d->next >= acl_d->count) {
+ return 0;
+ }
+
+ *entry_p = &acl_d->acl[acl_d->next++];
+
+ return 1;
+}
+
+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
+{
+ *type_p = entry_d->a_type;
+
+ return 0;
+}
+
+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
+{
+ *permset_p = &entry_d->a_perm;
+
+ return 0;
+}
+
+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
+{
+ if (entry_d->a_type != SMB_ACL_USER
+ && entry_d->a_type != SMB_ACL_GROUP) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return &entry_d->a_id;
+}
+
+/*
+ * There is no way of knowing what size the ACL returned by
+ * ACL_GET will be unless you first call ACL_CNT which means
+ * making an additional system call.
+ *
+ * In the hope of avoiding the cost of the additional system
+ * call in most cases, we initially allocate enough space for
+ * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
+ * be too small then we use ACL_CNT to find out the actual
+ * size, reallocate the ACL buffer, and then call ACL_GET again.
+ */
+
+#define INITIAL_ACL_SIZE 16
+
+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
+{
+ SMB_ACL_T acl_d;
+ int count; /* # of ACL entries allocated */
+ int naccess; /* # of access ACL entries */
+ int ndefault; /* # of default ACL entries */
+
+ if(hpux_acl_call_presence() == False) {
+ /* Looks like we don't have the acl() system call on HPUX.
+ * May be the system doesn't have the latest version of JFS.
+ */
+ return NULL;
+ }
+
+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ count = INITIAL_ACL_SIZE;
+ if ((acl_d = sys_acl_init(count)) == NULL) {
+ return NULL;
+ }
+
+ /*
+ * If there isn't enough space for the ACL entries we use
+ * ACL_CNT to determine the actual number of ACL entries
+ * reallocate and try again. This is in a loop because it
+ * is possible that someone else could modify the ACL and
+ * increase the number of entries between the call to
+ * ACL_CNT and the call to ACL_GET.
+ */
+ while ((count = acl(path_p, ACL_GET, count, &acl_d->acl[0])) < 0 && errno == ENOSPC) {
+
+ sys_acl_free_acl(acl_d);
+
+ if ((count = acl(path_p, ACL_CNT, 0, NULL)) < 0) {
+ return NULL;
+ }
+
+ if ((acl_d = sys_acl_init(count)) == NULL) {
+ return NULL;
+ }
+ }
+
+ if (count < 0) {
+ sys_acl_free_acl(acl_d);
+ return NULL;
+ }
+
+ /*
+ * calculate the number of access and default ACL entries
+ *
+ * Note: we assume that the acl() system call returned a
+ * well formed ACL which is sorted so that all of the
+ * access ACL entries preceed any default ACL entries
+ */
+ for (naccess = 0; naccess < count; naccess++) {
+ if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
+ break;
+ }
+ ndefault = count - naccess;
+
+ /*
+ * if the caller wants the default ACL we have to copy
+ * the entries down to the start of the acl[] buffer
+ * and mask out the ACL_DEFAULT flag from the type field
+ */
+ if (type == SMB_ACL_TYPE_DEFAULT) {
+ int i, j;
+
+ for (i = 0, j = naccess; i < ndefault; i++, j++) {
+ acl_d->acl[i] = acl_d->acl[j];
+ acl_d->acl[i].a_type &= ~ACL_DEFAULT;
+ }
+
+ acl_d->count = ndefault;
+ } else {
+ acl_d->count = naccess;
+ }
+
+ return acl_d;
+}
+
+SMB_ACL_T sys_acl_get_fd(int fd)
+{
+ /*
+ * HPUX doesn't have the facl call. Fake it using the path.... JRA.
+ */
+
+ files_struct *fsp = file_find_fd(fd);
+
+ if (fsp == NULL) {
+ errno = EBADF;
+ return NULL;
+ }
+
+ /*
+ * We know we're in the same conn context. So we
+ * can use the relative path.
+ */
+
+ return sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
+}
+
+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
+{
+ *permset_d = 0;
+
+ return 0;
+}
+
+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
+{
+ if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
+ && perm != SMB_ACL_EXECUTE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (permset_d == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ *permset_d |= perm;
+
+ return 0;
+}
+
+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
+{
+ return *permset_d & perm;
+}
+
+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
+{
+ int i;
+ int len, maxlen;
+ char *text;
+
+ /*
+ * use an initial estimate of 20 bytes per ACL entry
+ * when allocating memory for the text representation
+ * of the ACL
+ */
+ len = 0;
+ maxlen = 20 * acl_d->count;
+ if ((text = malloc(maxlen)) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ for (i = 0; i < acl_d->count; i++) {
+ struct acl *ap = &acl_d->acl[i];
+ struct passwd *pw;
+ struct group *gr;
+ char tagbuf[12];
+ char idbuf[12];
+ char *tag;
+ char *id = "";
+ char perms[4];
+ int nbytes;
+
+ switch (ap->a_type) {
+ /*
+ * for debugging purposes it's probably more
+ * useful to dump unknown tag types rather
+ * than just returning an error
+ */
+ default:
+ slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
+ ap->a_type);
+ tag = tagbuf;
+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
+ (long)ap->a_id);
+ id = idbuf;
+ break;
+
+ case SMB_ACL_USER:
+ if ((pw = sys_getpwuid(ap->a_id)) == NULL) {
+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
+ (long)ap->a_id);
+ id = idbuf;
+ } else {
+ id = pw->pw_name;
+ }
+ case SMB_ACL_USER_OBJ:
+ tag = "user";
+ break;
+
+ case SMB_ACL_GROUP:
+ if ((gr = getgrgid(ap->a_id)) == NULL) {
+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
+ (long)ap->a_id);
+ id = idbuf;
+ } else {
+ id = gr->gr_name;
+ }
+ case SMB_ACL_GROUP_OBJ:
+ tag = "group";
+ break;
+
+ case SMB_ACL_OTHER:
+ tag = "other";
+ break;
+
+ case SMB_ACL_MASK:
+ tag = "mask";
+ break;
+
+ }
+
+ perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
+ perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
+ perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
+ perms[3] = '\0';
+
+ /* <tag> : <qualifier> : rwx \n \0 */
+ nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
+
+ /*
+ * If this entry would overflow the buffer
+ * allocate enough additional memory for this
+ * entry and an estimate of another 20 bytes
+ * for each entry still to be processed
+ */
+ if ((len + nbytes) > maxlen) {
+ char *oldtext = text;
+
+ maxlen += nbytes + 20 * (acl_d->count - i);
+
+ if ((text = Realloc(oldtext, maxlen)) == NULL) {
+ free(oldtext);
+ errno = ENOMEM;
+ return NULL;
+ }
+ }
+
+ slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
+ len += nbytes - 1;
+ }
+
+ if (len_p)
+ *len_p = len;
+
+ return text;
+}
+
+SMB_ACL_T sys_acl_init(int count)
+{
+ SMB_ACL_T a;
+
+ if (count < 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /*
+ * note that since the definition of the structure pointed
+ * to by the SMB_ACL_T includes the first element of the
+ * acl[] array, this actually allocates an ACL with room
+ * for (count+1) entries
+ */
+ if ((a = malloc(sizeof(*a) + count * sizeof(struct acl))) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ a->size = count + 1;
+ a->count = 0;
+ a->next = -1;
+
+ return a;
+}
+
+
+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
+{
+ SMB_ACL_T acl_d;
+ SMB_ACL_ENTRY_T entry_d;
+
+ if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_d->count >= acl_d->size) {
+ errno = ENOSPC;
+ return -1;
+ }
+
+ entry_d = &acl_d->acl[acl_d->count++];
+ entry_d->a_type = 0;
+ entry_d->a_id = -1;
+ entry_d->a_perm = 0;
+ *entry_p = entry_d;
+
+ return 0;
+}
+
+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
+{
+ switch (tag_type) {
+ case SMB_ACL_USER:
+ case SMB_ACL_USER_OBJ:
+ case SMB_ACL_GROUP:
+ case SMB_ACL_GROUP_OBJ:
+ case SMB_ACL_OTHER:
+ case SMB_ACL_MASK:
+ entry_d->a_type = tag_type;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
+{
+ if (entry_d->a_type != SMB_ACL_GROUP
+ && entry_d->a_type != SMB_ACL_USER) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ entry_d->a_id = *((id_t *)qual_p);
+
+ return 0;
+}
+
+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
+{
+ if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
+ return EINVAL;
+ }
+
+ entry_d->a_perm = *permset_d;
+
+ return 0;
+}
+
+/* Structure to capture the count for each type of ACE. */
+
+struct hpux_acl_types {
+ int n_user;
+ int n_def_user;
+ int n_user_obj;
+ int n_def_user_obj;
+
+ int n_group;
+ int n_def_group;
+ int n_group_obj;
+ int n_def_group_obj;
+
+ int n_other;
+ int n_other_obj;
+ int n_def_other_obj;
+
+ int n_class_obj;
+ int n_def_class_obj;
+
+ int n_illegal_obj;
+};
+
+/* count_obj:
+ * Counts the different number of objects in a given array of ACL
+ * structures.
+ * Inputs:
+ *
+ * acl_count - Count of ACLs in the array of ACL strucutres.
+ * aclp - Array of ACL structures.
+ * acl_type_count - Pointer to acl_types structure. Should already be
+ * allocated.
+ * Output:
+ *
+ * acl_type_count - This structure is filled up with counts of various
+ * acl types.
+ */
+
+static int hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_types *acl_type_count)
+{
+ int i;
+
+ memset(acl_type_count, 0, sizeof(struct hpux_acl_types));
+
+ for(i=0;i<acl_count;i++) {
+ switch(aclp[i].a_type) {
+ case USER:
+ acl_type_count->n_user++;
+ break;
+ case USER_OBJ:
+ acl_type_count->n_user_obj++;
+ break;
+ case DEF_USER_OBJ:
+ acl_type_count->n_def_user_obj++;
+ break;
+ case GROUP:
+ acl_type_count->n_group++;
+ break;
+ case GROUP_OBJ:
+ acl_type_count->n_group_obj++;
+ break;
+ case DEF_GROUP_OBJ:
+ acl_type_count->n_def_group_obj++;
+ break;
+ case OTHER_OBJ:
+ acl_type_count->n_other_obj++;
+ break;
+ case DEF_OTHER_OBJ:
+ acl_type_count->n_def_other_obj++;
+ break;
+ case CLASS_OBJ:
+ acl_type_count->n_class_obj++;
+ break;
+ case DEF_CLASS_OBJ:
+ acl_type_count->n_def_class_obj++;
+ break;
+ case DEF_USER:
+ acl_type_count->n_def_user++;
+ break;
+ case DEF_GROUP:
+ acl_type_count->n_def_group++;
+ break;
+ default:
+ acl_type_count->n_illegal_obj++;
+ break;
+ }
+ }
+}
+
+/* swap_acl_entries: Swaps two ACL entries.
+ *
+ * Inputs: aclp0, aclp1 - ACL entries to be swapped.
+ */
+
+static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1)
+{
+ struct acl temp_acl;
+
+ temp_acl.a_type = aclp0->a_type;
+ temp_acl.a_id = aclp0->a_id;
+ temp_acl.a_perm = aclp0->a_perm;
+
+ aclp0->a_type = aclp1->a_type;
+ aclp0->a_id = aclp1->a_id;
+ aclp0->a_perm = aclp1->a_perm;
+
+ aclp1->a_type = temp_acl.a_type;
+ aclp1->a_id = temp_acl.a_id;
+ aclp1->a_perm = temp_acl.a_perm;
+}
+
+/* prohibited_duplicate_type
+ * Identifies if given ACL type can have duplicate entries or
+ * not.
+ *
+ * Inputs: acl_type - ACL Type.
+ *
+ * Outputs:
+ *
+ * Return..
+ *
+ * True - If the ACL type matches any of the prohibited types.
+ * False - If the ACL type doesn't match any of the prohibited types.
+ */
+
+static BOOL hpux_prohibited_duplicate_type(int acl_type)
+{
+ switch(acl_type) {
+ case USER:
+ case GROUP:
+ case DEF_USER:
+ case DEF_GROUP:
+ return True;
+ default:
+ return False;
+ }
+}
+
+/* get_needed_class_perm
+ * Returns the permissions of a ACL structure only if the ACL
+ * type matches one of the pre-determined types for computing
+ * CLASS_OBJ permissions.
+ *
+ * Inputs: aclp - Pointer to ACL structure.
+ */
+
+static int hpux_get_needed_class_perm(struct acl *aclp)
+{
+ switch(aclp->a_type) {
+ case USER:
+ case GROUP_OBJ:
+ case GROUP:
+ case DEF_USER_OBJ:
+ case DEF_USER:
+ case DEF_GROUP_OBJ:
+ case DEF_GROUP:
+ case DEF_CLASS_OBJ:
+ case DEF_OTHER_OBJ:
+ return aclp->a_perm;
+ default:
+ return 0;
+ }
+}
+
+/* acl_sort for HPUX.
+ * Sorts the array of ACL structures as per the description in
+ * aclsort man page. Refer to aclsort man page for more details
+ *
+ * Inputs:
+ *
+ * acl_count - Count of ACLs in the array of ACL structures.
+ * calclass - If this is not zero, then we compute the CLASS_OBJ
+ * permissions.
+ * aclp - Array of ACL structures.
+ *
+ * Outputs:
+ *
+ * aclp - Sorted array of ACL structures.
+ *
+ * Outputs:
+ *
+ * Returns 0 for success -1 for failure. Prints a message to the Samba
+ * debug log in case of failure.
+ */
+
+static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
+{
+#if !defined(HAVE_HPUX_ACLSORT)
+ /*
+ * The aclsort() system call is availabe on the latest HPUX General
+ * Patch Bundles. So for HPUX, we developed our version of acl_sort
+ * function. Because, we don't want to update to a new
+ * HPUX GR bundle just for aclsort() call.
+ */
+
+ struct hpux_acl_types acl_obj_count;
+ int n_class_obj_perm = 0;
+ int i, j;
+
+ if(!acl_count) {
+ DEBUG(10,("Zero acl count passed. Returning Success\n"));
+ return 0;
+ }
+
+ if(aclp == NULL) {
+ DEBUG(0,("Null ACL pointer in hpux_acl_sort. Returning Failure. \n"));
+ return -1;
+ }
+
+ /* Count different types of ACLs in the ACLs array */
+
+ hpux_count_obj(acl_count, aclp, &acl_obj_count);
+
+ /* There should be only one entry each of type USER_OBJ, GROUP_OBJ,
+ * CLASS_OBJ and OTHER_OBJ
+ */
+
+ if( (acl_obj_count.n_user_obj != 1) ||
+ (acl_obj_count.n_group_obj != 1) ||
+ (acl_obj_count.n_class_obj != 1) ||
+ (acl_obj_count.n_other_obj != 1)
+ ) {
+ DEBUG(0,("hpux_acl_sort: More than one entry or no entries for \
+USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n"));
+ return -1;
+ }
+
+ /* If any of the default objects are present, there should be only
+ * one of them each.
+ */
+
+ if( (acl_obj_count.n_def_user_obj > 1) || (acl_obj_count.n_def_group_obj > 1) ||
+ (acl_obj_count.n_def_other_obj > 1) || (acl_obj_count.n_def_class_obj > 1) ) {
+ DEBUG(0,("hpux_acl_sort: More than one entry for DEF_CLASS_OBJ \
+or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
+ return -1;
+ }
+
+ /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl
+ * structures.
+ *
+ * Sorting crieteria - First sort by ACL type. If there are multiple entries of
+ * same ACL type, sort by ACL id.
+ *
+ * I am using the trival kind of sorting method here because, performance isn't
+ * really effected by the ACLs feature. More over there aren't going to be more
+ * than 17 entries on HPUX.
+ */
+
+ for(i=0; i<acl_count;i++) {
+ for (j=i+1; j<acl_count; j++) {
+ if( aclp[i].a_type > aclp[j].a_type ) {
+ /* ACL entries out of order, swap them */
+
+ hpux_swap_acl_entries((aclp+i), (aclp+j));
+
+ } else if ( aclp[i].a_type == aclp[j].a_type ) {
+
+ /* ACL entries of same type, sort by id */
+
+ if(aclp[i].a_id > aclp[j].a_id) {
+ hpux_swap_acl_entries((aclp+i), (aclp+j));
+ } else if (aclp[i].a_id == aclp[j].a_id) {
+ /* We have a duplicate entry. */
+ if(hpux_prohibited_duplicate_type(aclp[i].a_type)) {
+ DEBUG(0, ("hpux_acl_sort: Duplicate entry: Type(hex): %x Id: %d\n",
+ aclp[i].a_type, aclp[i].a_id));
+ return -1;
+ }
+ }
+
+ }
+ }
+ }
+
+ /* set the class obj permissions to the computed one. */
+ if(calclass) {
+ int n_class_obj_index = -1;
+
+ for(i=0;i<acl_count;i++) {
+ n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i));
+
+ if(aclp[i].a_type == CLASS_OBJ)
+ n_class_obj_index = i;
+ }
+ aclp[n_class_obj_index].a_perm = n_class_obj_perm;
+ }
+
+ return 0;
+#else
+ return aclsort(acl_count, calclass, aclp);
+#endif
+}
+
+/*
+ * sort the ACL and check it for validity
+ *
+ * if it's a minimal ACL with only 4 entries then we
+ * need to recalculate the mask permissions to make
+ * sure that they are the same as the GROUP_OBJ
+ * permissions as required by the UnixWare acl() system call.
+ *
+ * (note: since POSIX allows minimal ACLs which only contain
+ * 3 entries - ie there is no mask entry - we should, in theory,
+ * check for this and add a mask entry if necessary - however
+ * we "know" that the caller of this interface always specifies
+ * a mask so, in practice "this never happens" (tm) - if it *does*
+ * happen aclsort() will fail and return an error and someone will
+ * have to fix it ...)
+ */
+
+static int acl_sort(SMB_ACL_T acl_d)
+{
+ int fixmask = (acl_d->count <= 4);
+
+ if (hpux_acl_sort(acl_d->count, fixmask, acl_d->acl) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+int sys_acl_valid(SMB_ACL_T acl_d)
+{
+ return acl_sort(acl_d);
+}
+
+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
+{
+ struct stat s;
+ struct acl *acl_p;
+ int acl_count;
+ struct acl *acl_buf = NULL;
+ int ret;
+
+ if(hpux_acl_call_presence() == False) {
+ /* Looks like we don't have the acl() system call on HPUX.
+ * May be the system doesn't have the latest version of JFS.
+ */
+ errno=ENOSYS;
+ return -1;
+ }
+
+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_sort(acl_d) != 0) {
+ return -1;
+ }
+
+ acl_p = &acl_d->acl[0];
+ acl_count = acl_d->count;
+
+ /*
+ * if it's a directory there is extra work to do
+ * since the acl() system call will replace both
+ * the access ACLs and the default ACLs (if any)
+ */
+ if (stat(name, &s) != 0) {
+ return -1;
+ }
+ if (S_ISDIR(s.st_mode)) {
+ SMB_ACL_T acc_acl;
+ SMB_ACL_T def_acl;
+ SMB_ACL_T tmp_acl;
+ int i;
+
+ if (type == SMB_ACL_TYPE_ACCESS) {
+ acc_acl = acl_d;
+ def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
+
+ } else {
+ def_acl = acl_d;
+ acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
+ }
+
+ if (tmp_acl == NULL) {
+ return -1;
+ }
+
+ /*
+ * allocate a temporary buffer for the complete ACL
+ */
+ acl_count = acc_acl->count + def_acl->count;
+ acl_p = acl_buf = malloc(acl_count * sizeof(acl_buf[0]));
+
+ if (acl_buf == NULL) {
+ sys_acl_free_acl(tmp_acl);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /*
+ * copy the access control and default entries into the buffer
+ */
+ memcpy(&acl_buf[0], &acc_acl->acl[0],
+ acc_acl->count * sizeof(acl_buf[0]));
+
+ memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
+ def_acl->count * sizeof(acl_buf[0]));
+
+ /*
+ * set the ACL_DEFAULT flag on the default entries
+ */
+ for (i = acc_acl->count; i < acl_count; i++) {
+ acl_buf[i].a_type |= ACL_DEFAULT;
+ }
+
+ sys_acl_free_acl(tmp_acl);
+
+ } else if (type != SMB_ACL_TYPE_ACCESS) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = acl(name, ACL_SET, acl_count, acl_p);
+
+ if (acl_buf) {
+ free(acl_buf);
+ }
+
+ return ret;
+}
+
+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
+{
+ /*
+ * HPUX doesn't have the facl call. Fake it using the path.... JRA.
+ */
+
+ files_struct *fsp = file_find_fd(fd);
+
+ if (fsp == NULL) {
+ errno = EBADF;
+ return NULL;
+ }
+
+ if (acl_sort(acl_d) != 0) {
+ return -1;
+ }
+
+ /*
+ * We know we're in the same conn context. So we
+ * can use the relative path.
+ */
+
+ return sys_acl_set_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS, acl_d);
+}
+
+int sys_acl_delete_def_file(const char *path)
+{
+ SMB_ACL_T acl_d;
+ int ret;
+
+ /*
+ * fetching the access ACL and rewriting it has
+ * the effect of deleting the default ACL
+ */
+ if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
+ return -1;
+ }
+
+ ret = acl(path, ACL_SET, acl_d->count, acl_d->acl);
+
+ sys_acl_free_acl(acl_d);
+
+ return ret;
+}
+
+int sys_acl_free_text(char *text)
+{
+ free(text);
+ return 0;
+}
+
+int sys_acl_free_acl(SMB_ACL_T acl_d)
+{
+ free(acl_d);
+ return 0;
+}
+
+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
+{
+ return 0;
+}
+
+#elif defined(HAVE_IRIX_ACLS)
+
+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+{
+ if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (entry_p == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
+ acl_d->next = 0;
+ }
+
+ if (acl_d->next < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_d->next >= acl_d->aclp->acl_cnt) {
+ return 0;
+ }
+
+ *entry_p = &acl_d->aclp->acl_entry[acl_d->next++];
+
+ return 1;
+}
+
+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
+{
+ *type_p = entry_d->ae_tag;
+
+ return 0;
+}
+
+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
+{
+ *permset_p = entry_d;
+
+ return 0;
+}
+
+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
+{
+ if (entry_d->ae_tag != SMB_ACL_USER
+ && entry_d->ae_tag != SMB_ACL_GROUP) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return &entry_d->ae_id;
+}
+
+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
+{
+ SMB_ACL_T a;
+
+ if ((a = malloc(sizeof(*a))) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ if ((a->aclp = acl_get_file(path_p, type)) == NULL) {
+ SAFE_FREE(a);
+ return NULL;
+ }
+ a->next = -1;
+ a->freeaclp = True;
+ return a;
+}
+
+SMB_ACL_T sys_acl_get_fd(int fd)
+{
+ SMB_ACL_T a;
+
+ if ((a = malloc(sizeof(*a))) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ if ((a->aclp = acl_get_fd(fd)) == NULL) {
+ SAFE_FREE(a);
+ return NULL;
+ }
+ a->next = -1;
+ a->freeaclp = True;
+ return a;
+}
+
+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
+{
+ permset_d->ae_perm = 0;
+
+ return 0;
+}
+
+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
+{
+ if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
+ && perm != SMB_ACL_EXECUTE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (permset_d == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ permset_d->ae_perm |= perm;
+
+ return 0;
+}
+
+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
+{
+ return permset_d->ae_perm & perm;
+}
+
+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
+{
+ return acl_to_text(acl_d->aclp, len_p);
+}
+
+SMB_ACL_T sys_acl_init(int count)
+{
+ SMB_ACL_T a;
+
+ if (count < 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if ((a = malloc(sizeof(*a) + sizeof(struct acl))) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ a->next = -1;
+ a->freeaclp = False;
+ a->aclp = (struct acl *)(&a->aclp + sizeof(struct acl *));
+ a->aclp->acl_cnt = 0;
+
+ return a;
+}
+
+
+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
+{
+ SMB_ACL_T acl_d;
+ SMB_ACL_ENTRY_T entry_d;
+
+ if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (acl_d->aclp->acl_cnt >= ACL_MAX_ENTRIES) {
+ errno = ENOSPC;
+ return -1;
+ }
+
+ entry_d = &acl_d->aclp->acl_entry[acl_d->aclp->acl_cnt++];
+ entry_d->ae_tag = 0;
+ entry_d->ae_id = 0;
+ entry_d->ae_perm = 0;
+ *entry_p = entry_d;
+
+ return 0;
+}
+
+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
+{
+ switch (tag_type) {
+ case SMB_ACL_USER:
+ case SMB_ACL_USER_OBJ:
+ case SMB_ACL_GROUP:
+ case SMB_ACL_GROUP_OBJ:
+ case SMB_ACL_OTHER:
+ case SMB_ACL_MASK:
+ entry_d->ae_tag = tag_type;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
+{
+ if (entry_d->ae_tag != SMB_ACL_GROUP
+ && entry_d->ae_tag != SMB_ACL_USER) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ entry_d->ae_id = *((id_t *)qual_p);
+
+ return 0;
+}
+
+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
+{
+ if (permset_d->ae_perm & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
+ return EINVAL;
+ }
+
+ entry_d->ae_perm = permset_d->ae_perm;
+
+ return 0;
+}
+
+int sys_acl_valid(SMB_ACL_T acl_d)
+{
+ return acl_valid(acl_d->aclp);
+}
+
+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
+{
+ return acl_set_file(name, type, acl_d->aclp);
+}
+
+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
+{
+ return acl_set_fd(fd, acl_d->aclp);
+}
+
+int sys_acl_delete_def_file(const char *name)
+{
+ return acl_delete_def_file(name);
+}
+
+int sys_acl_free_text(char *text)
+{
+ return acl_free(text);
+}
+
+int sys_acl_free_acl(SMB_ACL_T acl_d)
+{
+ if (acl_d->freeaclp) {
+ acl_free(acl_d->aclp);
+ }
+ acl_free(acl_d);
+ return 0;
+}
+
+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
+{
+ return 0;
+}
+
+#elif defined(HAVE_AIX_ACLS)
+
+/* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
+
+int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+{
+ struct acl_entry_link *link;
+ struct new_acl_entry *entry;
+ int keep_going;
+
+ DEBUG(10,("This is the count: %d\n",theacl->count));
+
+ /* Check if count was previously set to -1. *
+ * If it was, that means we reached the end *
+ * of the acl last time. */
+ if(theacl->count == -1)
+ return(0);
+
+ link = theacl;
+ /* To get to the next acl, traverse linked list until index *
+ * of acl matches the count we are keeping. This count is *
+ * incremented each time we return an acl entry. */
+
+ for(keep_going = 0; keep_going < theacl->count; keep_going++)
+ link = link->nextp;
+
+ entry = *entry_p = link->entryp;
+
+ DEBUG(10,("*entry_p is %d\n",entry_p));
+ DEBUG(10,("*entry_p->ace_access is %d\n",entry->ace_access));
+
+ /* Increment count */
+ theacl->count++;
+ if(link->nextp == NULL)
+ theacl->count = -1;
+
+ return(1);
+}
+
+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
+{
+ /* Initialize tag type */
+
+ *tag_type_p = -1;
+ DEBUG(10,("the tagtype is %d\n",entry_d->ace_id->id_type));
+
+ /* Depending on what type of entry we have, *
+ * return tag type. */
+ switch(entry_d->ace_id->id_type) {
+ case ACEID_USER:
+ *tag_type_p = SMB_ACL_USER;
+ break;
+ case ACEID_GROUP:
+ *tag_type_p = SMB_ACL_GROUP;
+ break;
+
+ case SMB_ACL_USER_OBJ:
+ case SMB_ACL_GROUP_OBJ:
+ case SMB_ACL_OTHER:
+ *tag_type_p = entry_d->ace_id->id_type;
+ break;
+
+ default:
+ return(-1);
+ }
+
+ return(0);
+}
+
+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
+{
+ DEBUG(10,("Starting AIX sys_acl_get_permset\n"));
+ *permset_p = &entry_d->ace_access;
+ DEBUG(10,("**permset_p is %d\n",**permset_p));
+ if(!(**permset_p & S_IXUSR) &&
+ !(**permset_p & S_IWUSR) &&
+ !(**permset_p & S_IRUSR) &&
+ (**permset_p != 0))
+ return(-1);
+
+ DEBUG(10,("Ending AIX sys_acl_get_permset\n"));
+ return(0);
+}
+
+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
+{
+ return(entry_d->ace_id->id_data);
+}
+
+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
+{
+ struct acl *file_acl = (struct acl *)NULL;
+ struct acl_entry *acl_entry;
+ struct new_acl_entry *new_acl_entry;
+ struct ace_id *idp;
+ struct acl_entry_link *acl_entry_link;
+ struct acl_entry_link *acl_entry_link_head;
+ int i;
+ int rc = 0;
+ uid_t user_id;
+
+ /* Get the acl using statacl */
+
+ DEBUG(10,("Entering sys_acl_get_file\n"));
+ DEBUG(10,("path_p is %s\n",path_p));
+
+ file_acl = (struct acl *)malloc(BUFSIZ);
+
+ if(file_acl == NULL) {
+ errno=ENOMEM;
+ DEBUG(0,("Error in AIX sys_acl_get_file: %d\n",errno));
+ return(NULL);
+ }
+
+ memset(file_acl,0,BUFSIZ);
+
+ rc = statacl((char *)path_p,0,file_acl,BUFSIZ);
+ if(rc == -1) {
+ DEBUG(0,("statacl returned %d with errno %d\n",rc,errno));
+ SAFE_FREE(file_acl);
+ return(NULL);
+ }
+
+ DEBUG(10,("Got facl and returned it\n"));
+
+ /* Point to the first acl entry in the acl */
+ acl_entry = file_acl->acl_ext;
+
+ /* Begin setting up the head of the linked list *
+ * that will be used for the storing the acl *
+ * in a way that is useful for the posix_acls.c *
+ * code. */
+
+ acl_entry_link_head = acl_entry_link = sys_acl_init(0);
+ if(acl_entry_link_head == NULL)
+ return(NULL);
+
+ acl_entry_link->entryp = (struct new_acl_entry *)malloc(sizeof(struct new_acl_entry));
+ if(acl_entry_link->entryp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
+ return(NULL);
+ }
+
+ DEBUG(10,("acl_entry is %d\n",acl_entry));
+ DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
+
+ /* Check if the extended acl bit is on. *
+ * If it isn't, do not show the *
+ * contents of the acl since AIX intends *
+ * the extended info to remain unused */
+
+ if(file_acl->acl_mode & S_IXACL){
+ /* while we are not pointing to the very end */
+ while(acl_entry < acl_last(file_acl)) {
+ /* before we malloc anything, make sure this is */
+ /* a valid acl entry and one that we want to map */
+ idp = id_nxt(acl_entry->ace_id);
+ if((acl_entry->ace_type == ACC_SPECIFY ||
+ (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
+ acl_entry = acl_nxt(acl_entry);
+ continue;
+ }
+
+ idp = acl_entry->ace_id;
+
+ /* Check if this is the first entry in the linked list. *
+ * The first entry needs to keep prevp pointing to NULL *
+ * and already has entryp allocated. */
+
+ if(acl_entry_link_head->count != 0) {
+ acl_entry_link->nextp = (struct acl_entry_link *)
+ malloc(sizeof(struct acl_entry_link));
+
+ if(acl_entry_link->nextp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
+ return(NULL);
+ }
+
+ acl_entry_link->nextp->prevp = acl_entry_link;
+ acl_entry_link = acl_entry_link->nextp;
+ acl_entry_link->entryp = (struct new_acl_entry *)malloc(sizeof(struct new_acl_entry));
+ if(acl_entry_link->entryp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
+ return(NULL);
+ }
+ acl_entry_link->nextp = NULL;
+ }
+
+ acl_entry_link->entryp->ace_len = acl_entry->ace_len;
+
+ /* Don't really need this since all types are going *
+ * to be specified but, it's better than leaving it 0 */
+
+ acl_entry_link->entryp->ace_type = acl_entry->ace_type;
+
+ acl_entry_link->entryp->ace_access = acl_entry->ace_access;
+
+ memcpy(acl_entry_link->entryp->ace_id,idp,sizeof(struct ace_id));
+
+ /* The access in the acl entries must be left shifted by *
+ * three bites, because they will ultimately be compared *
+ * to S_IRUSR, S_IWUSR, and S_IXUSR. */
+
+ switch(acl_entry->ace_type){
+ case ACC_PERMIT:
+ case ACC_SPECIFY:
+ acl_entry_link->entryp->ace_access = acl_entry->ace_access;
+ acl_entry_link->entryp->ace_access <<= 6;
+ acl_entry_link_head->count++;
+ break;
+ case ACC_DENY:
+ /* Since there is no way to return a DENY acl entry *
+ * change to PERMIT and then shift. */
+ DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
+ acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
+ DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
+ acl_entry_link->entryp->ace_access <<= 6;
+ acl_entry_link_head->count++;
+ break;
+ default:
+ return(0);
+ }
+
+ DEBUG(10,("acl_entry = %d\n",acl_entry));
+ DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
+
+ acl_entry = acl_nxt(acl_entry);
+ }
+ } /* end of if enabled */
+
+ /* Since owner, group, other acl entries are not *
+ * part of the acl entries in an acl, they must *
+ * be dummied up to become part of the list. */
+
+ for( i = 1; i < 4; i++) {
+ DEBUG(10,("i is %d\n",i));
+ if(acl_entry_link_head->count != 0) {
+ acl_entry_link->nextp = (struct acl_entry_link *)malloc(sizeof(struct acl_entry_link));
+ if(acl_entry_link->nextp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
+ return(NULL);
+ }
+
+ acl_entry_link->nextp->prevp = acl_entry_link;
+ acl_entry_link = acl_entry_link->nextp;
+ acl_entry_link->entryp = (struct new_acl_entry *)malloc(sizeof(struct new_acl_entry));
+ if(acl_entry_link->entryp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
+ return(NULL);
+ }
+ }
+
+ acl_entry_link->nextp = NULL;
+
+ new_acl_entry = acl_entry_link->entryp;
+ idp = new_acl_entry->ace_id;
+
+ new_acl_entry->ace_len = sizeof(struct acl_entry);
+ new_acl_entry->ace_type = ACC_PERMIT;
+ idp->id_len = sizeof(struct ace_id);
+ DEBUG(10,("idp->id_len = %d\n",idp->id_len));
+ memset(idp->id_data,0,sizeof(uid_t));
+
+ switch(i) {
+ case 2:
+ new_acl_entry->ace_access = file_acl->g_access << 6;
+ idp->id_type = SMB_ACL_GROUP_OBJ;
+ break;
+
+ case 3:
+ new_acl_entry->ace_access = file_acl->o_access << 6;
+ idp->id_type = SMB_ACL_OTHER;
+ break;
+
+ case 1:
+ new_acl_entry->ace_access = file_acl->u_access << 6;
+ idp->id_type = SMB_ACL_USER_OBJ;
+ break;
+
+ default:
+ return(NULL);
+
+ }
+
+ acl_entry_link_head->count++;
+ DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
+ }
+
+ acl_entry_link_head->count = 0;
+ SAFE_FREE(file_acl);
+
+ return(acl_entry_link_head);
+}
+
+SMB_ACL_T sys_acl_get_fd(int fd)
+{
+ struct acl *file_acl = (struct acl *)NULL;
+ struct acl_entry *acl_entry;
+ struct new_acl_entry *new_acl_entry;
+ struct ace_id *idp;
+ struct acl_entry_link *acl_entry_link;
+ struct acl_entry_link *acl_entry_link_head;
+ int i;
+ int rc = 0;
+ uid_t user_id;
+
+ /* Get the acl using fstatacl */
+
+ DEBUG(10,("Entering sys_acl_get_fd\n"));
+ DEBUG(10,("fd is %d\n",fd));
+ file_acl = (struct acl *)malloc(BUFSIZ);
+
+ if(file_acl == NULL) {
+ errno=ENOMEM;
+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
+ return(NULL);
+ }
+
+ memset(file_acl,0,BUFSIZ);
+
+ rc = fstatacl(fd,0,file_acl,BUFSIZ);
+ if(rc == -1) {
+ DEBUG(0,("The fstatacl call returned %d with errno %d\n",rc,errno));
+ SAFE_FREE(file_acl);
+ return(NULL);
+ }
+
+ DEBUG(10,("Got facl and returned it\n"));
+
+ /* Point to the first acl entry in the acl */
+
+ acl_entry = file_acl->acl_ext;
+ /* Begin setting up the head of the linked list *
+ * that will be used for the storing the acl *
+ * in a way that is useful for the posix_acls.c *
+ * code. */
+
+ acl_entry_link_head = acl_entry_link = sys_acl_init(0);
+ if(acl_entry_link_head == NULL){
+ SAFE_FREE(file_acl);
+ return(NULL);
+ }
+
+ acl_entry_link->entryp = (struct new_acl_entry *)malloc(sizeof(struct new_acl_entry));
+
+ if(acl_entry_link->entryp == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
+ SAFE_FREE(file_acl);
+ return(NULL);
+ }
+
+ DEBUG(10,("acl_entry is %d\n",acl_entry));
+ DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
+
+ /* Check if the extended acl bit is on. *
+ * If it isn't, do not show the *
+ * contents of the acl since AIX intends *
+ * the extended info to remain unused */
+
+ if(file_acl->acl_mode & S_IXACL){
+ /* while we are not pointing to the very end */
+ while(acl_entry < acl_last(file_acl)) {
+ /* before we malloc anything, make sure this is */
+ /* a valid acl entry and one that we want to map */
+
+ idp = id_nxt(acl_entry->ace_id);
+ if((acl_entry->ace_type == ACC_SPECIFY ||
+ (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
+ acl_entry = acl_nxt(acl_entry);
+ continue;
+ }
+
+ idp = acl_entry->ace_id;
+
+ /* Check if this is the first entry in the linked list. *
+ * The first entry needs to keep prevp pointing to NULL *
+ * and already has entryp allocated. */
+
+ if(acl_entry_link_head->count != 0) {
+ acl_entry_link->nextp = (struct acl_entry_link *)malloc(sizeof(struct acl_entry_link));
+ if(acl_entry_link->nextp == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
+ SAFE_FREE(file_acl);
+ return(NULL);
+ }
+ acl_entry_link->nextp->prevp = acl_entry_link;
+ acl_entry_link = acl_entry_link->nextp;
+ acl_entry_link->entryp = (struct new_acl_entry *)malloc(sizeof(struct new_acl_entry));
+ if(acl_entry_link->entryp == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
+ SAFE_FREE(file_acl);
+ return(NULL);
+ }
+
+ acl_entry_link->nextp = NULL;
+ }
+
+ acl_entry_link->entryp->ace_len = acl_entry->ace_len;
+
+ /* Don't really need this since all types are going *
+ * to be specified but, it's better than leaving it 0 */
+
+ acl_entry_link->entryp->ace_type = acl_entry->ace_type;
+ acl_entry_link->entryp->ace_access = acl_entry->ace_access;
+
+ memcpy(acl_entry_link->entryp->ace_id, idp, sizeof(struct ace_id));
+
+ /* The access in the acl entries must be left shifted by *
+ * three bites, because they will ultimately be compared *
+ * to S_IRUSR, S_IWUSR, and S_IXUSR. */
+
+ switch(acl_entry->ace_type){
+ case ACC_PERMIT:
+ case ACC_SPECIFY:
+ acl_entry_link->entryp->ace_access = acl_entry->ace_access;
+ acl_entry_link->entryp->ace_access <<= 6;
+ acl_entry_link_head->count++;
+ break;
+ case ACC_DENY:
+ /* Since there is no way to return a DENY acl entry *
+ * change to PERMIT and then shift. */
+ DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
+ acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
+ DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
+ acl_entry_link->entryp->ace_access <<= 6;
+ acl_entry_link_head->count++;
+ break;
+ default:
+ return(0);
+ }
+
+ DEBUG(10,("acl_entry = %d\n",acl_entry));
+ DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
+
+ acl_entry = acl_nxt(acl_entry);
+ }
+ } /* end of if enabled */
+
+ /* Since owner, group, other acl entries are not *
+ * part of the acl entries in an acl, they must *
+ * be dummied up to become part of the list. */
+
+ for( i = 1; i < 4; i++) {
+ DEBUG(10,("i is %d\n",i));
+ if(acl_entry_link_head->count != 0){
+ acl_entry_link->nextp = (struct acl_entry_link *)malloc(sizeof(struct acl_entry_link));
+ if(acl_entry_link->nextp == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
+ SAFE_FREE(file_acl);
+ return(NULL);
+ }
+
+ acl_entry_link->nextp->prevp = acl_entry_link;
+ acl_entry_link = acl_entry_link->nextp;
+ acl_entry_link->entryp = (struct new_acl_entry *)malloc(sizeof(struct new_acl_entry));
+
+ if(acl_entry_link->entryp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
+ return(NULL);
+ }
+ }
+
+ acl_entry_link->nextp = NULL;
+
+ new_acl_entry = acl_entry_link->entryp;
+ idp = new_acl_entry->ace_id;
+
+ new_acl_entry->ace_len = sizeof(struct acl_entry);
+ new_acl_entry->ace_type = ACC_PERMIT;
+ idp->id_len = sizeof(struct ace_id);
+ DEBUG(10,("idp->id_len = %d\n",idp->id_len));
+ memset(idp->id_data,0,sizeof(uid_t));
+
+ switch(i) {
+ case 2:
+ new_acl_entry->ace_access = file_acl->g_access << 6;
+ idp->id_type = SMB_ACL_GROUP_OBJ;
+ break;
+
+ case 3:
+ new_acl_entry->ace_access = file_acl->o_access << 6;
+ idp->id_type = SMB_ACL_OTHER;
+ break;
+
+ case 1:
+ new_acl_entry->ace_access = file_acl->u_access << 6;
+ idp->id_type = SMB_ACL_USER_OBJ;
+ break;
+
+ default:
+ return(NULL);
+ }
+
+ acl_entry_link_head->count++;
+ DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
+ }
+
+ acl_entry_link_head->count = 0;
+ SAFE_FREE(file_acl);
+
+ return(acl_entry_link_head);
+}
+
+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
+{
+ *permset = *permset & ~0777;
+ return(0);
+}
+
+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+ if((perm != 0) &&
+ (perm & (S_IXUSR | S_IWUSR | S_IRUSR)) == 0)
+ return(-1);
+
+ *permset |= perm;
+ DEBUG(10,("This is the permset now: %d\n",*permset));
+ return(0);
+}
+
+char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen)
+{
+ return(NULL);
+}
+
+SMB_ACL_T sys_acl_init( int count)
+{
+ struct acl_entry_link *theacl = NULL;
+
+ DEBUG(10,("Entering sys_acl_init\n"));
+
+ theacl = (struct acl_entry_link *)malloc(sizeof(struct acl_entry_link));
+ if(theacl == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_init is %d\n",errno));
+ return(NULL);
+ }
+
+ theacl->count = 0;
+ theacl->nextp = NULL;
+ theacl->prevp = NULL;
+ theacl->entryp = NULL;
+ DEBUG(10,("Exiting sys_acl_init\n"));
+ return(theacl);
+}
+
+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
+{
+ struct acl_entry_link *theacl;
+ struct acl_entry_link *acl_entryp;
+ struct acl_entry_link *temp_entry;
+ int counting;
+
+ DEBUG(10,("Entering the sys_acl_create_entry\n"));
+
+ theacl = acl_entryp = *pacl;
+
+ /* Get to the end of the acl before adding entry */
+
+ for(counting=0; counting < theacl->count; counting++){
+ DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
+ temp_entry = acl_entryp;
+ acl_entryp = acl_entryp->nextp;
+ }
+
+ if(theacl->count != 0){
+ temp_entry->nextp = acl_entryp = (struct acl_entry_link *)malloc(sizeof(struct acl_entry_link));
+ if(acl_entryp == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
+ return(-1);
+ }
+
+ DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
+ acl_entryp->prevp = temp_entry;
+ DEBUG(10,("The acl_entryp->prevp is %d\n",acl_entryp->prevp));
+ }
+
+ *pentry = acl_entryp->entryp = (struct new_acl_entry *)malloc(sizeof(struct new_acl_entry));
+ if(*pentry == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
+ return(-1);
+ }
+
+ memset(*pentry,0,sizeof(struct new_acl_entry));
+ acl_entryp->entryp->ace_len = sizeof(struct acl_entry);
+ acl_entryp->entryp->ace_type = ACC_PERMIT;
+ acl_entryp->entryp->ace_id->id_len = sizeof(struct ace_id);
+ acl_entryp->nextp = NULL;
+ theacl->count++;
+ DEBUG(10,("Exiting sys_acl_create_entry\n"));
+ return(0);
+}
+
+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
+{
+ DEBUG(10,("Starting AIX sys_acl_set_tag_type\n"));
+ entry->ace_id->id_type = tagtype;
+ DEBUG(10,("The tag type is %d\n",entry->ace_id->id_type));
+ DEBUG(10,("Ending AIX sys_acl_set_tag_type\n"));
+}
+
+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
+{
+ DEBUG(10,("Starting AIX sys_acl_set_qualifier\n"));
+ memcpy(entry->ace_id->id_data,qual,sizeof(uid_t));
+ DEBUG(10,("Ending AIX sys_acl_set_qualifier\n"));
+ return(0);
+}
+
+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
+{
+ DEBUG(10,("Starting AIX sys_acl_set_permset\n"));
+ if(!(*permset & S_IXUSR) &&
+ !(*permset & S_IWUSR) &&
+ !(*permset & S_IRUSR) &&
+ (*permset != 0))
+ return(-1);
+
+ entry->ace_access = *permset;
+ DEBUG(10,("entry->ace_access = %d\n",entry->ace_access));
+ DEBUG(10,("Ending AIX sys_acl_set_permset\n"));
+ return(0);
+}
+
+int sys_acl_valid( SMB_ACL_T theacl )
+{
+ int user_obj = 0;
+ int group_obj = 0;
+ int other_obj = 0;
+ struct acl_entry_link *acl_entry;
+
+ for(acl_entry=theacl; acl_entry != NULL; acl_entry = acl_entry->nextp) {
+ user_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_USER_OBJ);
+ group_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_GROUP_OBJ);
+ other_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_OTHER);
+ }
+
+ DEBUG(10,("user_obj=%d, group_obj=%d, other_obj=%d\n",user_obj,group_obj,other_obj));
+
+ if(user_obj != 1 || group_obj != 1 || other_obj != 1)
+ return(-1);
+
+ return(0);
+}
+
+int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
+{
+ struct acl_entry_link *acl_entry_link = NULL;
+ struct acl *file_acl = NULL;
+ struct acl *file_acl_temp = NULL;
+ struct acl_entry *acl_entry = NULL;
+ struct ace_id *ace_id = NULL;
+ uint id_type;
+ uint ace_access;
+ uint user_id;
+ uint acl_length;
+ uint rc;
+
+ DEBUG(10,("Entering sys_acl_set_file\n"));
+ DEBUG(10,("File name is %s\n",name));
+
+ /* AIX has no default ACL */
+ if(acltype == SMB_ACL_TYPE_DEFAULT)
+ return(0);
+
+ acl_length = BUFSIZ;
+ file_acl = (struct acl *)malloc(BUFSIZ);
+
+ if(file_acl == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
+ return(-1);
+ }
+
+ memset(file_acl,0,BUFSIZ);
+
+ file_acl->acl_len = ACL_SIZ;
+ file_acl->acl_mode = S_IXACL;
+
+ for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
+ acl_entry_link->entryp->ace_access >>= 6;
+ id_type = acl_entry_link->entryp->ace_id->id_type;
+
+ switch(id_type) {
+ case SMB_ACL_USER_OBJ:
+ file_acl->u_access = acl_entry_link->entryp->ace_access;
+ continue;
+ case SMB_ACL_GROUP_OBJ:
+ file_acl->g_access = acl_entry_link->entryp->ace_access;
+ continue;
+ case SMB_ACL_OTHER:
+ file_acl->o_access = acl_entry_link->entryp->ace_access;
+ continue;
+ case SMB_ACL_MASK:
+ continue;
+ }
+
+ if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
+ acl_length += sizeof(struct acl_entry);
+ file_acl_temp = (struct acl *)malloc(acl_length);
+ if(file_acl_temp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
+ return(-1);
+ }
+
+ memcpy(file_acl_temp,file_acl,file_acl->acl_len);
+ SAFE_FREE(file_acl);
+ file_acl = file_acl_temp;
+ }
+
+ acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
+ file_acl->acl_len += sizeof(struct acl_entry);
+ acl_entry->ace_len = acl_entry_link->entryp->ace_len;
+ acl_entry->ace_access = acl_entry_link->entryp->ace_access;
+
+ /* In order to use this, we'll need to wait until we can get denies */
+ /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
+ acl_entry->ace_type = ACC_SPECIFY; */
+
+ acl_entry->ace_type = ACC_SPECIFY;
+
+ ace_id = acl_entry->ace_id;
+
+ ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
+ DEBUG(10,("The id type is %d\n",ace_id->id_type));
+ ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
+ memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
+ memcpy(acl_entry->ace_id->id_data, &user_id, sizeof(uid_t));
+ }
+
+ rc = chacl(name,file_acl,file_acl->acl_len);
+ DEBUG(10,("errno is %d\n",errno));
+ DEBUG(10,("return code is %d\n",rc));
+ SAFE_FREE(file_acl);
+ DEBUG(10,("Exiting the sys_acl_set_file\n"));
+ return(rc);
+}
+
+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
+{
+ struct acl_entry_link *acl_entry_link = NULL;
+ struct acl *file_acl = NULL;
+ struct acl *file_acl_temp = NULL;
+ struct acl_entry *acl_entry = NULL;
+ struct ace_id *ace_id = NULL;
+ uint id_type;
+ uint user_id;
+ uint acl_length;
+ uint rc;
+
+ DEBUG(10,("Entering sys_acl_set_fd\n"));
+ acl_length = BUFSIZ;
+ file_acl = (struct acl *)malloc(BUFSIZ);
+
+ if(file_acl == NULL) {
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
+ return(-1);
+ }
+
+ memset(file_acl,0,BUFSIZ);
+
+ file_acl->acl_len = ACL_SIZ;
+ file_acl->acl_mode = S_IXACL;
+
+ for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
+ acl_entry_link->entryp->ace_access >>= 6;
+ id_type = acl_entry_link->entryp->ace_id->id_type;
+ DEBUG(10,("The id_type is %d\n",id_type));
+
+ switch(id_type) {
+ case SMB_ACL_USER_OBJ:
+ file_acl->u_access = acl_entry_link->entryp->ace_access;
+ continue;
+ case SMB_ACL_GROUP_OBJ:
+ file_acl->g_access = acl_entry_link->entryp->ace_access;
+ continue;
+ case SMB_ACL_OTHER:
+ file_acl->o_access = acl_entry_link->entryp->ace_access;
+ continue;
+ case SMB_ACL_MASK:
+ continue;
+ }
+
+ if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
+ acl_length += sizeof(struct acl_entry);
+ file_acl_temp = (struct acl *)malloc(acl_length);
+ if(file_acl_temp == NULL) {
+ SAFE_FREE(file_acl);
+ errno = ENOMEM;
+ DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
+ return(-1);
+ }
+
+ memcpy(file_acl_temp,file_acl,file_acl->acl_len);
+ SAFE_FREE(file_acl);
+ file_acl = file_acl_temp;
+ }
+
+ acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
+ file_acl->acl_len += sizeof(struct acl_entry);
+ acl_entry->ace_len = acl_entry_link->entryp->ace_len;
+ acl_entry->ace_access = acl_entry_link->entryp->ace_access;
+
+ /* In order to use this, we'll need to wait until we can get denies */
+ /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
+ acl_entry->ace_type = ACC_SPECIFY; */
+
+ acl_entry->ace_type = ACC_SPECIFY;
+
+ ace_id = acl_entry->ace_id;
+
+ ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
+ DEBUG(10,("The id type is %d\n",ace_id->id_type));
+ ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
+ memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
+ memcpy(ace_id->id_data, &user_id, sizeof(uid_t));
+ }
+
+ rc = fchacl(fd,file_acl,file_acl->acl_len);
+ DEBUG(10,("errno is %d\n",errno));
+ DEBUG(10,("return code is %d\n",rc));
+ SAFE_FREE(file_acl);
+ DEBUG(10,("Exiting sys_acl_set_fd\n"));
+ return(rc);
+}
+
+int sys_acl_delete_def_file(const char *name)
+{
+ /* AIX has no default ACL */
+ return 0;
+}
+
+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+ return(*permset & perm);
+}
+
+int sys_acl_free_text(char *text)
+{
+ return(0);
+}
+
+int sys_acl_free_acl(SMB_ACL_T posix_acl)
+{
+ struct acl_entry_link *acl_entry_link;
+
+ for(acl_entry_link = posix_acl->nextp; acl_entry_link->nextp != NULL; acl_entry_link = acl_entry_link->nextp) {
+ SAFE_FREE(acl_entry_link->prevp->entryp);
+ SAFE_FREE(acl_entry_link->prevp);
+ }
+
+ SAFE_FREE(acl_entry_link->prevp->entryp);
+ SAFE_FREE(acl_entry_link->prevp);
+ SAFE_FREE(acl_entry_link->entryp);
+ SAFE_FREE(acl_entry_link);
+
+ return(0);
+}
+
+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
+{
+ return(0);
+}
+
+#else /* No ACLs. */
+
+int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
+{
+ errno = ENOSYS;
+ return NULL;
+}
+
+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
+{
+ errno = ENOSYS;
+ return (SMB_ACL_T)NULL;
+}
+
+SMB_ACL_T sys_acl_get_fd(int fd)
+{
+ errno = ENOSYS;
+ return (SMB_ACL_T)NULL;
+}
+
+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
+{
+ errno = ENOSYS;
+ return (permset & perm) ? 1 : 0;
+}
+
+char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
+{
+ errno = ENOSYS;
+ return NULL;
+}
+
+int sys_acl_free_text(char *text)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+SMB_ACL_T sys_acl_init( int count)
+{
+ errno = ENOSYS;
+ return NULL;
+}
+
+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_valid( SMB_ACL_T theacl )
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_delete_def_file(const char *name)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_free_acl(SMB_ACL_T the_acl)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+#endif /* No ACLs. */
diff --git a/source3/lib/system.c b/source3/lib/system.c
index 938746e9c9..8c7eec939e 100644
--- a/source3/lib/system.c
+++ b/source3/lib/system.c
@@ -1,8 +1,8 @@
/*
- Unix SMB/Netbios implementation.
- Version 1.9.
+ Unix SMB/CIFS implementation.
Samba system utilities
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1998-2002
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,202 +21,1214 @@
#include "includes.h"
-extern int DEBUGLEVEL;
-
/*
The idea is that this file will eventually have wrappers around all
- important system calls in samba. The aim is twofold:
+ important system calls in samba. The aims are:
- to enable easier porting by putting OS dependent stuff in here
- to allow for hooks into other "pseudo-filesystems"
- to allow easier integration of things like the japanese extensions
+
+ - to support the philosophy of Samba to expose the features of
+ the OS within the SMB model. In general whatever file/printer/variable
+ expansions/etc make sense to the OS should be acceptable to Samba.
*/
+
/*******************************************************************
-this replaces the normal select() system call
-return if some data has arrived on one of the file descriptors
-return -1 means error
+ A wrapper for usleep in case we don't have one.
********************************************************************/
-#ifdef NO_SELECT
-static int pollfd(int fd)
-{
- int r=0;
-
-#ifdef HAS_RDCHK
- r = rdchk(fd);
-#elif defined(TCRDCHK)
- (void)ioctl(fd, TCRDCHK, &r);
-#else
- (void)ioctl(fd, FIONREAD, &r);
-#endif
- return(r);
-}
-
-int sys_select(fd_set *fds,struct timeval *tval)
+int sys_usleep(long usecs)
{
- fd_set fds2;
- int counter=0;
- int found=0;
+#ifndef HAVE_USLEEP
+ struct timeval tval;
+#endif
- FD_ZERO(&fds2);
+ /*
+ * We need this braindamage as the glibc usleep
+ * is not SPEC1170 complient... grumble... JRA.
+ */
- while (1)
- {
- int i;
- for (i=0;i<255;i++) {
- if (FD_ISSET(i,fds) && pollfd(i)>0) {
- found++;
- FD_SET(i,&fds2);
+ if(usecs < 0 || usecs > 1000000) {
+ errno = EINVAL;
+ return -1;
}
- }
- if (found) {
- memcpy((void *)fds,(void *)&fds2,sizeof(fds2));
- return(found);
- }
-
- if (tval && tval.tv_sec < counter) return(0);
- sleep(1);
- counter++;
- }
+#if HAVE_USLEEP
+ usleep(usecs);
+ return 0;
+#else /* HAVE_USLEEP */
+ /*
+ * Fake it with select...
+ */
+ tval.tv_sec = 0;
+ tval.tv_usec = usecs/1000;
+ select(0,NULL,NULL,NULL,&tval);
+ return 0;
+#endif /* HAVE_USLEEP */
}
-#else
-int sys_select(fd_set *fds,struct timeval *tval)
+/*******************************************************************
+A stat() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
{
- struct timeval t2;
- int selrtn;
+ int ret;
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
+ ret = stat64(fname, sbuf);
+#else
+ ret = stat(fname, sbuf);
+#endif
+ /* we always want directories to appear zero size */
+ if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
+ return ret;
+}
- do {
- if (tval) memcpy((void *)&t2,(void *)tval,sizeof(t2));
- errno = 0;
- selrtn = select(16,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL);
- } while (selrtn<0 && errno == EINTR);
+/*******************************************************************
+ An fstat() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
- return(selrtn);
-}
+int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
+{
+ int ret;
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
+ ret = fstat64(fd, sbuf);
+#else
+ ret = fstat(fd, sbuf);
#endif
-
+ /* we always want directories to appear zero size */
+ if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
+ return ret;
+}
/*******************************************************************
-just a unlink wrapper
+ An lstat() wrapper that will deal with 64 bit filesizes.
********************************************************************/
-int sys_unlink(char *fname)
+
+int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
{
- return(unlink(dos_to_unix(fname,False)));
+ int ret;
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
+ ret = lstat64(fname, sbuf);
+#else
+ ret = lstat(fname, sbuf);
+#endif
+ /* we always want directories to appear zero size */
+ if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
+ return ret;
}
-
/*******************************************************************
-a simple open() wrapper
+ An ftruncate() wrapper that will deal with 64 bit filesizes.
********************************************************************/
-int sys_open(char *fname,int flags,int mode)
+
+int sys_ftruncate(int fd, SMB_OFF_T offset)
{
- return(open(dos_to_unix(fname,False),flags,mode));
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
+ return ftruncate64(fd, offset);
+#else
+ return ftruncate(fd, offset);
+#endif
}
-
/*******************************************************************
-a simple opendir() wrapper
+ An lseek() wrapper that will deal with 64 bit filesizes.
********************************************************************/
-DIR *sys_opendir(char *dname)
+
+SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
{
- return(opendir(dos_to_unix(dname,False)));
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
+ return lseek64(fd, offset, whence);
+#else
+ return lseek(fd, offset, whence);
+#endif
}
+/*******************************************************************
+ An fseek() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
+ return fseek64(fp, offset, whence);
+#elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
+ return fseeko64(fp, offset, whence);
+#else
+ return fseek(fp, offset, whence);
+#endif
+}
/*******************************************************************
-and a stat() wrapper
+ An ftell() wrapper that will deal with 64 bit filesizes.
********************************************************************/
-int sys_stat(char *fname,struct stat *sbuf)
+
+SMB_OFF_T sys_ftell(FILE *fp)
{
- return(stat(dos_to_unix(fname,False),sbuf));
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
+ return (SMB_OFF_T)ftell64(fp);
+#elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
+ return (SMB_OFF_T)ftello64(fp);
+#else
+ return (SMB_OFF_T)ftell(fp);
+#endif
}
/*******************************************************************
-don't forget lstat()
+ A creat() wrapper that will deal with 64 bit filesizes.
********************************************************************/
-int sys_lstat(char *fname,struct stat *sbuf)
+
+int sys_creat(const char *path, mode_t mode)
{
- return(lstat(dos_to_unix(fname,False),sbuf));
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
+ return creat64(path, mode);
+#else
+ /*
+ * If creat64 isn't defined then ensure we call a potential open64.
+ * JRA.
+ */
+ return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
+#endif
}
+/*******************************************************************
+ An open() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_open(const char *path, int oflag, mode_t mode)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
+ return open64(path, oflag, mode);
+#else
+ return open(path, oflag, mode);
+#endif
+}
/*******************************************************************
-mkdir() gets a wrapper
+ An fopen() wrapper that will deal with 64 bit filesizes.
********************************************************************/
-int sys_mkdir(char *dname,int mode)
+
+FILE *sys_fopen(const char *path, const char *type)
{
- return(mkdir(dos_to_unix(dname,False),mode));
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
+ return fopen64(path, type);
+#else
+ return fopen(path, type);
+#endif
}
+/*******************************************************************
+ A readdir wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+SMB_STRUCT_DIRENT *sys_readdir(DIR *dirp)
+{
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
+ return readdir64(dirp);
+#else
+ return readdir(dirp);
+#endif
+}
/*******************************************************************
-do does rmdir()
+ An mknod() wrapper that will deal with 64 bit filesizes.
********************************************************************/
-int sys_rmdir(char *dname)
+
+int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
{
- return(rmdir(dos_to_unix(dname,False)));
+#if defined(HAVE_MKNOD) || defined(HAVE_MKNOD64)
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_MKNOD64) && defined(HAVE_DEV64_T)
+ return mknod64(path, mode, dev);
+#else
+ return mknod(path, mode, dev);
+#endif
+#else
+ /* No mknod system call. */
+ errno = ENOSYS;
+ return -1;
+#endif
}
+/*******************************************************************
+ Wrapper for realpath.
+********************************************************************/
+
+char *sys_realpath(const char *path, char *resolved_path)
+{
+#if defined(HAVE_REALPATH)
+ return realpath(path, resolved_path);
+#else
+ /* As realpath is not a system call we can't return ENOSYS. */
+ errno = EINVAL;
+ return NULL;
+#endif
+}
/*******************************************************************
-I almost forgot chdir()
+The wait() calls vary between systems
********************************************************************/
-int sys_chdir(char *dname)
+
+int sys_waitpid(pid_t pid,int *status,int options)
{
- return(chdir(dos_to_unix(dname,False)));
+#ifdef HAVE_WAITPID
+ return waitpid(pid,status,options);
+#else /* HAVE_WAITPID */
+ return wait4(pid, status, options, NULL);
+#endif /* HAVE_WAITPID */
}
+/*******************************************************************
+ System wrapper for getwd
+********************************************************************/
+
+char *sys_getwd(char *s)
+{
+ char *wd;
+#ifdef HAVE_GETCWD
+ wd = (char *)getcwd(s, sizeof (pstring));
+#else
+ wd = (char *)getwd(s);
+#endif
+ return wd;
+}
/*******************************************************************
-now for utime()
+system wrapper for symlink
********************************************************************/
-int sys_utime(char *fname,struct utimbuf *times)
+
+int sys_symlink(const char *oldpath, const char *newpath)
{
- return(utime(dos_to_unix(fname,False),times));
+#ifndef HAVE_SYMLINK
+ errno = ENOSYS;
+ return -1;
+#else
+ return symlink(oldpath, newpath);
+#endif
}
/*******************************************************************
-for rename()
+system wrapper for readlink
********************************************************************/
-int sys_rename(char *from, char *to)
+
+int sys_readlink(const char *path, char *buf, size_t bufsiz)
{
-#ifdef KANJI
- pstring zfrom, zto;
- strcpy (zfrom, dos_to_unix (from, False));
- strcpy (zto, dos_to_unix (to, False));
- return rename (zfrom, zto);
-#else
- return rename (from, to);
-#endif /* KANJI */
+#ifndef HAVE_READLINK
+ errno = ENOSYS;
+ return -1;
+#else
+ return readlink(path, buf, bufsiz);
+#endif
}
+/*******************************************************************
+system wrapper for link
+********************************************************************/
+
+int sys_link(const char *oldpath, const char *newpath)
+{
+#ifndef HAVE_LINK
+ errno = ENOSYS;
+ return -1;
+#else
+ return link(oldpath, newpath);
+#endif
+}
/*******************************************************************
chown isn't used much but OS/2 doesn't have it
********************************************************************/
-int sys_chown(char *fname,int uid,int gid)
+
+int sys_chown(const char *fname,uid_t uid,gid_t gid)
{
-#ifdef NO_CHOWN
- DEBUG(1,("Warning - chown(%s,%d,%d) not done\n",fname,uid,gid));
+#ifndef HAVE_CHOWN
+ static int done;
+ if (!done) {
+ DEBUG(1,("WARNING: no chown!\n"));
+ done=1;
+ }
#else
- return(chown(fname,uid,gid));
+ return(chown(fname,uid,gid));
#endif
}
/*******************************************************************
os/2 also doesn't have chroot
********************************************************************/
-int sys_chroot(char *dname)
+int sys_chroot(const char *dname)
+{
+#ifndef HAVE_CHROOT
+ static int done;
+ if (!done) {
+ DEBUG(1,("WARNING: no chroot!\n"));
+ done=1;
+ }
+ errno = ENOSYS;
+ return -1;
+#else
+ return(chroot(dname));
+#endif
+}
+
+/**************************************************************************
+A wrapper for gethostbyname() that tries avoids looking up hostnames
+in the root domain, which can cause dial-on-demand links to come up for no
+apparent reason.
+****************************************************************************/
+
+struct hostent *sys_gethostbyname(const char *name)
+{
+#ifdef REDUCE_ROOT_DNS_LOOKUPS
+ char query[256], hostname[256];
+ char *domain;
+
+ /* Does this name have any dots in it? If so, make no change */
+
+ if (strchr_m(name, '.'))
+ return(gethostbyname(name));
+
+ /* Get my hostname, which should have domain name
+ attached. If not, just do the gethostname on the
+ original string.
+ */
+
+ gethostname(hostname, sizeof(hostname) - 1);
+ hostname[sizeof(hostname) - 1] = 0;
+ if ((domain = strchr_m(hostname, '.')) == NULL)
+ return(gethostbyname(name));
+
+ /* Attach domain name to query and do modified query.
+ If names too large, just do gethostname on the
+ original string.
+ */
+
+ if((strlen(name) + strlen(domain)) >= sizeof(query))
+ return(gethostbyname(name));
+
+ slprintf(query, sizeof(query)-1, "%s%s", name, domain);
+ return(gethostbyname(query));
+#else /* REDUCE_ROOT_DNS_LOOKUPS */
+ return(gethostbyname(name));
+#endif /* REDUCE_ROOT_DNS_LOOKUPS */
+}
+
+
+#if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
+/**************************************************************************
+ Try and abstract process capabilities (for systems that have them).
+****************************************************************************/
+static BOOL set_process_capability( uint32 cap_flag, BOOL enable )
+{
+ if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
+ cap_t cap = cap_get_proc();
+
+ if (cap == NULL) {
+ DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
+ strerror(errno)));
+ return False;
+ }
+
+ if(enable)
+ cap->cap_effective |= CAP_NETWORK_MGT;
+ else
+ cap->cap_effective &= ~CAP_NETWORK_MGT;
+
+ if (cap_set_proc(cap) == -1) {
+ DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
+ strerror(errno)));
+ cap_free(cap);
+ return False;
+ }
+
+ cap_free(cap);
+
+ DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
+ }
+ return True;
+}
+
+/**************************************************************************
+ Try and abstract inherited process capabilities (for systems that have them).
+****************************************************************************/
+
+static BOOL set_inherited_process_capability( uint32 cap_flag, BOOL enable )
+{
+ if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
+ cap_t cap = cap_get_proc();
+
+ if (cap == NULL) {
+ DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n",
+ strerror(errno)));
+ return False;
+ }
+
+ if(enable)
+ cap->cap_inheritable |= CAP_NETWORK_MGT;
+ else
+ cap->cap_inheritable &= ~CAP_NETWORK_MGT;
+
+ if (cap_set_proc(cap) == -1) {
+ DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n",
+ strerror(errno)));
+ cap_free(cap);
+ return False;
+ }
+
+ cap_free(cap);
+
+ DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
+ }
+ return True;
+}
+#endif
+
+/****************************************************************************
+ Gain the oplock capability from the kernel if possible.
+****************************************************************************/
+
+void oplock_set_capability(BOOL this_process, BOOL inherit)
+{
+#if HAVE_KERNEL_OPLOCKS_IRIX
+ set_process_capability(KERNEL_OPLOCK_CAPABILITY,this_process);
+ set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY,inherit);
+#endif
+}
+
+/**************************************************************************
+ Wrapper for random().
+****************************************************************************/
+
+long sys_random(void)
+{
+#if defined(HAVE_RANDOM)
+ return (long)random();
+#elif defined(HAVE_RAND)
+ return (long)rand();
+#else
+ DEBUG(0,("Error - no random function available !\n"));
+ exit(1);
+#endif
+}
+
+/**************************************************************************
+ Wrapper for srandom().
+****************************************************************************/
+
+void sys_srandom(unsigned int seed)
+{
+#if defined(HAVE_SRANDOM)
+ srandom(seed);
+#elif defined(HAVE_SRAND)
+ srand(seed);
+#else
+ DEBUG(0,("Error - no srandom function available !\n"));
+ exit(1);
+#endif
+}
+
+/**************************************************************************
+ Returns equivalent to NGROUPS_MAX - using sysconf if needed.
+****************************************************************************/
+
+int groups_max(void)
+{
+#if defined(SYSCONF_SC_NGROUPS_MAX)
+ int ret = sysconf(_SC_NGROUPS_MAX);
+ return (ret == -1) ? NGROUPS_MAX : ret;
+#else
+ return NGROUPS_MAX;
+#endif
+}
+
+/**************************************************************************
+ Wrapper for getgroups. Deals with broken (int) case.
+****************************************************************************/
+
+int sys_getgroups(int setlen, gid_t *gidset)
+{
+#if !defined(HAVE_BROKEN_GETGROUPS)
+ return getgroups(setlen, gidset);
+#else
+
+ GID_T gid;
+ GID_T *group_list;
+ int i, ngroups;
+
+ if(setlen == 0) {
+ return getgroups(setlen, &gid);
+ }
+
+ /*
+ * Broken case. We need to allocate a
+ * GID_T array of size setlen.
+ */
+
+ if(setlen < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (setlen == 0)
+ setlen = groups_max();
+
+ if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
+ DEBUG(0,("sys_getgroups: Malloc fail.\n"));
+ return -1;
+ }
+
+ if((ngroups = getgroups(setlen, group_list)) < 0) {
+ int saved_errno = errno;
+ SAFE_FREE(group_list);
+ errno = saved_errno;
+ return -1;
+ }
+
+ for(i = 0; i < ngroups; i++)
+ gidset[i] = (gid_t)group_list[i];
+
+ SAFE_FREE(group_list);
+ return ngroups;
+#endif /* HAVE_BROKEN_GETGROUPS */
+}
+
+#ifdef HAVE_SETGROUPS
+
+/**************************************************************************
+ Wrapper for setgroups. Deals with broken (int) case. Automatically used
+ if we have broken getgroups.
+****************************************************************************/
+
+int sys_setgroups(int setlen, gid_t *gidset)
+{
+#if !defined(HAVE_BROKEN_GETGROUPS)
+ return setgroups(setlen, gidset);
+#else
+
+ GID_T *group_list;
+ int i ;
+
+ if (setlen == 0)
+ return 0 ;
+
+ if (setlen < 0 || setlen > groups_max()) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Broken case. We need to allocate a
+ * GID_T array of size setlen.
+ */
+
+ if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
+ DEBUG(0,("sys_setgroups: Malloc fail.\n"));
+ return -1;
+ }
+
+ for(i = 0; i < setlen; i++)
+ group_list[i] = (GID_T) gidset[i];
+
+ if(setgroups(setlen, group_list) != 0) {
+ int saved_errno = errno;
+ SAFE_FREE(group_list);
+ errno = saved_errno;
+ return -1;
+ }
+
+ SAFE_FREE(group_list);
+ return 0 ;
+#endif /* HAVE_BROKEN_GETGROUPS */
+}
+
+#endif /* HAVE_SETGROUPS */
+
+/*
+ * We only wrap pw_name and pw_passwd for now as these
+ * are the only potentially modified fields.
+ */
+
+/**************************************************************************
+ Helper function for getpwnam/getpwuid wrappers.
+****************************************************************************/
+
+struct saved_pw {
+ fstring pw_name;
+ fstring pw_passwd;
+ fstring pw_gecos;
+ pstring pw_dir;
+ pstring pw_shell;
+ struct passwd pass;
+};
+
+static struct saved_pw pw_mod; /* This is the structure returned - can be modified. */
+static struct saved_pw pw_cache; /* This is the structure saved - used to check cache. */
+
+static int num_lookups; /* Counter so we don't always use cache. */
+#ifndef PW_RET_CACHE_MAX_LOOKUPS
+#define PW_RET_CACHE_MAX_LOOKUPS 100
+#endif
+
+static void copy_pwent(struct saved_pw *dst, struct passwd *pass)
{
-#ifdef NO_CHROOT
- DEBUG(1,("Warning - chroot(%s) not done\n",dname));
+ memcpy((char *)&dst->pass, pass, sizeof(struct passwd));
+
+ fstrcpy(dst->pw_name, pass->pw_name);
+ dst->pass.pw_name = dst->pw_name;
+
+ fstrcpy(dst->pw_passwd, pass->pw_passwd);
+ dst->pass.pw_passwd = dst->pw_passwd;
+
+ fstrcpy(dst->pw_gecos, pass->pw_gecos);
+ dst->pass.pw_gecos = dst->pw_gecos;
+
+ pstrcpy(dst->pw_dir, pass->pw_dir);
+ dst->pass.pw_dir = dst->pw_dir;
+
+ pstrcpy(dst->pw_shell, pass->pw_shell);
+ dst->pass.pw_shell = dst->pw_shell;
+}
+
+static struct passwd *setup_pwret(struct passwd *pass)
+{
+ if (pass == NULL) {
+ /* Clear the caches. */
+ memset(&pw_cache, '\0', sizeof(struct saved_pw));
+ memset(&pw_mod, '\0', sizeof(struct saved_pw));
+ num_lookups = 0;
+ return NULL;
+ }
+
+ copy_pwent( &pw_mod, pass);
+
+ if (pass != &pw_cache.pass) {
+
+ /* If it's a cache miss we must also refill the cache. */
+
+ copy_pwent( &pw_cache, pass);
+ num_lookups = 1;
+
+ } else {
+
+ /* Cache hit. */
+
+ num_lookups++;
+ num_lookups = (num_lookups % PW_RET_CACHE_MAX_LOOKUPS);
+ }
+
+ return &pw_mod.pass;
+}
+
+/**************************************************************************
+ Wrappers for setpwent(), getpwent() and endpwent()
+****************************************************************************/
+
+void sys_setpwent(void)
+{
+ setup_pwret(NULL); /* Clear cache. */
+ setpwent();
+}
+
+struct passwd *sys_getpwent(void)
+{
+ return setup_pwret(getpwent());
+}
+
+void sys_endpwent(void)
+{
+ setup_pwret(NULL); /* Clear cache. */
+ endpwent();
+}
+
+/**************************************************************************
+ Wrapper for getpwnam(). Always returns a static that can be modified.
+****************************************************************************/
+
+struct passwd *sys_getpwnam(const char *name)
+{
+ if (!name || !name[0])
+ return NULL;
+
+ /* check for a cache hit first */
+ if (num_lookups && pw_cache.pass.pw_name && !strcmp(name, pw_cache.pass.pw_name)) {
+ return setup_pwret(&pw_cache.pass);
+ }
+
+ return setup_pwret(getpwnam(name));
+}
+
+/**************************************************************************
+ Wrapper for getpwuid(). Always returns a static that can be modified.
+****************************************************************************/
+
+struct passwd *sys_getpwuid(uid_t uid)
+{
+ if (num_lookups && pw_cache.pass.pw_name && (uid == pw_cache.pass.pw_uid)) {
+ return setup_pwret(&pw_cache.pass);
+ }
+
+ return setup_pwret(getpwuid(uid));
+}
+
+#if 0 /* NOT CURRENTLY USED - JRA */
+/**************************************************************************
+ The following are the UNICODE versions of *all* system interface functions
+ called within Samba. Ok, ok, the exceptions are the gethostbyXX calls,
+ which currently are left as ascii as they are not used other than in name
+ resolution.
+****************************************************************************/
+
+/**************************************************************************
+ Wide stat. Just narrow and call sys_xxx.
+****************************************************************************/
+
+int wsys_stat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
+{
+ pstring fname;
+ return sys_stat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
+}
+
+/**************************************************************************
+ Wide lstat. Just narrow and call sys_xxx.
+****************************************************************************/
+
+int wsys_lstat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
+{
+ pstring fname;
+ return sys_lstat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
+}
+
+/**************************************************************************
+ Wide creat. Just narrow and call sys_xxx.
+****************************************************************************/
+
+int wsys_creat(const smb_ucs2_t *wfname, mode_t mode)
+{
+ pstring fname;
+ return sys_creat(unicode_to_unix(fname,wfname,sizeof(fname)), mode);
+}
+
+/**************************************************************************
+ Wide open. Just narrow and call sys_xxx.
+****************************************************************************/
+
+int wsys_open(const smb_ucs2_t *wfname, int oflag, mode_t mode)
+{
+ pstring fname;
+ return sys_open(unicode_to_unix(fname,wfname,sizeof(fname)), oflag, mode);
+}
+
+/**************************************************************************
+ Wide fopen. Just narrow and call sys_xxx.
+****************************************************************************/
+
+FILE *wsys_fopen(const smb_ucs2_t *wfname, const char *type)
+{
+ pstring fname;
+ return sys_fopen(unicode_to_unix(fname,wfname,sizeof(fname)), type);
+}
+
+/**************************************************************************
+ Wide opendir. Just narrow and call sys_xxx.
+****************************************************************************/
+
+DIR *wsys_opendir(const smb_ucs2_t *wfname)
+{
+ pstring fname;
+ return opendir(unicode_to_unix(fname,wfname,sizeof(fname)));
+}
+
+/**************************************************************************
+ Wide readdir. Return a structure pointer containing a wide filename.
+****************************************************************************/
+
+SMB_STRUCT_WDIRENT *wsys_readdir(DIR *dirp)
+{
+ static SMB_STRUCT_WDIRENT retval;
+ SMB_STRUCT_DIRENT *dirval = sys_readdir(dirp);
+
+ if(!dirval)
+ return NULL;
+
+ /*
+ * The only POSIX defined member of this struct is d_name.
+ */
+
+ unix_to_unicode(retval.d_name,dirval->d_name,sizeof(retval.d_name));
+
+ return &retval;
+}
+
+/**************************************************************************
+ Wide getwd. Call sys_xxx and widen. Assumes s points to a wpstring.
+****************************************************************************/
+
+smb_ucs2_t *wsys_getwd(smb_ucs2_t *s)
+{
+ pstring fname;
+ char *p = sys_getwd(fname);
+
+ if(!p)
+ return NULL;
+
+ return unix_to_unicode(s, p, sizeof(wpstring));
+}
+
+/**************************************************************************
+ Wide chown. Just narrow and call sys_xxx.
+****************************************************************************/
+
+int wsys_chown(const smb_ucs2_t *wfname, uid_t uid, gid_t gid)
+{
+ pstring fname;
+ return chown(unicode_to_unix(fname,wfname,sizeof(fname)), uid, gid);
+}
+
+/**************************************************************************
+ Wide chroot. Just narrow and call sys_xxx.
+****************************************************************************/
+
+int wsys_chroot(const smb_ucs2_t *wfname)
+{
+ pstring fname;
+ return chroot(unicode_to_unix(fname,wfname,sizeof(fname)));
+}
+
+/**************************************************************************
+ Wide getpwnam. Return a structure pointer containing wide names.
+****************************************************************************/
+
+SMB_STRUCT_WPASSWD *wsys_getpwnam(const smb_ucs2_t *wname)
+{
+ static SMB_STRUCT_WPASSWD retval;
+ fstring name;
+ struct passwd *pwret = sys_getpwnam(unicode_to_unix(name,wname,sizeof(name)));
+
+ if(!pwret)
+ return NULL;
+
+ unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
+ retval.pw_passwd = pwret->pw_passwd;
+ retval.pw_uid = pwret->pw_uid;
+ retval.pw_gid = pwret->pw_gid;
+ unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
+ unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
+ unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
+
+ return &retval;
+}
+
+/**************************************************************************
+ Wide getpwuid. Return a structure pointer containing wide names.
+****************************************************************************/
+
+SMB_STRUCT_WPASSWD *wsys_getpwuid(uid_t uid)
+{
+ static SMB_STRUCT_WPASSWD retval;
+ struct passwd *pwret = sys_getpwuid(uid);
+
+ if(!pwret)
+ return NULL;
+
+ unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
+ retval.pw_passwd = pwret->pw_passwd;
+ retval.pw_uid = pwret->pw_uid;
+ retval.pw_gid = pwret->pw_gid;
+ unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
+ unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
+ unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
+
+ return &retval;
+}
+#endif /* NOT CURRENTLY USED - JRA */
+
+/**************************************************************************
+ Extract a command into an arg list. Uses a static pstring for storage.
+ Caller frees returned arg list (which contains pointers into the static pstring).
+****************************************************************************/
+
+static char **extract_args(const char *command)
+{
+ static pstring trunc_cmd;
+ char *ptr;
+ int argcl;
+ char **argl = NULL;
+ int i;
+
+ pstrcpy(trunc_cmd, command);
+
+ if(!(ptr = strtok(trunc_cmd, " \t"))) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /*
+ * Count the args.
+ */
+
+ for( argcl = 1; ptr; ptr = strtok(NULL, " \t"))
+ argcl++;
+
+ if((argl = (char **)malloc((argcl + 1) * sizeof(char *))) == NULL)
+ return NULL;
+
+ /*
+ * Now do the extraction.
+ */
+
+ pstrcpy(trunc_cmd, command);
+
+ ptr = strtok(trunc_cmd, " \t");
+ i = 0;
+ argl[i++] = ptr;
+
+ while((ptr = strtok(NULL, " \t")) != NULL)
+ argl[i++] = ptr;
+
+ argl[i++] = NULL;
+ return argl;
+}
+
+/**************************************************************************
+ Wrapper for fork. Ensures that mypid is reset. Used so we can write
+ a sys_getpid() that only does a system call *once*.
+****************************************************************************/
+
+static pid_t mypid = (pid_t)-1;
+
+pid_t sys_fork(void)
+{
+ pid_t forkret = fork();
+
+ if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
+ mypid = (pid_t) -1;
+
+ return forkret;
+}
+
+/**************************************************************************
+ Wrapper for getpid. Ensures we only do a system call *once*.
+****************************************************************************/
+
+pid_t sys_getpid(void)
+{
+ if (mypid == (pid_t)-1)
+ mypid = getpid();
+
+ return mypid;
+}
+
+/**************************************************************************
+ Wrapper for popen. Safer as it doesn't search a path.
+ Modified from the glibc sources.
+ modified by tridge to return a file descriptor. We must kick our FILE* habit
+****************************************************************************/
+
+typedef struct _popen_list
+{
+ int fd;
+ pid_t child_pid;
+ struct _popen_list *next;
+} popen_list;
+
+static popen_list *popen_chain;
+
+int sys_popen(const char *command)
+{
+ int parent_end, child_end;
+ int pipe_fds[2];
+ popen_list *entry = NULL;
+ char **argl = NULL;
+
+ if (pipe(pipe_fds) < 0)
+ return -1;
+
+ parent_end = pipe_fds[0];
+ child_end = pipe_fds[1];
+
+ if (!*command) {
+ errno = EINVAL;
+ goto err_exit;
+ }
+
+ if((entry = (popen_list *)malloc(sizeof(popen_list))) == NULL)
+ goto err_exit;
+
+ ZERO_STRUCTP(entry);
+
+ /*
+ * Extract the command and args into a NULL terminated array.
+ */
+
+ if(!(argl = extract_args(command)))
+ goto err_exit;
+
+ entry->child_pid = sys_fork();
+
+ if (entry->child_pid == -1) {
+ goto err_exit;
+ }
+
+ if (entry->child_pid == 0) {
+
+ /*
+ * Child !
+ */
+
+ int child_std_end = STDOUT_FILENO;
+ popen_list *p;
+
+ close(parent_end);
+ if (child_end != child_std_end) {
+ dup2 (child_end, child_std_end);
+ close (child_end);
+ }
+
+ /*
+ * POSIX.2: "popen() shall ensure that any streams from previous
+ * popen() calls that remain open in the parent process are closed
+ * in the new child process."
+ */
+
+ for (p = popen_chain; p; p = p->next)
+ close(p->fd);
+
+ execv(argl[0], argl);
+ _exit (127);
+ }
+
+ /*
+ * Parent.
+ */
+
+ close (child_end);
+ SAFE_FREE(argl);
+
+ /* Link into popen_chain. */
+ entry->next = popen_chain;
+ popen_chain = entry;
+ entry->fd = parent_end;
+
+ return entry->fd;
+
+err_exit:
+
+ SAFE_FREE(entry);
+ SAFE_FREE(argl);
+ close(pipe_fds[0]);
+ close(pipe_fds[1]);
+ return -1;
+}
+
+/**************************************************************************
+ Wrapper for pclose. Modified from the glibc sources.
+****************************************************************************/
+
+int sys_pclose(int fd)
+{
+ int wstatus;
+ popen_list **ptr = &popen_chain;
+ popen_list *entry = NULL;
+ pid_t wait_pid;
+ int status = -1;
+
+ /* Unlink from popen_chain. */
+ for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
+ if ((*ptr)->fd == fd) {
+ entry = *ptr;
+ *ptr = (*ptr)->next;
+ status = 0;
+ break;
+ }
+ }
+
+ if (status < 0 || close(entry->fd) < 0)
+ return -1;
+
+ /*
+ * As Samba is catching and eating child process
+ * exits we don't really care about the child exit
+ * code, a -1 with errno = ECHILD will do fine for us.
+ */
+
+ do {
+ wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
+ } while (wait_pid == -1 && errno == EINTR);
+
+ SAFE_FREE(entry);
+
+ if (wait_pid == -1)
+ return -1;
+ return wstatus;
+}
+
+/**************************************************************************
+ Wrappers for dlopen, dlsym, dlclose.
+****************************************************************************/
+
+void *sys_dlopen(const char *name, int flags)
+{
+#if defined(HAVE_LIBDL) || defined(HAVE_DLOPEN)
+ return dlopen(name, flags);
+#else
+ return NULL;
+#endif
+}
+
+void *sys_dlsym(void *handle, char *symbol)
+{
+#if defined(HAVE_LIBDL) || defined(HAVE_DLSYM)
+ return dlsym(handle, symbol);
+#else
+ return NULL;
+#endif
+}
+
+int sys_dlclose (void *handle)
+{
+#if defined(HAVE_LIBDL) || defined(HAVE_DLCLOSE)
+ return dlclose(handle);
+#else
+ return 0;
+#endif
+}
+
+const char *sys_dlerror(void)
+{
+#if defined(HAVE_LIBDL) || defined(HAVE_DLERROR)
+ return dlerror();
+#else
+ return NULL;
+#endif
+}
+
+/**************************************************************************
+ Wrapper for Admin Logs.
+****************************************************************************/
+
+void sys_adminlog(int priority, const char *format_str, ...)
+{
+ va_list ap;
+ int ret;
+ char **msgbuf = NULL;
+
+ if (!lp_admin_log())
+ return;
+
+ va_start( ap, format_str );
+ ret = vasprintf( msgbuf, format_str, ap );
+ va_end( ap );
+
+ if (ret == -1)
+ return;
+
+#if defined(HAVE_SYSLOG)
+ syslog( priority, "%s", *msgbuf );
#else
- return(chroot(dname));
+ DEBUG(0,("%s", *msgbuf ));
#endif
+ SAFE_FREE(*msgbuf);
}
diff --git a/source3/lib/talloc.c b/source3/lib/talloc.c
new file mode 100644
index 0000000000..6ac784a929
--- /dev/null
+++ b/source3/lib/talloc.c
@@ -0,0 +1,441 @@
+/*
+ Samba Unix SMB/CIFS implementation.
+ Samba temporary memory allocation functions
+ Copyright (C) Andrew Tridgell 2000
+ Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/**
+ @defgroup talloc Simple memory allocator
+ @{
+
+ This is a very simple temporary memory allocator. To use it do the following:
+
+ 1) when you first want to allocate a pool of meomry use
+ talloc_init() and save the resulting context pointer somewhere
+
+ 2) to allocate memory use talloc()
+
+ 3) when _all_ of the memory allocated using this context is no longer needed
+ use talloc_destroy()
+
+ talloc does not zero the memory. It guarantees memory of a
+ TALLOC_ALIGN alignment
+
+ @sa talloc.h
+*/
+
+/**
+ * @todo We could allocate both the talloc_chunk structure, and the
+ * memory it contains all in one allocation, which might be a bit
+ * faster and perhaps use less memory overhead.
+ *
+ * That smells like a premature optimization, though. -- mbp
+ **/
+
+/**
+ * If you want testing for memory corruption, link with dmalloc or use
+ * Insure++. It doesn't seem useful to duplicate them here.
+ **/
+
+#include "includes.h"
+
+struct talloc_chunk {
+ struct talloc_chunk *next;
+ size_t size;
+ void *ptr;
+};
+
+
+struct talloc_ctx {
+ struct talloc_chunk *list;
+ size_t total_alloc_size;
+
+ /** The name recorded for this pool, if any. Should describe
+ * the purpose for which it was allocated. The string is
+ * allocated within the pool. **/
+ char *name;
+
+ /** Pointer to the next allocate talloc pool, so that we can
+ * summarize all talloc memory usage. **/
+ struct talloc_ctx *next_ctx;
+};
+
+
+/**
+ * Start of linked list of all talloc pools.
+ *
+ * @todo We should turn the global list off when using Insure++,
+ * otherwise all the memory will be seen as still reachable.
+ **/
+TALLOC_CTX *list_head = NULL;
+
+
+/**
+ * Add to the global list
+ **/
+static void talloc_enroll(TALLOC_CTX *t)
+{
+ t->next_ctx = list_head;
+ list_head = t;
+}
+
+
+static void talloc_disenroll(TALLOC_CTX *t)
+{
+ TALLOC_CTX **ttmp;
+
+ /* Use a double-* so that no special case is required for the
+ * list head. */
+ for (ttmp = &list_head; *ttmp; ttmp = &((*ttmp)->next_ctx))
+ if (*ttmp == t) {
+ /* ttmp is the link that points to t, either
+ * list_head or the next_ctx link in its
+ * predecessor */
+ *ttmp = t->next_ctx;
+ t->next_ctx = NULL; /* clobber */
+ return;
+ }
+ abort(); /* oops, this talloc was already
+ * clobbered or something else went
+ * wrong. */
+}
+
+
+/** Create a new talloc context. **/
+TALLOC_CTX *talloc_init(void)
+{
+ TALLOC_CTX *t;
+
+ t = (TALLOC_CTX *)malloc(sizeof(TALLOC_CTX));
+ if (t) {
+ t->list = NULL;
+ t->total_alloc_size = 0;
+ t->name = NULL;
+ talloc_enroll(t);
+ }
+
+ return t;
+}
+
+
+
+/**
+ * Create a new talloc context, with a name specifying its purpose.
+ * Please call this in preference to talloc_init().
+ **/
+ TALLOC_CTX *talloc_init_named(char const *fmt, ...)
+{
+ TALLOC_CTX *t;
+ va_list ap;
+
+ t = talloc_init();
+ if (t && fmt) {
+ va_start(ap, fmt);
+ t->name = talloc_vasprintf(t, fmt, ap);
+ va_end(ap);
+ }
+
+ return t;
+}
+
+
+/** Allocate a bit of memory from the specified pool **/
+void *talloc(TALLOC_CTX *t, size_t size)
+{
+ void *p;
+ struct talloc_chunk *tc;
+
+ if (!t || size == 0) return NULL;
+
+ p = malloc(size);
+ if (p) {
+ tc = malloc(sizeof(*tc));
+ if (tc) {
+ tc->ptr = p;
+ tc->size = size;
+ tc->next = t->list;
+ t->list = tc;
+ t->total_alloc_size += size;
+ }
+ else {
+ SAFE_FREE(p);
+ }
+ }
+ return p;
+}
+
+/** A talloc version of realloc */
+void *talloc_realloc(TALLOC_CTX *t, void *ptr, size_t size)
+{
+ struct talloc_chunk *tc;
+ void *new_ptr;
+
+ /* size zero is equivalent to free() */
+ if (!t || size == 0)
+ return NULL;
+
+ /* realloc(NULL) is equavalent to malloc() */
+ if (ptr == NULL)
+ return talloc(t, size);
+
+ for (tc=t->list; tc; tc=tc->next) {
+ if (tc->ptr == ptr) {
+ new_ptr = Realloc(ptr, size);
+ if (new_ptr) {
+ t->total_alloc_size += (size - tc->size);
+ tc->size = size;
+ tc->ptr = new_ptr;
+ }
+ return new_ptr;
+ }
+ }
+ return NULL;
+}
+
+/** Destroy all the memory allocated inside @p t, but not @p t
+ * itself. */
+void talloc_destroy_pool(TALLOC_CTX *t)
+{
+ struct talloc_chunk *c;
+
+ if (!t)
+ return;
+
+ while (t->list) {
+ c = t->list->next;
+ SAFE_FREE(t->list->ptr);
+ SAFE_FREE(t->list);
+ t->list = c;
+ }
+
+ t->total_alloc_size = 0;
+}
+
+/** Destroy a whole pool including the context */
+void talloc_destroy(TALLOC_CTX *t)
+{
+ if (!t)
+ return;
+
+ talloc_destroy_pool(t);
+ talloc_disenroll(t);
+ memset(t, 0, sizeof(TALLOC_CTX));
+ SAFE_FREE(t);
+}
+
+/** Return the current total size of the pool. */
+size_t talloc_pool_size(TALLOC_CTX *t)
+{
+ if (t)
+ return t->total_alloc_size;
+ else
+ return 0;
+}
+
+const char * talloc_pool_name(TALLOC_CTX const *t)
+{
+ if (t)
+ return t->name;
+ else
+ return NULL;
+}
+
+
+/** talloc and zero memory. */
+void *talloc_zero(TALLOC_CTX *t, size_t size)
+{
+ void *p = talloc(t, size);
+
+ if (p)
+ memset(p, '\0', size);
+
+ return p;
+}
+
+/** memdup with a talloc. */
+void *talloc_memdup(TALLOC_CTX *t, const void *p, size_t size)
+{
+ void *newp = talloc(t,size);
+
+ if (newp)
+ memcpy(newp, p, size);
+
+ return newp;
+}
+
+/** strdup with a talloc */
+char *talloc_strdup(TALLOC_CTX *t, const char *p)
+{
+ if (p)
+ return talloc_memdup(t, p, strlen(p) + 1);
+ else
+ return NULL;
+}
+
+/**
+ * Perform string formatting, and return a pointer to newly allocated
+ * memory holding the result, inside a memory pool.
+ **/
+ char *talloc_asprintf(TALLOC_CTX *t, const char *fmt, ...)
+{
+ va_list ap;
+ char *ret;
+
+ va_start(ap, fmt);
+ ret = talloc_vasprintf(t, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+
+ char *talloc_vasprintf(TALLOC_CTX *t, const char *fmt, va_list ap)
+{
+ int len;
+ char *ret;
+
+ len = vsnprintf(NULL, 0, fmt, ap);
+
+ ret = talloc(t, len+1);
+ if (ret)
+ vsnprintf(ret, len+1, fmt, ap);
+
+ return ret;
+}
+
+
+/**
+ * Realloc @p s to append the formatted result of @p fmt and return @p
+ * s, which may have moved. Good for gradually accumulating output
+ * into a string buffer.
+ **/
+ char *talloc_asprintf_append(TALLOC_CTX *t, char *s,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ s = talloc_vasprintf_append(t, s, fmt, ap);
+ va_end(ap);
+ return s;
+}
+
+
+
+/**
+ * Realloc @p s to append the formatted result of @p fmt and @p ap,
+ * and return @p s, which may have moved. Good for gradually
+ * accumulating output into a string buffer.
+ **/
+ char *talloc_vasprintf_append(TALLOC_CTX *t, char *s,
+ const char *fmt, va_list ap)
+{
+ int len, s_len;
+
+ s_len = strlen(s);
+ len = vsnprintf(NULL, 0, fmt, ap);
+
+ s = talloc_realloc(t, s, s_len + len+1);
+ if (!s) return NULL;
+
+ vsnprintf(s+s_len, len+1, fmt, ap);
+
+ return s;
+}
+
+
+/**
+ * Return a human-readable description of all talloc memory usage.
+ * The result is allocated from @p t.
+ **/
+char *talloc_describe_all(TALLOC_CTX *rt)
+{
+ int n_pools = 0, total_chunks = 0;
+ size_t total_bytes = 0;
+ TALLOC_CTX *it;
+ char *s;
+
+ if (!rt) return NULL;
+
+ s = talloc_asprintf(rt, "global talloc allocations in pid: %u\n",
+ (unsigned) sys_getpid());
+ s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n",
+ "name", "chunks", "bytes");
+ s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n",
+ "----------------------------------------",
+ "--------",
+ "--------");
+
+ for (it = list_head; it; it = it->next_ctx) {
+ size_t bytes;
+ int n_chunks;
+ fstring what;
+
+ n_pools++;
+
+ talloc_get_allocation(it, &bytes, &n_chunks);
+
+ if (it->name)
+ fstrcpy(what, it->name);
+ else
+ slprintf(what, sizeof what, "@%p", it);
+
+ s = talloc_asprintf_append(rt, s, "%-40s %8u %8u\n",
+ what,
+ (unsigned) n_chunks,
+ (unsigned) bytes);
+ total_bytes += bytes;
+ total_chunks += n_chunks;
+ }
+
+ s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n",
+ "----------------------------------------",
+ "--------",
+ "--------");
+
+ s = talloc_asprintf_append(rt, s, "%-40s %8u %8u\n",
+ "TOTAL",
+ (unsigned) total_chunks, (unsigned) total_bytes);
+
+ return s;
+}
+
+
+
+/**
+ * Return an estimated memory usage for the specified pool. This does
+ * not include memory used by the underlying malloc implementation.
+ **/
+void talloc_get_allocation(TALLOC_CTX *t,
+ size_t *total_bytes,
+ int *n_chunks)
+{
+ struct talloc_chunk *chunk;
+
+ if (t) {
+ *total_bytes = 0;
+ *n_chunks = 0;
+
+ for (chunk = t->list; chunk; chunk = chunk->next) {
+ n_chunks[0]++;
+ *total_bytes += chunk->size;
+ }
+ }
+}
+
+
+/** @} */
diff --git a/source3/lib/tallocmsg.c b/source3/lib/tallocmsg.c
new file mode 100644
index 0000000000..608cdad452
--- /dev/null
+++ b/source3/lib/tallocmsg.c
@@ -0,0 +1,58 @@
+/*
+ samba -- Unix SMB/CIFS implementation.
+ Copyright (C) 2001, 2002 by Martin Pool
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/**
+ * @file tallocmsg.c
+ *
+ * Glue code between talloc profiling and the Samba messaging system.
+ **/
+
+
+/**
+ * Respond to a POOL_USAGE message by sending back string form of memory
+ * usage stats.
+ **/
+void msg_pool_usage(int msg_type, pid_t src_pid,
+ void *UNUSED(buf), size_t UNUSED(len))
+{
+ char *reply;
+ TALLOC_CTX *reply_pool = talloc_init_named("msg_pool_usage");
+
+ SMB_ASSERT(msg_type == MSG_REQ_POOL_USAGE);
+
+ DEBUG(2,("Got POOL_USAGE\n"));
+
+ reply = talloc_describe_all(reply_pool);
+
+ message_send_pid(src_pid, MSG_POOL_USAGE,
+ reply, strlen(reply)+1, True);
+
+ talloc_destroy(reply_pool);
+}
+
+/**
+ * Register handler for MSG_REQ_POOL_USAGE
+ **/
+void register_msg_pool_usage(void)
+{
+ message_register(MSG_REQ_POOL_USAGE, msg_pool_usage);
+ DEBUG(2, ("Registered MSG_REQ_POOL_USAGE\n"));
+}
diff --git a/source3/lib/talloctort.c b/source3/lib/talloctort.c
new file mode 100644
index 0000000000..3a64803776
--- /dev/null
+++ b/source3/lib/talloctort.c
@@ -0,0 +1,65 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba temporary memory allocation functions -- torturer
+ Copyright (C) 2001 by Martin Pool <mbp@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#define NCTX 10
+#define NOBJ 20
+
+int main(void)
+{
+ int i;
+ TALLOC_CTX *ctx[NCTX];
+
+ for (i = 0; i < NCTX; i++) {
+ ctx[i] = talloc_init_named("torture(%d)", i);
+ }
+
+ for (i = 0; i < NCTX; i++) {
+ int j;
+ for (j = 0; j < NOBJ; j++) {
+ char *p;
+ size_t size = 1<<(i/3+j);
+
+ p = talloc(ctx[i], size);
+ if (!p) {
+ fprintf(stderr,
+ "failed to talloc %.0f bytes\n",
+ (double) size);
+ exit(1);
+ }
+
+ memset(p, 'A' + j, size);
+ }
+ }
+
+ for (i = 0; i < NCTX; i++) {
+ printf("talloc@%p %-40s %dkB\n", ctx[i],
+ talloc_pool_name(ctx[i]),
+ talloc_pool_size(ctx[i]) >> 10);
+ }
+
+ printf("%s", talloc_describe_all(ctx[0]));
+
+ for (i = NCTX - 1; i >= 0; i--)
+ talloc_destroy(ctx[i]);
+
+ return 0;
+}
diff --git a/source3/lib/time.c b/source3/lib/time.c
new file mode 100644
index 0000000000..5fc43612dd
--- /dev/null
+++ b/source3/lib/time.c
@@ -0,0 +1,749 @@
+/*
+ Unix SMB/CIFS implementation.
+ time handling functions
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ This stuff was largely rewritten by Paul Eggert <eggert@twinsun.com>
+ in May 1996
+ */
+
+
+int extra_time_offset = 0;
+
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+#ifndef TIME_T_MIN
+#define TIME_T_MIN ((time_t)0 < (time_t) -1 ? (time_t) 0 \
+ : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
+#endif
+#ifndef TIME_T_MAX
+#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
+#endif
+
+/*******************************************************************
+ External access to time_t_min and time_t_max.
+********************************************************************/
+
+time_t get_time_t_min(void)
+{
+ return TIME_T_MIN;
+}
+
+time_t get_time_t_max(void)
+{
+ return TIME_T_MAX;
+}
+
+/*******************************************************************
+a gettimeofday wrapper
+********************************************************************/
+void GetTimeOfDay(struct timeval *tval)
+{
+#ifdef HAVE_GETTIMEOFDAY_TZ
+ gettimeofday(tval,NULL);
+#else
+ gettimeofday(tval);
+#endif
+}
+
+#define TM_YEAR_BASE 1900
+
+/*******************************************************************
+yield the difference between *A and *B, in seconds, ignoring leap seconds
+********************************************************************/
+static int tm_diff(struct tm *a, struct tm *b)
+{
+ int ay = a->tm_year + (TM_YEAR_BASE - 1);
+ int by = b->tm_year + (TM_YEAR_BASE - 1);
+ int intervening_leap_days =
+ (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
+ int years = ay - by;
+ int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday);
+ int hours = 24*days + (a->tm_hour - b->tm_hour);
+ int minutes = 60*hours + (a->tm_min - b->tm_min);
+ int seconds = 60*minutes + (a->tm_sec - b->tm_sec);
+
+ return seconds;
+}
+
+/*******************************************************************
+ return the UTC offset in seconds west of UTC, or 0 if it cannot be determined
+ ******************************************************************/
+static int TimeZone(time_t t)
+{
+ struct tm *tm = gmtime(&t);
+ struct tm tm_utc;
+ if (!tm)
+ return 0;
+ tm_utc = *tm;
+ tm = localtime(&t);
+ if (!tm)
+ return 0;
+ return tm_diff(&tm_utc,tm);
+
+}
+
+static BOOL done_serverzone_init;
+
+/* Return the smb serverzone value */
+
+static int get_serverzone(void)
+{
+ static int serverzone;
+
+ if (!done_serverzone_init) {
+ serverzone = TimeZone(time(NULL));
+
+ if ((serverzone % 60) != 0) {
+ DEBUG(1,("WARNING: Your timezone is not a multiple of 1 minute.\n"));
+ }
+
+ DEBUG(4,("Serverzone is %d\n",serverzone));
+
+ done_serverzone_init = True;
+ }
+
+ return serverzone;
+}
+
+/* Re-read the smb serverzone value */
+
+static struct timeval start_time_hires;
+
+void TimeInit(void)
+{
+ done_serverzone_init = False;
+ get_serverzone();
+ /* Save the start time of this process. */
+ if (start_time_hires.tv_sec == 0 && start_time_hires.tv_usec == 0)
+ GetTimeOfDay(&start_time_hires);
+}
+
+/**********************************************************************
+ Return a timeval struct of the uptime of this process. As TimeInit is
+ done before a daemon fork then this is the start time from the parent
+ daemon start. JRA.
+***********************************************************************/
+
+void get_process_uptime(struct timeval *ret_time)
+{
+ struct timeval time_now_hires;
+
+ GetTimeOfDay(&time_now_hires);
+ ret_time->tv_sec = time_now_hires.tv_sec - start_time_hires.tv_sec;
+ ret_time->tv_usec = time_now_hires.tv_usec - start_time_hires.tv_usec;
+ if (time_now_hires.tv_usec < start_time_hires.tv_usec) {
+ ret_time->tv_sec -= 1;
+ ret_time->tv_usec = 1000000 + (time_now_hires.tv_usec - start_time_hires.tv_usec);
+ } else
+ ret_time->tv_usec = time_now_hires.tv_usec - start_time_hires.tv_usec;
+}
+
+/*******************************************************************
+return the same value as TimeZone, but it should be more efficient.
+
+We keep a table of DST offsets to prevent calling localtime() on each
+call of this function. This saves a LOT of time on many unixes.
+
+Updated by Paul Eggert <eggert@twinsun.com>
+********************************************************************/
+static int TimeZoneFaster(time_t t)
+{
+ static struct dst_table {time_t start,end; int zone;} *tdt, *dst_table = NULL;
+ static int table_size = 0;
+ int i;
+ int zone = 0;
+
+ if (t == 0) t = time(NULL);
+
+ /* Tunis has a 8 day DST region, we need to be careful ... */
+#define MAX_DST_WIDTH (365*24*60*60)
+#define MAX_DST_SKIP (7*24*60*60)
+
+ for (i=0;i<table_size;i++)
+ if (t >= dst_table[i].start && t <= dst_table[i].end) break;
+
+ if (i<table_size) {
+ zone = dst_table[i].zone;
+ } else {
+ time_t low,high;
+
+ zone = TimeZone(t);
+ tdt = (struct dst_table *)Realloc(dst_table,
+ sizeof(dst_table[0])*(i+1));
+ if (!tdt) {
+ DEBUG(0,("TimeZoneFaster: out of memory!\n"));
+ SAFE_FREE(dst_table);
+ table_size = 0;
+ } else {
+ dst_table = tdt;
+ table_size++;
+
+ dst_table[i].zone = zone;
+ dst_table[i].start = dst_table[i].end = t;
+
+ /* no entry will cover more than 6 months */
+ low = t - MAX_DST_WIDTH/2;
+ if (t < low)
+ low = TIME_T_MIN;
+
+ high = t + MAX_DST_WIDTH/2;
+ if (high < t)
+ high = TIME_T_MAX;
+
+ /* widen the new entry using two bisection searches */
+ while (low+60*60 < dst_table[i].start) {
+ if (dst_table[i].start - low > MAX_DST_SKIP*2)
+ t = dst_table[i].start - MAX_DST_SKIP;
+ else
+ t = low + (dst_table[i].start-low)/2;
+ if (TimeZone(t) == zone)
+ dst_table[i].start = t;
+ else
+ low = t;
+ }
+
+ while (high-60*60 > dst_table[i].end) {
+ if (high - dst_table[i].end > MAX_DST_SKIP*2)
+ t = dst_table[i].end + MAX_DST_SKIP;
+ else
+ t = high - (high-dst_table[i].end)/2;
+ if (TimeZone(t) == zone)
+ dst_table[i].end = t;
+ else
+ high = t;
+ }
+#if 0
+ DEBUG(1,("Added DST entry from %s ",
+ asctime(localtime(&dst_table[i].start))));
+ DEBUG(1,("to %s (%d)\n",asctime(localtime(&dst_table[i].end)),
+ dst_table[i].zone));
+#endif
+ }
+ }
+ return zone;
+}
+
+/****************************************************************************
+ return the UTC offset in seconds west of UTC, adjusted for extra time offset
+ **************************************************************************/
+int TimeDiff(time_t t)
+{
+ return TimeZoneFaster(t) + 60*extra_time_offset;
+}
+
+
+/****************************************************************************
+ return the UTC offset in seconds west of UTC, adjusted for extra time
+ offset, for a local time value. If ut = lt + LocTimeDiff(lt), then
+ lt = ut - TimeDiff(ut), but the converse does not necessarily hold near
+ daylight savings transitions because some local times are ambiguous.
+ LocTimeDiff(t) equals TimeDiff(t) except near daylight savings transitions.
+ +**************************************************************************/
+static int LocTimeDiff(time_t lte)
+{
+ time_t lt = lte - 60*extra_time_offset;
+ int d = TimeZoneFaster(lt);
+ time_t t = lt + d;
+
+ /* if overflow occurred, ignore all the adjustments so far */
+ if (((lte < lt) ^ (extra_time_offset < 0)) | ((t < lt) ^ (d < 0)))
+ t = lte;
+
+ /* now t should be close enough to the true UTC to yield the right answer */
+ return TimeDiff(t);
+}
+
+
+/****************************************************************************
+try to optimise the localtime call, it can be quite expensive on some machines
+****************************************************************************/
+struct tm *LocalTime(time_t *t)
+{
+ time_t t2 = *t;
+
+ t2 -= TimeDiff(t2);
+
+ return(gmtime(&t2));
+}
+
+#define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
+
+/****************************************************************************
+interpret an 8 byte "filetime" structure to a time_t
+It's originally in "100ns units since jan 1st 1601"
+
+It appears to be kludge-GMT (at least for file listings). This means
+its the GMT you get by taking a localtime and adding the
+serverzone. This is NOT the same as GMT in some cases. This routine
+converts this to real GMT.
+****************************************************************************/
+time_t nt_time_to_unix(NTTIME *nt)
+{
+ double d;
+ time_t ret;
+ /* The next two lines are a fix needed for the
+ broken SCO compiler. JRA. */
+ time_t l_time_min = TIME_T_MIN;
+ time_t l_time_max = TIME_T_MAX;
+
+ if (nt->high == 0) return(0);
+
+ d = ((double)nt->high)*4.0*(double)(1<<30);
+ d += (nt->low&0xFFF00000);
+ d *= 1.0e-7;
+
+ /* now adjust by 369 years to make the secs since 1970 */
+ d -= TIME_FIXUP_CONSTANT;
+
+ if (!(l_time_min <= d && d <= l_time_max))
+ return(0);
+
+ ret = (time_t)(d+0.5);
+
+ /* this takes us from kludge-GMT to real GMT */
+ ret -= get_serverzone();
+ ret += LocTimeDiff(ret);
+
+ return(ret);
+}
+
+/****************************************************************************
+convert a NTTIME structure to a time_t
+It's originally in "100ns units"
+
+this is an absolute version of the one above.
+By absolute I mean, it doesn't adjust from 1/1/1601 to 1/1/1970
+if the NTTIME was 5 seconds, the time_t is 5 seconds. JFM
+****************************************************************************/
+time_t nt_time_to_unix_abs(NTTIME *nt)
+{
+ double d;
+ time_t ret;
+ /* The next two lines are a fix needed for the
+ broken SCO compiler. JRA. */
+ time_t l_time_min = TIME_T_MIN;
+ time_t l_time_max = TIME_T_MAX;
+
+ if (nt->high == 0)
+ return(0);
+
+ if (nt->high==0x80000000 && nt->low==0)
+ return -1;
+
+ /* reverse the time */
+ /* it's a negative value, turn it to positive */
+ nt->high=~nt->high;
+ nt->low=~nt->low;
+
+ d = ((double)nt->high)*4.0*(double)(1<<30);
+ d += (nt->low&0xFFF00000);
+ d *= 1.0e-7;
+
+ if (!(l_time_min <= d && d <= l_time_max))
+ return(0);
+
+ ret = (time_t)(d+0.5);
+
+ /* this takes us from kludge-GMT to real GMT */
+ ret -= get_serverzone();
+ ret += LocTimeDiff(ret);
+
+ return(ret);
+}
+
+
+
+/****************************************************************************
+interprets an nt time into a unix time_t
+****************************************************************************/
+time_t interpret_long_date(char *p)
+{
+ NTTIME nt;
+ nt.low = IVAL(p,0);
+ nt.high = IVAL(p,4);
+ return nt_time_to_unix(&nt);
+}
+
+/****************************************************************************
+put a 8 byte filetime from a time_t
+This takes real GMT as input and converts to kludge-GMT
+****************************************************************************/
+void unix_to_nt_time(NTTIME *nt, time_t t)
+{
+ double d;
+
+ if (t==0)
+ {
+ nt->low = 0;
+ nt->high = 0;
+ return;
+ }
+ if (t == TIME_T_MAX)
+ {
+ nt->low = 0xffffffff;
+ nt->high = 0x7fffffff;
+ return;
+ }
+ if (t == -1)
+ {
+ nt->low = 0xffffffff;
+ nt->high = 0xffffffff;
+ return;
+ }
+
+ /* this converts GMT to kludge-GMT */
+ t -= LocTimeDiff(t) - get_serverzone();
+
+ d = (double)(t);
+ d += TIME_FIXUP_CONSTANT;
+ d *= 1.0e7;
+
+ nt->high = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
+ nt->low = (uint32)(d - ((double)nt->high)*4.0*(double)(1<<30));
+}
+
+/****************************************************************************
+convert a time_t to a NTTIME structure
+
+this is an absolute version of the one above.
+By absolute I mean, it doesn't adjust from 1/1/1970 to 1/1/1601
+if the nttime_t was 5 seconds, the NTTIME is 5 seconds. JFM
+****************************************************************************/
+void unix_to_nt_time_abs(NTTIME *nt, time_t t)
+{
+ double d;
+
+ if (t==0) {
+ nt->low = 0;
+ nt->high = 0;
+ return;
+ }
+
+ if (t == TIME_T_MAX) {
+ nt->low = 0xffffffff;
+ nt->high = 0x7fffffff;
+ return;
+ }
+
+ if (t == -1) {
+ /* that's what NT uses for infinite */
+ nt->low = 0x0;
+ nt->high = 0x80000000;
+ return;
+ }
+
+ /* this converts GMT to kludge-GMT */
+ t -= LocTimeDiff(t) - get_serverzone();
+
+ d = (double)(t);
+ d *= 1.0e7;
+
+ nt->high = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
+ nt->low = (uint32)(d - ((double)nt->high)*4.0*(double)(1<<30));
+
+ /* convert to a negative value */
+ nt->high=~nt->high;
+ nt->low=~nt->low;
+}
+
+
+/****************************************************************************
+take an NTTIME structure, containing high / low time. convert to unix time.
+lkclXXXX this may need 2 SIVALs not a memcpy. we'll see...
+****************************************************************************/
+void put_long_date(char *p,time_t t)
+{
+ NTTIME nt;
+ unix_to_nt_time(&nt, t);
+ SIVAL(p, 0, nt.low);
+ SIVAL(p, 4, nt.high);
+}
+
+/****************************************************************************
+check if it's a null mtime
+****************************************************************************/
+BOOL null_mtime(time_t mtime)
+{
+ if (mtime == 0 || mtime == 0xFFFFFFFF || mtime == (time_t)-1)
+ return(True);
+ return(False);
+}
+
+/*******************************************************************
+ create a 16 bit dos packed date
+********************************************************************/
+static uint16 make_dos_date1(struct tm *t)
+{
+ uint16 ret=0;
+ ret = (((unsigned)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1);
+ ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5));
+ return(ret);
+}
+
+/*******************************************************************
+ create a 16 bit dos packed time
+********************************************************************/
+static uint16 make_dos_time1(struct tm *t)
+{
+ uint16 ret=0;
+ ret = ((((unsigned)t->tm_min >> 3)&0x7) | (((unsigned)t->tm_hour) << 3));
+ ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5));
+ return(ret);
+}
+
+/*******************************************************************
+ create a 32 bit dos packed date/time from some parameters
+ This takes a GMT time and returns a packed localtime structure
+********************************************************************/
+static uint32 make_dos_date(time_t unixdate)
+{
+ struct tm *t;
+ uint32 ret=0;
+
+ t = LocalTime(&unixdate);
+ if (!t)
+ return 0xFFFFFFFF;
+
+ ret = make_dos_date1(t);
+ ret = ((ret&0xFFFF)<<16) | make_dos_time1(t);
+
+ return(ret);
+}
+
+/*******************************************************************
+put a dos date into a buffer (time/date format)
+This takes GMT time and puts local time in the buffer
+********************************************************************/
+void put_dos_date(char *buf,int offset,time_t unixdate)
+{
+ uint32 x = make_dos_date(unixdate);
+ SIVAL(buf,offset,x);
+}
+
+/*******************************************************************
+put a dos date into a buffer (date/time format)
+This takes GMT time and puts local time in the buffer
+********************************************************************/
+void put_dos_date2(char *buf,int offset,time_t unixdate)
+{
+ uint32 x = make_dos_date(unixdate);
+ x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+ SIVAL(buf,offset,x);
+}
+
+/*******************************************************************
+put a dos 32 bit "unix like" date into a buffer. This routine takes
+GMT and converts it to LOCAL time before putting it (most SMBs assume
+localtime for this sort of date)
+********************************************************************/
+void put_dos_date3(char *buf,int offset,time_t unixdate)
+{
+ if (!null_mtime(unixdate))
+ unixdate -= TimeDiff(unixdate);
+ SIVAL(buf,offset,unixdate);
+}
+
+/*******************************************************************
+ interpret a 32 bit dos packed date/time to some parameters
+********************************************************************/
+static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second)
+{
+ uint32 p0,p1,p2,p3;
+
+ p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF;
+ p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF;
+
+ *second = 2*(p0 & 0x1F);
+ *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3);
+ *hour = (p1>>3)&0xFF;
+ *day = (p2&0x1F);
+ *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1;
+ *year = ((p3>>1)&0xFF) + 80;
+}
+
+/*******************************************************************
+ create a unix date (int GMT) from a dos date (which is actually in
+ localtime)
+********************************************************************/
+time_t make_unix_date(void *date_ptr)
+{
+ uint32 dos_date=0;
+ struct tm t;
+ time_t ret;
+
+ dos_date = IVAL(date_ptr,0);
+
+ if (dos_date == 0) return(0);
+
+ interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
+ &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
+ t.tm_isdst = -1;
+
+ /* mktime() also does the local to GMT time conversion for us */
+ ret = mktime(&t);
+
+ return(ret);
+}
+
+/*******************************************************************
+like make_unix_date() but the words are reversed
+********************************************************************/
+time_t make_unix_date2(void *date_ptr)
+{
+ uint32 x,x2;
+
+ x = IVAL(date_ptr,0);
+ x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+ SIVAL(&x,0,x2);
+
+ return(make_unix_date((void *)&x));
+}
+
+/*******************************************************************
+ create a unix GMT date from a dos date in 32 bit "unix like" format
+ these generally arrive as localtimes, with corresponding DST
+ ******************************************************************/
+time_t make_unix_date3(void *date_ptr)
+{
+ time_t t = (time_t)IVAL(date_ptr,0);
+ if (!null_mtime(t))
+ t += LocTimeDiff(t);
+ return(t);
+}
+
+
+/***************************************************************************
+return a HTTP/1.0 time string
+ ***************************************************************************/
+char *http_timestring(time_t t)
+{
+ static fstring buf;
+ struct tm *tm = LocalTime(&t);
+
+ if (!tm)
+ slprintf(buf,sizeof(buf)-1,"%ld seconds since the Epoch",(long)t);
+ else
+#ifndef HAVE_STRFTIME
+ fstrcpy(buf, asctime(tm));
+ if(buf[strlen(buf)-1] == '\n')
+ buf[strlen(buf)-1] = 0;
+#else /* !HAVE_STRFTIME */
+ strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S %Z", tm);
+#endif /* !HAVE_STRFTIME */
+ return buf;
+}
+
+
+
+/****************************************************************************
+ Return the date and time as a string
+****************************************************************************/
+
+char *timestring(BOOL hires)
+{
+ static fstring TimeBuf;
+ struct timeval tp;
+ time_t t;
+ struct tm *tm;
+
+ if (hires) {
+ GetTimeOfDay(&tp);
+ t = (time_t)tp.tv_sec;
+ } else {
+ t = time(NULL);
+ }
+ tm = LocalTime(&t);
+ if (!tm) {
+ if (hires) {
+ slprintf(TimeBuf,
+ sizeof(TimeBuf)-1,
+ "%ld.%06ld seconds since the Epoch",
+ (long)tp.tv_sec,
+ (long)tp.tv_usec);
+ } else {
+ slprintf(TimeBuf,
+ sizeof(TimeBuf)-1,
+ "%ld seconds since the Epoch",
+ (long)t);
+ }
+ } else {
+#ifdef HAVE_STRFTIME
+ if (hires) {
+ strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm);
+ slprintf(TimeBuf+strlen(TimeBuf),
+ sizeof(TimeBuf)-1 - strlen(TimeBuf),
+ ".%06ld",
+ (long)tp.tv_usec);
+ } else {
+ strftime(TimeBuf,100,"%Y/%m/%d %H:%M:%S",tm);
+ }
+#else
+ if (hires) {
+ slprintf(TimeBuf,
+ sizeof(TimeBuf)-1,
+ "%s.%06ld",
+ asctime(tm),
+ (long)tp.tv_usec);
+ } else {
+ fstrcpy(TimeBuf, asctime(tm));
+ }
+#endif
+ }
+ return(TimeBuf);
+}
+
+/****************************************************************************
+ return the best approximation to a 'create time' under UNIX from a stat
+ structure.
+****************************************************************************/
+
+time_t get_create_time(SMB_STRUCT_STAT *st,BOOL fake_dirs)
+{
+ time_t ret, ret1;
+
+ if(S_ISDIR(st->st_mode) && fake_dirs)
+ return (time_t)315493200L; /* 1/1/1980 */
+
+ ret = MIN(st->st_ctime, st->st_mtime);
+ ret1 = MIN(ret, st->st_atime);
+
+ if(ret1 != (time_t)0)
+ return ret1;
+
+ /*
+ * One of ctime, mtime or atime was zero (probably atime).
+ * Just return MIN(ctime, mtime).
+ */
+ return ret;
+}
+
+/****************************************************************************
+initialise an NTTIME to -1, which means "unknown" or "don't expire"
+****************************************************************************/
+
+void init_nt_time(NTTIME *nt)
+{
+ nt->high = 0x7FFFFFFF;
+ nt->low = 0xFFFFFFFF;
+}
diff --git a/source3/lib/ufc.c b/source3/lib/ufc.c
index 8417285821..ecc04d9e97 100644
--- a/source3/lib/ufc.c
+++ b/source3/lib/ufc.c
@@ -16,12 +16,14 @@
*/
-#ifdef UFC_CRYPT
+#include "includes.h"
+
+#ifndef HAVE_CRYPT
/*
* UFC-crypt: ultra fast crypt(3) implementation
*
- * Copyright (C) 1991, 1992, Free Software Foundation, Inc.
+ * Copyright (C) 1991-1998, Free Software Foundation, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -42,7 +44,6 @@
* Support routines
*
*/
-#include "includes.h"
#ifndef long32
@@ -281,9 +282,7 @@ static ufc_long longmask[32] = {
* bzero and some don't have memset.
*/
-static void clearmem(start, cnt)
- char *start;
- int cnt;
+static void clearmem(char *start, int cnt)
{ while(cnt--)
*start++ = '\0';
}
@@ -299,7 +298,7 @@ static int initialized = 0;
* by fcrypt users.
*/
-static void ufc_init_des()
+static void ufc_init_des(void)
{ int comes_from_bit;
int bit, sg;
ufc_long j;
@@ -350,13 +349,13 @@ static void ufc_init_des()
clearmem((char*)eperm32tab, sizeof(eperm32tab));
for(bit = 0; bit < 48; bit++) {
- ufc_long mask1,comes_from;
+ ufc_long inner_mask1,comes_from;
comes_from = perm32[esel[bit]-1]-1;
- mask1 = bytemask[comes_from % 8];
+ inner_mask1 = bytemask[comes_from % 8];
for(j = 256; j--;) {
- if(j & mask1)
+ if(j & inner_mask1)
eperm32tab[comes_from / 8][j][bit / 24] |= BITMASK(bit % 24);
}
}
@@ -431,7 +430,7 @@ static void ufc_init_des()
clearmem((char*)efp, sizeof efp);
for(bit = 0; bit < 64; bit++) {
int o_bit, o_long;
- ufc_long word_value, mask1, mask2;
+ ufc_long word_value, inner_mask1, inner_mask2;
int comes_from_f_bit, comes_from_e_bit;
int comes_from_word, bit_within_word;
@@ -451,12 +450,12 @@ static void ufc_init_des()
comes_from_word = comes_from_e_bit / 6; /* 0..15 */
bit_within_word = comes_from_e_bit % 6; /* 0..5 */
- mask1 = longmask[bit_within_word + 26];
- mask2 = longmask[o_bit];
+ inner_mask1 = longmask[bit_within_word + 26];
+ inner_mask2 = longmask[o_bit];
for(word_value = 64; word_value--;) {
- if(word_value & mask1)
- efp[comes_from_word][word_value][o_long] |= mask2;
+ if(word_value & inner_mask1)
+ efp[comes_from_word][word_value][o_long] |= inner_mask2;
}
}
initialized++;
@@ -468,9 +467,7 @@ static void ufc_init_des()
*/
#ifdef _UFC_32_
-static void shuffle_sb(k, saltbits)
- long32 *k;
- ufc_long saltbits;
+static void shuffle_sb(long32 *k, ufc_long saltbits)
{ ufc_long j;
long32 x;
for(j=4096; j--;) {
@@ -482,9 +479,7 @@ static void shuffle_sb(k, saltbits)
#endif
#ifdef _UFC_64_
-static void shuffle_sb(k, saltbits)
- long64 *k;
- ufc_long saltbits;
+static void shuffle_sb(long64 *k, ufc_long saltbits)
{ ufc_long j;
long64 x;
for(j=4096; j--;) {
@@ -503,9 +498,9 @@ static unsigned char current_salt[3] = "&&"; /* invalid value */
static ufc_long current_saltbits = 0;
static int direction = 0;
-static void setup_salt(char *s1)
+static void setup_salt(const char *s1)
{ ufc_long i, j, saltbits;
- unsigned char *s2 = (unsigned char *)s1;
+ const unsigned char *s2 = (const unsigned char *)s1;
if(!initialized)
ufc_init_des();
@@ -543,8 +538,7 @@ static void setup_salt(char *s1)
current_saltbits = saltbits;
}
-static void ufc_mk_keytab(key)
- char *key;
+static void ufc_mk_keytab(char *key)
{ ufc_long v1, v2, *k1;
int i;
#ifdef _UFC_32_
@@ -593,8 +587,7 @@ static void ufc_mk_keytab(key)
* Undo an extra E selection and do final permutations
*/
-ufc_long *_ufc_dofinalperm(l1, l2, r1, r2)
- ufc_long l1,l2,r1,r2;
+ufc_long *_ufc_dofinalperm(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2)
{ ufc_long v1, v2, x;
static ufc_long ary[2];
@@ -632,9 +625,7 @@ ufc_long *_ufc_dofinalperm(l1, l2, r1, r2)
* prefixing with the salt
*/
-static char *output_conversion(v1, v2, salt)
- ufc_long v1, v2;
- char *salt;
+static char *output_conversion(ufc_long v1, ufc_long v2, const char *salt)
{ static char outbuf[14];
int i, s;
@@ -656,13 +647,13 @@ static char *output_conversion(v1, v2, salt)
return outbuf;
}
-ufc_long *_ufc_doit();
-
/*
* UNIX crypt function
*/
+
+static ufc_long *_ufc_doit(ufc_long , ufc_long, ufc_long, ufc_long, ufc_long);
-char *ufc_crypt(char *key,char *salt)
+char *ufc_crypt(const char *key,const char *salt)
{ ufc_long *s;
char ktab[9];
@@ -702,8 +693,7 @@ extern long32 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[];
#define SBA(sb, v) (*(long32*)((char*)(sb)+(v)))
-ufc_long *_ufc_doit(l1, l2, r1, r2, itr)
- ufc_long l1, l2, r1, r2, itr;
+static ufc_long *_ufc_doit(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2, ufc_long itr)
{ int i;
long32 s, *k;
@@ -742,8 +732,7 @@ extern long64 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[];
#define SBA(sb, v) (*(long64*)((char*)(sb)+(v)))
-ufc_long *_ufc_doit(l1, l2, r1, r2, itr)
- ufc_long l1, l2, r1, r2, itr;
+static ufc_long *_ufc_doit(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2, ufc_long itr)
{ int i;
long64 l, r, s, *k;
@@ -777,6 +766,6 @@ ufc_long *_ufc_doit(l1, l2, r1, r2, itr)
#else
-int ufc_dummy_procedure(void)
-{return 0;}
+ int ufc_dummy_procedure(void);
+ int ufc_dummy_procedure(void) {return 0;}
#endif
diff --git a/source3/lib/username.c b/source3/lib/username.c
index 3d214fbbda..1504fd6a06 100644
--- a/source3/lib/username.c
+++ b/source3/lib/username.c
@@ -1,8 +1,8 @@
/*
- Unix SMB/Netbios implementation.
- Version 1.9.
+ Unix SMB/CIFS implementation.
Username handling
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1997-2001.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,227 +20,667 @@
*/
#include "includes.h"
-#include "loadparm.h"
-extern int DEBUGLEVEL;
+/* internal functions */
+static struct passwd *uname_string_combinations(char *s, struct passwd * (*fn) (const char *), int N);
+static struct passwd *uname_string_combinations2(char *s, int offset, struct passwd * (*fn) (const char *), int N);
+
+/*****************************************************************
+ Check if a user or group name is local (this is a *local* name for
+ *local* people, there's nothing for you here...).
+*****************************************************************/
+
+BOOL name_is_local(const char *name)
+{
+ return !(strchr_m(name, *lp_winbind_separator()));
+}
+
+/*****************************************************************
+ Splits passed user or group name to domain and user/group name parts
+ Returns True if name was splitted and False otherwise.
+*****************************************************************/
+
+BOOL split_domain_and_name(const char *name, char *domain, char* username)
+{
+ char *p = strchr(name,*lp_winbind_separator());
+
+
+ /* Parse a string of the form DOMAIN/user into a domain and a user */
+ DEBUG(10,("split_domain_and_name: checking whether name |%s| local or not\n", name));
+
+ if (p) {
+ fstrcpy(username, p+1);
+ fstrcpy(domain, name);
+ domain[PTR_DIFF(p, name)] = 0;
+ } else if (lp_winbind_use_default_domain()) {
+ fstrcpy(username, name);
+ fstrcpy(domain, lp_workgroup());
+ } else
+ return False;
+
+ DEBUG(10,("split_domain_and_name: all is fine, domain is |%s| and name is |%s|\n", domain, username));
+ return True;
+}
/****************************************************************************
-get a users home directory. tries as-is then lower case
+ Get a users home directory.
****************************************************************************/
-char *get_home_dir(char *user)
+
+char *get_user_home_dir(const char *user)
{
- static struct passwd *pass;
+ static struct passwd *pass;
- pass = Get_Pwnam(user,False);
+ /* Ensure the user exists. */
- if (!pass) return(NULL);
- return(pass->pw_dir);
+ pass = Get_Pwnam(user);
+
+ if (!pass)
+ return(NULL);
+ /* Return home directory from struct passwd. */
+
+ return(pass->pw_dir);
}
+/****************************************************************************
+ Get a users service home directory.
+****************************************************************************/
+
+char *get_user_service_home_dir(const char *user)
+{
+ static struct passwd *pass;
+ int snum;
+
+ /* Ensure the user exists. */
+
+ pass = Get_Pwnam(user);
+
+ if (!pass)
+ return(NULL);
+
+ /* If a path is specified in [homes] then use it instead of the
+ user's home directory from struct passwd. */
+
+ if ((snum = lp_servicenumber(HOMES_NAME)) != -1) {
+ static pstring home_dir;
+
+ pstrcpy(home_dir, lp_pathname(snum));
+ standard_sub_home(snum, user, home_dir);
+
+ if (home_dir[0])
+ return home_dir;
+ }
+
+ /* Return home directory from struct passwd. */
+
+ return(pass->pw_dir);
+}
/*******************************************************************
-map a username from a dos name to a unix name by looking in the username
-map
+ Map a username from a dos name to a unix name by looking in the username
+ map. Note that this modifies the name in place.
+ This is the main function that should be called *once* on
+ any incoming or new username - in order to canonicalize the name.
+ This is being done to de-couple the case conversions from the user mapping
+ function. Previously, the map_username was being called
+ every time Get_Pwnam was called.
+ Returns True if username was changed, false otherwise.
********************************************************************/
-void map_username(char *user)
-{
- static int depth=0;
- static BOOL initialised=False;
- static fstring last_from,last_to;
- FILE *f;
- char *s;
- char *mapfile = lp_username_map();
- if (!*mapfile || depth) return;
-
- if (!*user) return;
-
- if (!initialised) {
- *last_from = *last_to = 0;
- initialised = True;
- }
-
- if (strequal(user,last_to)) return;
-
- if (strequal(user,last_from)) {
- DEBUG(3,("Mapped user %s to %s\n",user,last_to));
- strcpy(user,last_to);
- return;
- }
+
+BOOL map_username(char *user)
+{
+ static BOOL initialised=False;
+ static fstring last_from,last_to;
+ XFILE *f;
+ char *mapfile = lp_username_map();
+ char *s;
+ pstring buf;
+ BOOL mapped_user = False;
+
+ if (!*user)
+ return False;
+
+ if (!*mapfile)
+ return False;
+
+ if (!initialised) {
+ *last_from = *last_to = 0;
+ initialised = True;
+ }
+
+ if (strequal(user,last_to))
+ return False;
+
+ if (strequal(user,last_from)) {
+ DEBUG(3,("Mapped user %s to %s\n",user,last_to));
+ fstrcpy(user,last_to);
+ return True;
+ }
- f = fopen(mapfile,"r");
- if (!f) {
- DEBUG(0,("can't open username map %s\n",mapfile));
- return;
- }
+ f = x_fopen(mapfile,O_RDONLY, 0);
+ if (!f) {
+ DEBUG(0,("can't open username map %s. Error %s\n",mapfile, strerror(errno) ));
+ return False;
+ }
+
+ DEBUG(4,("Scanning username map %s\n",mapfile));
- DEBUG(4,("Scanning username map %s\n",mapfile));
+ while((s=fgets_slash(buf,sizeof(buf),f))!=NULL) {
+ char *unixname = s;
+ char *dosname = strchr_m(unixname,'=');
+ char **dosuserlist;
+ BOOL return_if_mapped = False;
- depth++;
+ if (!dosname)
+ continue;
- for (; (s=fgets_slash(NULL,80,f)); free(s)) {
- char *unixname = s;
- char *dosname = strchr(unixname,'=');
+ *dosname++ = 0;
+
+ while (isspace((int)*unixname))
+ unixname++;
+
+ if ('!' == *unixname) {
+ return_if_mapped = True;
+ unixname++;
+ while (*unixname && isspace((int)*unixname))
+ unixname++;
+ }
+
+ if (!*unixname || strchr_m("#;",*unixname))
+ continue;
- if (!dosname) continue;
- *dosname++ = 0;
+ {
+ int l = strlen(unixname);
+ while (l && isspace((int)unixname[l-1])) {
+ unixname[l-1] = 0;
+ l--;
+ }
+ }
- while (isspace(*unixname)) unixname++;
- if (!*unixname || strchr("#;",*unixname)) continue;
+ dosuserlist = lp_list_make(dosname);
+ if (!dosuserlist) {
+ DEBUG(0,("Unable to build user list\n"));
+ return False;
+ }
- {
- int l = strlen(unixname);
- while (l && isspace(unixname[l-1])) {
- unixname[l-1] = 0;
- l--;
- }
- }
+ if (strchr_m(dosname,'*') || user_in_list(user, dosuserlist)) {
+ DEBUG(3,("Mapped user %s to %s\n",user,unixname));
+ mapped_user = True;
+ fstrcpy(last_from,user);
+ sscanf(unixname,"%s",user);
+ fstrcpy(last_to,user);
+ if(return_if_mapped) {
+ lp_list_free (&dosuserlist);
+ x_fclose(f);
+ return True;
+ }
+ }
+
+ lp_list_free (&dosuserlist);
+ }
- if (strchr(dosname,'*') || user_in_list(user,dosname)) {
- DEBUG(3,("Mapped user %s to %s\n",user,unixname));
- StrnCpy(last_from,user,sizeof(last_from)-1);
- sscanf(unixname,"%s",user);
- StrnCpy(last_to,user,sizeof(last_to)-1);
- }
- }
+ x_fclose(f);
- fclose(f);
+ /*
+ * Setup the last_from and last_to as an optimization so
+ * that we don't scan the file again for the same user.
+ */
+ fstrcpy(last_from,user);
+ fstrcpy(last_to,user);
- depth--;
+ return mapped_user;
}
/****************************************************************************
-internals of Get_Pwnam wrapper
+ * A wrapper for sys_getpwnam(). The following variations are tried:
+ * - as transmitted
+ * - in all lower case if this differs from transmitted
+ * - in all upper case if this differs from transmitted
+ * - using lp_usernamelevel() for permutations.
****************************************************************************/
-static struct passwd *_Get_Pwnam(char *s)
-{
- struct passwd *ret;
-
- ret = getpwnam(s);
- if (ret)
- {
-#ifdef GETPWANAM
- struct passwd_adjunct *pwret;
- pwret = getpwanam(s);
- if (pwret)
- {
- free(ret->pw_passwd);
- ret->pw_passwd = pwret->pwa_passwd;
+
+static struct passwd *Get_Pwnam_internals(const char *user, char *user2)
+{
+ struct passwd *ret = NULL;
+
+ if (!user2 || !(*user2))
+ return(NULL);
+
+ if (!user || !(*user))
+ return(NULL);
+
+ /* Try in all lower case first as this is the most
+ common case on UNIX systems */
+ strlower(user2);
+ DEBUG(5,("Trying _Get_Pwnam(), username as lowercase is %s\n",user2));
+ ret = sys_getpwnam(user2);
+ if(ret)
+ goto done;
+
+ /* Try as given, if username wasn't originally lowercase */
+ if(strcmp(user, user2) != 0) {
+ DEBUG(5,("Trying _Get_Pwnam(), username as given is %s\n", user));
+ ret = sys_getpwnam(user);
+ if(ret)
+ goto done;
}
-#endif
- }
+ /* Try as uppercase, if username wasn't originally uppercase */
+ strupper(user2);
+ if(strcmp(user, user2) != 0) {
+ DEBUG(5,("Trying _Get_Pwnam(), username as uppercase is %s\n", user2));
+ ret = sys_getpwnam(user2);
+ if(ret)
+ goto done;
+ }
- return(ret);
-}
+ /* Try all combinations up to usernamelevel */
+ strlower(user2);
+ DEBUG(5,("Checking combinations of %d uppercase letters in %s\n", lp_usernamelevel(), user2));
+ ret = uname_string_combinations(user2, sys_getpwnam, lp_usernamelevel());
+done:
+ DEBUG(5,("Get_Pwnam_internals %s find user [%s]!\n",ret ? "did":"didn't", user));
+ return ret;
+}
/****************************************************************************
-a wrapper for getpwnam() that tries with all lower and all upper case
-if the initial name fails. Also tried with first letter capitalised
-Note that this changes user!
+ Get_Pwnam wrapper for modification.
+ NOTE: This can potentially modify 'user'!
****************************************************************************/
-struct passwd *Get_Pwnam(char *user,BOOL allow_change)
+
+struct passwd *Get_Pwnam_Modify(char *user)
{
- fstring user2;
+ fstring user2;
+ struct passwd *ret;
- struct passwd *ret;
+ fstrcpy(user2, user);
- if (!user || !(*user))
- return(NULL);
+ ret = Get_Pwnam_internals(user, user2);
+
+ /* If caller wants the modified username, ensure they get it */
+ fstrcpy(user,user2);
- StrnCpy(user2,user,sizeof(user2)-1);
+ /* We can safely assume ret is NULL if none of the above succeed */
+ return(ret);
+}
- if (!allow_change) {
- user = &user2[0];
- }
+/****************************************************************************
+ Get_Pwnam wrapper without modification.
+ NOTE: This with NOT modify 'user'!
+****************************************************************************/
+
+struct passwd *Get_Pwnam(const char *user)
+{
+ fstring user2;
+ struct passwd *ret;
+
+ fstrcpy(user2, user);
- map_username(user);
+ DEBUG(5,("Finding user %s\n", user));
- ret = _Get_Pwnam(user);
- if (ret) return(ret);
+ ret = Get_Pwnam_internals(user, user2);
+
+ DEBUG(5,("Get_Pwnam %s find user [%s]!\n",ret ? "did":"didn't", user));
- strlower(user);
- ret = _Get_Pwnam(user);
- if (ret) return(ret);
+ return ret;
+}
- strupper(user);
- ret = _Get_Pwnam(user);
- if (ret) return(ret);
+/****************************************************************************
+ Check if a user is in a netgroup user list.
+****************************************************************************/
- /* try with first letter capitalised */
- if (strlen(user) > 1)
- strlower(user+1);
- ret = _Get_Pwnam(user);
- if (ret) return(ret);
+static BOOL user_in_netgroup_list(const char *user, const char *ngname)
+{
+#ifdef HAVE_NETGROUP
+ static char *mydomain = NULL;
+ if (mydomain == NULL)
+ yp_get_default_domain(&mydomain);
+
+ if(mydomain == NULL) {
+ DEBUG(5,("Unable to get default yp domain\n"));
+ return False;
+ }
- if (allow_change)
- strcpy(user,user2);
+ DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
+ user, mydomain, ngname));
+ DEBUG(5,("innetgr is %s\n", innetgr(ngname, NULL, user, mydomain)
+ ? "TRUE" : "FALSE"));
- return(NULL);
+ if (innetgr(ngname, NULL, user, mydomain))
+ return (True);
+#endif /* HAVE_NETGROUP */
+ return False;
}
-
/****************************************************************************
-check if a user is in a user list
+ Check if a user is in a winbind group.
+****************************************************************************/
+
+static BOOL user_in_winbind_group_list(const char *user, const char *gname, BOOL *winbind_answered)
+{
+ int num_groups;
+ int i;
+ gid_t *groups = NULL;
+ gid_t gid;
+ BOOL ret = False;
+
+ *winbind_answered = False;
+
+ /*
+ * Get the gid's that this user belongs to.
+ */
+
+ if ((num_groups = winbind_getgroups(user, 0, NULL)) == -1)
+ return False;
+
+ if (num_groups == 0) {
+ *winbind_answered = True;
+ return False;
+ }
+
+ if ((groups = (gid_t *)malloc(sizeof(gid_t) * num_groups )) == NULL) {
+ DEBUG(0,("user_in_winbind_group_list: malloc fail.\n"));
+ goto err;
+ }
+
+ if ((num_groups = winbind_getgroups(user, num_groups, groups)) == -1) {
+ DEBUG(0,("user_in_winbind_group_list: second winbind_getgroups call \
+failed with error %s\n", strerror(errno) ));
+ goto err;
+ }
+
+ /*
+ * Now we have the gid list for this user - convert the gname
+ * to a gid_t via either winbind or the local UNIX lookup and do the comparison.
+ */
+
+ if ((gid = nametogid(gname)) == (gid_t)-1) {
+ DEBUG(0,("user_in_winbind_group_list: winbind_lookup_name for group %s failed.\n",
+ gname ));
+ goto err;
+ }
+
+ for (i = 0; i < num_groups; i++) {
+ if (gid == groups[i]) {
+ ret = True;
+ break;
+ }
+ }
+
+ *winbind_answered = True;
+ SAFE_FREE(groups);
+ return ret;
+
+ err:
+
+ *winbind_answered = False;
+ SAFE_FREE(groups);
+ return False;
+}
+
+/****************************************************************************
+ Check if a user is in a UNIX group.
****************************************************************************/
-BOOL user_in_list(char *user,char *list)
-{
- pstring tok;
- char *p=list;
-
- while (next_token(&p,tok,LIST_SEP))
- {
- if (strequal(user,tok))
- return(True);
-
-#ifdef NETGROUP
- if (*tok == '@')
- {
- static char *mydomain = NULL;
- if (mydomain == 0)
- yp_get_default_domain(&mydomain);
-
- DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
- user, mydomain, &tok[1]));
- DEBUG(5,("innetgr is %s\n",
- innetgr(&tok[1], (char *) 0, user, mydomain)
- ? "TRUE" : "FALSE"));
-
- if (innetgr(&tok[1], (char *)0, user, mydomain))
- return (True);
+
+static BOOL user_in_unix_group_list(const char *user,const char *gname)
+{
+ struct passwd *pass = Get_Pwnam(user);
+ struct sys_userlist *user_list;
+ struct sys_userlist *member;
+
+ DEBUG(10,("user_in_unix_group_list: checking user %s in group %s\n", user, gname));
+
+ /*
+ * We need to check the users primary group as this
+ * group is implicit and often not listed in the group database.
+ */
+
+ if (pass) {
+ if (strequal(gname,gidtoname(pass->pw_gid))) {
+ DEBUG(10,("user_in_unix_group_list: group %s is primary group.\n", gname ));
+ return True;
+ }
+ }
+
+ user_list = get_users_in_group(gname);
+ if (user_list == NULL) {
+ DEBUG(10,("user_in_unix_group_list: no such group %s\n", gname ));
+ return False;
+ }
+
+ for (member = user_list; member; member = member->next) {
+ DEBUG(10,("user_in_unix_group_list: checking user %s against member %s\n",
+ user, member->unix_name ));
+ if (strequal(member->unix_name,user)) {
+ free_userlist(user_list);
+ return(True);
+ }
}
-#endif
+ free_userlist(user_list);
+ return False;
+}
-#if HAVE_GETGRNAM
- if (*tok == '@')
- {
- struct group *gptr;
- char **member;
- struct passwd *pass = Get_Pwnam(user,False);
+/****************************************************************************
+ Check if a user is in a group list. Ask winbind first, then use UNIX.
+****************************************************************************/
+
+BOOL user_in_group_list(const char *user, const char *gname)
+{
+ BOOL winbind_answered = False;
+ BOOL ret;
- if (pass) {
- gptr = getgrgid(pass->pw_gid);
- if (gptr && strequal(gptr->gr_name,&tok[1]))
- return(True);
- }
+ ret = user_in_winbind_group_list(user, gname, &winbind_answered);
+ if (!winbind_answered)
+ ret = user_in_unix_group_list(user, gname);
- gptr = (struct group *)getgrnam(&tok[1]);
+ if (ret)
+ DEBUG(10,("user_in_group_list: user |%s| is in group |%s|\n", user, gname));
+ return ret;
+}
- if (gptr)
- {
- member = gptr->gr_mem;
- while (member && *member)
- {
- if (strequal(*member,user))
- return(True);
- member++;
+/****************************************************************************
+ Check if a user is in a user list - can check combinations of UNIX
+ and netgroup lists.
+****************************************************************************/
+
+BOOL user_in_list(const char *user,char **list)
+{
+ if (!list || !*list)
+ return False;
+
+ DEBUG(10,("user_in_list: checking user %s in list\n", user));
+
+ while (*list) {
+
+ DEBUG(10,("user_in_list: checking user |%s| in group |%s|\n", user, *list));
+
+ /*
+ * Check raw username.
+ */
+ if (strequal(user, *list))
+ return(True);
+
+ /*
+ * Now check to see if any combination
+ * of UNIX and netgroups has been specified.
+ */
+
+ if(**list == '@') {
+ /*
+ * Old behaviour. Check netgroup list
+ * followed by UNIX list.
+ */
+ if(user_in_netgroup_list(user, *list +1))
+ return True;
+ if(user_in_group_list(user, *list +1))
+ return True;
+ } else if (**list == '+') {
+
+ if((*(*list +1)) == '&') {
+ /*
+ * Search UNIX list followed by netgroup.
+ */
+ if(user_in_group_list(user, *list +2))
+ return True;
+ if(user_in_netgroup_list(user, *list +2))
+ return True;
+
+ } else {
+
+ /*
+ * Just search UNIX list.
+ */
+
+ if(user_in_group_list(user, *list +1))
+ return True;
+ }
+
+ } else if (**list == '&') {
+
+ if(*(*list +1) == '+') {
+ /*
+ * Search netgroup list followed by UNIX list.
+ */
+ if(user_in_netgroup_list(user, *list +2))
+ return True;
+ if(user_in_group_list(user, *list +2))
+ return True;
+ } else {
+ /*
+ * Just search netgroup list.
+ */
+ if(user_in_netgroup_list(user, *list +1))
+ return True;
+ }
+ } else if (!name_is_local(*list)) {
+ /*
+ * If user name did not match and token is not
+ * a unix group and the token has a winbind separator in the
+ * name then see if it is a Windows group.
+ */
+
+ DOM_SID g_sid;
+ enum SID_NAME_USE name_type;
+ BOOL winbind_answered = False;
+ BOOL ret;
+ fstring groupname, domain;
+
+ /* Parse a string of the form DOMAIN/user into a domain and a user */
+
+ char *p = strchr(*list,*lp_winbind_separator());
+
+ DEBUG(10,("user_in_list: checking if user |%s| is in winbind group |%s|\n", user, *list));
+
+ if (p) {
+ fstrcpy(groupname, p+1);
+ fstrcpy(domain, *list);
+ domain[PTR_DIFF(p, *list)] = 0;
+
+ /* Check to see if name is a Windows group */
+ if (winbind_lookup_name(domain, groupname, &g_sid, &name_type) && name_type == SID_NAME_DOM_GRP) {
+
+ /* Check if user name is in the Windows group */
+ ret = user_in_winbind_group_list(user, *list, &winbind_answered);
+
+ if (winbind_answered && ret == True) {
+ DEBUG(10,("user_in_list: user |%s| is in winbind group |%s|\n", user, *list));
+ return ret;
+ }
+ }
+ }
}
- }
- }
-#endif
- }
- return(False);
+
+ list++;
+ }
+ return(False);
}
+/* The functions below have been taken from password.c and slightly modified */
+/****************************************************************************
+ Apply a function to upper/lower case combinations
+ of a string and return true if one of them returns true.
+ Try all combinations with N uppercase letters.
+ offset is the first char to try and change (start with 0)
+ it assumes the string starts lowercased
+****************************************************************************/
+
+static struct passwd *uname_string_combinations2(char *s,int offset,struct passwd *(*fn)(const char *),int N)
+{
+ ssize_t len = (ssize_t)strlen(s);
+ int i;
+ struct passwd *ret;
+
+ if (N <= 0 || offset >= len)
+ return(fn(s));
+
+ for (i=offset;i<(len-(N-1));i++) {
+ char c = s[i];
+ if (!islower((int)c))
+ continue;
+ s[i] = toupper(c);
+ ret = uname_string_combinations2(s,i+1,fn,N-1);
+ if(ret)
+ return(ret);
+ s[i] = c;
+ }
+ return(NULL);
+}
+/****************************************************************************
+ Apply a function to upper/lower case combinations
+ of a string and return true if one of them returns true.
+ Try all combinations with up to N uppercase letters.
+ offset is the first char to try and change (start with 0)
+ it assumes the string starts lowercased
+****************************************************************************/
+
+static struct passwd * uname_string_combinations(char *s,struct passwd * (*fn)(const char *),int N)
+{
+ int n;
+ struct passwd *ret;
+
+ for (n=1;n<=N;n++) {
+ ret = uname_string_combinations2(s,0,fn,n);
+ if(ret)
+ return(ret);
+ }
+ return(NULL);
+}
+
+/****************************************************************************
+ These wrappers allow appliance mode to work. In appliance mode the username
+ takes the form DOMAIN/user.
+****************************************************************************/
+
+struct passwd *smb_getpwnam(char *user, BOOL allow_change)
+{
+ struct passwd *pw;
+ char *p;
+ char *sep;
+ extern pstring global_myname;
+
+ if (allow_change)
+ pw = Get_Pwnam_Modify(user);
+ else
+ pw = Get_Pwnam(user);
+
+ if (pw)
+ return pw;
+
+ /*
+ * If it is a domain qualified name and it isn't in our password
+ * database but the domain portion matches our local machine name then
+ * lookup just the username portion locally.
+ */
+
+ sep = lp_winbind_separator();
+ p = strchr_m(user,*sep);
+ if (p && strncasecmp(global_myname, user, strlen(global_myname))==0) {
+ if (allow_change)
+ pw = Get_Pwnam_Modify(p+1);
+ else
+ pw = Get_Pwnam(p+1);
+ }
+ return NULL;
+}
diff --git a/source3/lib/util.c b/source3/lib/util.c
index 7bd6298c4c..7e2ad49639 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -1,8 +1,9 @@
/*
- Unix SMB/Netbios implementation.
- Version 1.9.
+ Unix SMB/CIFS implementation.
Samba utility functions
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2001
+ Copyright (C) Simo Sorce 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,41 +21,51 @@
*/
#include "includes.h"
-#include "loadparm.h"
-pstring scope = "";
+#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
+#ifdef WITH_NISPLUS_HOME
+#ifdef BROKEN_NISPLUS_INCLUDE_FILES
+/*
+ * The following lines are needed due to buggy include files
+ * in Solaris 2.6 which define GROUP in both /usr/include/sys/acl.h and
+ * also in /usr/include/rpcsvc/nis.h. The definitions conflict. JRA.
+ * Also GROUP_OBJ is defined as 0x4 in /usr/include/sys/acl.h and as
+ * an enum in /usr/include/rpcsvc/nis.h.
+ */
-int DEBUGLEVEL = 1;
+#if defined(GROUP)
+#undef GROUP
+#endif
-BOOL passive = False;
+#if defined(GROUP_OBJ)
+#undef GROUP_OBJ
+#endif
-int Protocol = PROTOCOL_COREPLUS;
+#endif /* BROKEN_NISPLUS_INCLUDE_FILES */
-int serverzone=0;
+#include <rpcsvc/nis.h>
-/* a default finfo structure to ensure all fields are sensible */
-file_info def_finfo = {-1,0,0,0,0,0,0,""};
+#else /* !WITH_NISPLUS_HOME */
-/* these are some file handles where debug info will be stored */
-FILE *dbf = NULL;
+#include "rpcsvc/ypclnt.h"
-/* the client file descriptor */
-int Client = -1;
+#endif /* WITH_NISPLUS_HOME */
+#endif /* HAVE_NETGROUP && WITH_AUTOMOUNT */
-/* info on the client */
-struct from_host Client_info=
-{"UNKNOWN","0.0.0.0",NULL};
+#ifdef WITH_SSL
+#include <openssl/ssl.h>
+#undef Realloc /* SSLeay defines this and samba has a function of this name */
+extern SSL *ssl;
+extern int sslFd;
+#endif /* WITH_SSL */
-/* the last IP received from */
-struct in_addr lastip;
+int Protocol = PROTOCOL_COREPLUS;
-/* the last port received from */
-int lastport=0;
+/* a default finfo structure to ensure all fields are sensible */
+file_info def_finfo = {-1,0,0,0,0,0,0,"",""};
-/* my IP, the broadcast IP and the Netmask */
-struct in_addr myip;
-struct in_addr bcast_ip;
-struct in_addr Netmask;
+/* this is used by the chaining code */
+int chain_size = 0;
int trans_num = 0;
@@ -63,13 +74,6 @@ int trans_num = 0;
*/
int case_default = CASE_LOWER;
-
-/* size of reads during a direct file to file transfer */
-int ReadSize = 16*1024;
-
-pstring debugf = "/tmp/log.samba";
-int syslog_level;
-
/* the following control case operations - they are put here so the
client can link easily */
BOOL case_sensitive;
@@ -78,916 +82,110 @@ BOOL use_mangled_map = False;
BOOL short_case_preserve;
BOOL case_mangle;
-fstring remote_machine="";
-fstring local_machine="";
-fstring remote_arch="UNKNOWN";
-fstring remote_proto="UNKNOWN";
-pstring myhostname="";
-pstring user_socket_options="";
-pstring sesssetup_user="";
-
-
-static char *filename_dos(char *path,char *buf);
-
-static BOOL stdout_logging = False;
-
-
-/*******************************************************************
- get ready for syslog stuff
- ******************************************************************/
-void setup_logging(char *pname,BOOL interactive)
-{
-#ifdef SYSLOG
- if (!interactive) {
- char *p = strrchr(pname,'/');
- if (p) pname = p+1;
- openlog(pname, LOG_PID, LOG_DAEMON);
- }
-#endif
- if (interactive) {
- stdout_logging = True;
- dbf = stdout;
- }
-}
-
-
-BOOL append_log=False;
-
-
-/****************************************************************************
-reopen the log files
-****************************************************************************/
-void reopen_logs(void)
-{
- extern FILE *dbf;
- pstring fname;
-
- if (DEBUGLEVEL > 0)
- {
- strcpy(fname,debugf);
- if (lp_loaded() && (*lp_logfile()))
- strcpy(fname,lp_logfile());
-
- if (!strcsequal(fname,debugf) || !dbf || !file_exist(debugf,NULL))
- {
- strcpy(debugf,fname);
- if (dbf) fclose(dbf);
- if (append_log)
- dbf = fopen(debugf,"a");
- else
- dbf = fopen(debugf,"w");
- if (dbf) setbuf(dbf,NULL);
- }
- }
- else
- {
- if (dbf)
- {
- fclose(dbf);
- dbf = NULL;
- }
- }
-}
-
-
-/*******************************************************************
-write an debug message on the debugfile. This is called by the DEBUG
-macro
-********************************************************************/
-#ifdef __STDC__
-int Debug1(char *format_str, ...)
-{
-#else
-int Debug1(va_alist)
-va_dcl
-{
- char *format_str;
-#endif
- va_list ap;
-
-#ifdef __STDC__
- va_start(ap, format_str);
-#else
- va_start(ap);
- format_str = va_arg(ap,char *);
-#endif
-
- if (stdout_logging) {
- vfprintf(dbf,format_str,ap);
- va_end(ap);
- return(0);
- }
+static enum remote_arch_types ra_type = RA_UNKNOWN;
+pstring user_socket_options=DEFAULT_SOCKET_OPTIONS;
- {
- static int debug_count=0;
+pstring global_myname = "";
+fstring global_myworkgroup = "";
+char **my_netbios_names;
- debug_count++;
- if (debug_count == 100) {
- int maxlog = lp_max_log_size() * 1024;
- if (dbf && maxlog > 0)
- {
- struct stat st;
-
- if (fstat(fileno(dbf),&st) == 0 && st.st_size > maxlog) {
- fclose(dbf); dbf = NULL;
- reopen_logs();
- if (dbf && file_size(debugf) > maxlog) {
- pstring name;
- fclose(dbf); dbf = NULL;
- sprintf(name,"%s.old",debugf);
- sys_rename(debugf,name);
- reopen_logs();
- }
- }
- }
- debug_count=0;
- }
- }
-
-#ifdef SYSLOG
- if (!lp_syslog_only())
-#endif
- {
- if (!dbf)
- {
- dbf = fopen(debugf,"w");
- if (dbf)
- setbuf(dbf,NULL);
- else
- return(0);
- }
- }
-
-#ifdef SYSLOG
- if (syslog_level < lp_syslog())
- {
- /*
- * map debug levels to syslog() priorities
- * note that not all DEBUG(0, ...) calls are
- * necessarily errors
- */
- static int priority_map[] = {
- LOG_ERR, /* 0 */
- LOG_WARNING, /* 1 */
- LOG_NOTICE, /* 2 */
- LOG_INFO, /* 3 */
- };
- int priority;
- pstring msgbuf;
-
- if (syslog_level >= sizeof(priority_map) / sizeof(priority_map[0]) ||
- syslog_level < 0)
- priority = LOG_DEBUG;
- else
- priority = priority_map[syslog_level];
-
- vsprintf(msgbuf, format_str, ap);
-
- msgbuf[255] = '\0';
- syslog(priority, "%s", msgbuf);
- }
-#endif
-
-#ifdef SYSLOG
- if (!lp_syslog_only())
-#endif
- {
- vfprintf(dbf,format_str,ap);
- fflush(dbf);
- }
-
- va_end(ap);
- return(0);
-}
/****************************************************************************
-routine to do file locking
-****************************************************************************/
-BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type)
+ find a suitable temporary directory. The result should be copied immediately
+ as it may be overwritten by a subsequent call.
+ ****************************************************************************/
+char *tmpdir(void)
{
-#if HAVE_FCNTL_LOCK
- struct flock lock;
- int ret;
-
-#if 1
- uint32 mask = 0xC0000000;
-
- /* make sure the count is reasonable, we might kill the lockd otherwise */
- count &= ~mask;
-
- /* the offset is often strange - remove 2 of its bits if either of
- the top two bits are set. Shift the top ones by two bits. This
- still allows OLE2 apps to operate, but should stop lockd from
- dieing */
- if ((offset & mask) != 0)
- offset = (offset & ~mask) | ((offset & mask) >> 2);
-#else
- unsigned long mask = ((unsigned)1<<31);
-
- /* interpret negative counts as large numbers */
- if (count < 0)
- count &= ~mask;
-
- /* no negative offsets */
- offset &= ~mask;
-
- /* count + offset must be in range */
- while ((offset < 0 || (offset + count < 0)) && mask)
- {
- offset &= ~mask;
- mask = mask >> 1;
- }
-#endif
-
-
- DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type));
-
- lock.l_type = type;
- lock.l_whence = SEEK_SET;
- lock.l_start = (int)offset;
- lock.l_len = (int)count;
- lock.l_pid = 0;
-
- errno = 0;
-
- ret = fcntl(fd,op,&lock);
-
- if (errno != 0)
- DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
-
- /* a lock query */
- if (op == F_GETLK)
- {
- if ((ret != -1) &&
- (lock.l_type != F_UNLCK) &&
- (lock.l_pid != 0) &&
- (lock.l_pid != getpid()))
- {
- DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid));
- return(True);
- }
-
- /* it must be not locked or locked by me */
- return(False);
- }
-
- /* a lock set or unset */
- if (ret == -1)
- {
- DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n",
- offset,count,op,type,strerror(errno)));
-
- /* perhaps it doesn't support this sort of locking?? */
- if (errno == EINVAL)
- {
- DEBUG(3,("locking not supported? returning True\n"));
- return(True);
- }
-
- return(False);
- }
-
- /* everything went OK */
- DEBUG(5,("Lock call successful\n"));
-
- return(True);
-#else
- return(False);
-#endif
-}
-
-/*******************************************************************
-lock a file - returning a open file descriptor or -1 on failure
-The timeout is in seconds. 0 means no timeout
-********************************************************************/
-int file_lock(char *name,int timeout)
-{
- int fd = open(name,O_RDWR|O_CREAT,0666);
- time_t t=0;
- if (fd < 0) return(-1);
-
-#if HAVE_FCNTL_LOCK
- if (timeout) t = time(NULL);
- while (!timeout || (time(NULL)-t < timeout)) {
- if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)) return(fd);
- msleep(LOCK_RETRY_TIMEOUT);
- }
- return(-1);
-#else
- return(fd);
-#endif
-}
-
-/*******************************************************************
-unlock a file locked by file_lock
-********************************************************************/
-void file_unlock(int fd)
-{
- if (fd<0) return;
-#if HAVE_FCNTL_LOCK
- fcntl_lock(fd,F_SETLK,0,1,F_UNLCK);
-#endif
- close(fd);
-}
-
-/*******************************************************************
-a gettimeofday wrapper
-********************************************************************/
-void GetTimeOfDay(struct timeval *tval)
-{
-#ifdef GETTIMEOFDAY1
- gettimeofday(tval);
-#else
- gettimeofday(tval,NULL);
-#endif
-}
-
-int extra_time_offset = 0;
-
-static int timediff = 0;
-
-/*******************************************************************
-init the time differences
-********************************************************************/
-void TimeInit(void)
-{
- struct tm tm_utc,tm_local;
- time_t t;
-
- t = time(NULL);
-
- tm_utc = *(gmtime(&t));
- tm_local = *(localtime(&t));
-
-#ifdef HAVE_GMTOFF
- timediff = -tm_local.tm_gmtoff;
-#else
- timediff = mktime(&tm_utc) - mktime(&tm_local);
-#endif
-
- if (serverzone == 0) {
- serverzone = timediff - DSTDiff(t);
- DEBUG(4,("Serverzone is %d\n",serverzone));
- }
-}
-
-
-/*******************************************************************
-return the DST offset for a particular time
-We keep a table of DST offsets to prevent calling localtime() on each
-call of this function. This saves a LOT of time on many unixes.
-********************************************************************/
-int DSTDiff(time_t t)
-{
- static struct dst_table {time_t start,end; BOOL is_dst;} *dst_table = NULL;
- static int table_size = 0;
- int i;
- BOOL is_dst = False;
-
- if (t == 0) t = time(NULL);
-
-#ifndef NO_ISDST
- for (i=0;i<table_size;i++)
- if (t >= dst_table[i].start && t <= dst_table[i].end) break;
-
- if (i<table_size) {
- is_dst = dst_table[i].is_dst;
- } else {
- time_t low,high;
-
- dst_table = (struct dst_table *)Realloc(dst_table,
- sizeof(dst_table[0])*(i+1));
- if (!dst_table) {
- table_size = 0;
- return(0);
- }
-
- table_size++;
-
- dst_table[i].is_dst = is_dst = (localtime(&t)->tm_isdst?True:False);;
- dst_table[i].start = dst_table[i].end = t;
-
- /* no entry will cover more than 6 months */
- low = t - 3*30*24*60*60;
- high = t + 3*30*24*60*60;
-
- /* widen the new entry using two bisection searches */
- while (low+60*60 < dst_table[i].start) {
- t = low + (dst_table[i].start-low)/2;
- if ((localtime(&t)->tm_isdst?True:False) == is_dst)
- dst_table[i].start = t;
- else
- low = t;
- }
-
- while (high-60*60 > dst_table[i].end) {
- t = high + (high-dst_table[i].end)/2;
- if ((localtime(&t)->tm_isdst?True:False) == is_dst)
- dst_table[i].end = t;
- else
- high = t;
- }
-
-/*
- DEBUG(1,("Added DST entry from %s ",
- asctime(localtime(&dst_table[i].start))));
- DEBUG(1,("to %s (%d)\n",asctime(localtime(&dst_table[i].end)),
- dst_table[i].is_dst));
-*/
- }
-#endif
-
- return((is_dst?60*60:0) - (extra_time_offset*60));
-}
-
-/****************************************************************************
-return the difference between local and GMT time
-****************************************************************************/
-int TimeDiff(time_t t)
-{
- static BOOL initialised = False;
- if (!initialised) {initialised=True; TimeInit();}
- return(timediff - DSTDiff(t));
-}
-
-/****************************************************************************
-try to optimise the localtime call, it can be quite expenive on some machines
-timemul is normally LOCAL_TO_GMT, GMT_TO_LOCAL or 0
-****************************************************************************/
-struct tm *LocalTime(time_t *t,int timemul)
-{
- time_t t2 = *t;
-
- if (timemul)
- t2 += timemul * TimeDiff(t2);
-
- return(gmtime(&t2));
-}
-
-
-/****************************************************************************
-determine if a file descriptor is in fact a socket
-****************************************************************************/
-BOOL is_a_socket(int fd)
-{
- int v,l;
- l = sizeof(int);
- return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
-}
-
-
-static char *last_ptr=NULL;
-
-/****************************************************************************
- Get the next token from a string, return False if none found
- handles double-quotes.
-Based on a routine by GJC@VILLAGE.COM.
-Extensively modified by Andrew.Tridgell@anu.edu.au
-****************************************************************************/
-BOOL next_token(char **ptr,char *buff,char *sep)
-{
- char *s;
- BOOL quoted;
-
- if (!ptr) ptr = &last_ptr;
- if (!ptr) return(False);
-
- s = *ptr;
-
- /* default to simple separators */
- if (!sep) sep = " \t\n\r";
-
- /* find the first non sep char */
- while(*s && strchr(sep,*s)) s++;
-
- /* nothing left? */
- if (! *s) return(False);
-
- /* copy over the token */
- for (quoted = False; *s && (quoted || !strchr(sep,*s)); s++)
- {
- if (*s == '\"')
- quoted = !quoted;
- else
- *buff++ = *s;
- }
-
- *ptr = (*s) ? s+1 : s;
- *buff = 0;
- last_ptr = *ptr;
-
- return(True);
+ char *p;
+ if ((p = getenv("TMPDIR")))
+ return p;
+ return "/tmp";
}
/****************************************************************************
-Convert list of tokens to array; dependent on above routine.
-Uses last_ptr from above - bit of a hack.
+ Determine whether we are in the specified group.
****************************************************************************/
-char **toktocliplist(int *ctok, char *sep)
-{
- char *s=last_ptr;
- int ictok=0;
- char **ret, **iret;
-
- if (!sep) sep = " \t\n\r";
- while(*s && strchr(sep,*s)) s++;
-
- /* nothing left? */
- if (!*s) return(NULL);
-
- do {
- ictok++;
- while(*s && (!strchr(sep,*s))) s++;
- while(*s && strchr(sep,*s)) *s++=0;
- } while(*s);
-
- *ctok=ictok;
- s=last_ptr;
-
- if (!(ret=iret=malloc(ictok*sizeof(char *)))) return NULL;
-
- while(ictok--) {
- *iret++=s;
- while(*s++);
- while(!*s) s++;
- }
-
- return ret;
-}
-
-#ifndef HAVE_MEMMOVE
-/*******************************************************************
-safely copies memory, ensuring no overlap problems.
-this is only used if the machine does not have it's own memmove().
-this is not the fastest algorithm in town, but it will do for our
-needs.
-********************************************************************/
-void *MemMove(void *dest,void *src,int size)
+BOOL in_group(gid_t group, gid_t current_gid, int ngroups, gid_t *groups)
{
- unsigned long d,s;
- int i;
- if (dest==src || !size) return(dest);
+ int i;
- d = (unsigned long)dest;
- s = (unsigned long)src;
+ if (group == current_gid)
+ return(True);
- if ((d >= (s+size)) || (s >= (d+size))) {
- /* no overlap */
- memcpy(dest,src,size);
- return(dest);
- }
+ for (i=0;i<ngroups;i++)
+ if (group == groups[i])
+ return(True);
- if (d < s)
- {
- /* we can forward copy */
- if (s-d >= sizeof(int) &&
- !(s%sizeof(int)) && !(d%sizeof(int)) && !(size%sizeof(int))) {
- /* do it all as words */
- int *idest = (int *)dest;
- int *isrc = (int *)src;
- size /= sizeof(int);
- for (i=0;i<size;i++) idest[i] = isrc[i];
- } else {
- /* simplest */
- char *cdest = (char *)dest;
- char *csrc = (char *)src;
- for (i=0;i<size;i++) cdest[i] = csrc[i];
- }
- }
- else
- {
- /* must backward copy */
- if (d-s >= sizeof(int) &&
- !(s%sizeof(int)) && !(d%sizeof(int)) && !(size%sizeof(int))) {
- /* do it all as words */
- int *idest = (int *)dest;
- int *isrc = (int *)src;
- size /= sizeof(int);
- for (i=size-1;i>=0;i--) idest[i] = isrc[i];
- } else {
- /* simplest */
- char *cdest = (char *)dest;
- char *csrc = (char *)src;
- for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
- }
- }
- return(dest);
+ return(False);
}
-#endif
-
/****************************************************************************
-prompte a dptr (to make it recently used)
+ Like atoi but gets the value up to the separator character.
****************************************************************************/
-void array_promote(char *array,int elsize,int element)
-{
- char *p;
- if (element == 0)
- return;
- p = (char *)malloc(elsize);
-
- if (!p)
- {
- DEBUG(5,("Ahh! Can't malloc\n"));
- return;
- }
- memcpy(p,array + element * elsize, elsize);
- memmove(array + elsize,array,elsize*element);
- memcpy(array,p,elsize);
- free(p);
-}
-
-enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
-
-struct
+char *Atoic(char *p, int *n, char *c)
{
- char *name;
- int level;
- int option;
- int value;
- int opttype;
-} socket_options[] = {
- {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
- {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
- {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
-#ifdef TCP_NODELAY
- {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
-#endif
-#ifdef IPTOS_LOWDELAY
- {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
-#endif
-#ifdef IPTOS_THROUGHPUT
- {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
-#endif
-#ifdef SO_SNDBUF
- {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
-#endif
-#ifdef SO_RCVBUF
- {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
-#endif
-#ifdef SO_SNDLOWAT
- {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
-#endif
-#ifdef SO_RCVLOWAT
- {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
-#endif
- {NULL,0,0,0,0}};
-
-
-
-/****************************************************************************
-set user socket options
-****************************************************************************/
-void set_socket_options(int fd, char *options)
-{
- string tok;
-
- while (next_token(&options,tok," \t,"))
- {
- int ret=0,i;
- int value = 1;
- char *p;
- BOOL got_value = False;
-
- if ((p = strchr(tok,'=')))
- {
- *p = 0;
- value = atoi(p+1);
- got_value = True;
+ if (!isdigit((int)*p)) {
+ DEBUG(5, ("Atoic: malformed number\n"));
+ return NULL;
}
- for (i=0;socket_options[i].name;i++)
- if (strequal(socket_options[i].name,tok))
- break;
+ (*n) = atoi(p);
- if (!socket_options[i].name)
- {
- DEBUG(0,("Unknown socket option %s\n",tok));
- continue;
- }
+ while ((*p) && isdigit((int)*p))
+ p++;
- switch (socket_options[i].opttype)
+ if (strchr_m(c, *p) == NULL)
{
- case OPT_BOOL:
- case OPT_INT:
- ret = setsockopt(fd,socket_options[i].level,
- socket_options[i].option,(char *)&value,sizeof(int));
- break;
-
- case OPT_ON:
- if (got_value)
- DEBUG(0,("syntax error - %s does not take a value\n",tok));
-
- {
- int on = socket_options[i].value;
- ret = setsockopt(fd,socket_options[i].level,
- socket_options[i].option,(char *)&on,sizeof(int));
- }
- break;
+ DEBUG(5, ("Atoic: no separator characters (%s) not found\n", c));
+ return NULL;
}
-
- if (ret != 0)
- DEBUG(0,("Failed to set socket option %s\n",tok));
- }
-}
-
-
-/****************************************************************************
- close the socket communication
-****************************************************************************/
-void close_sockets(void )
-{
- close(Client);
- Client = 0;
+ return p;
}
-/****************************************************************************
- return the date and time as a string
-****************************************************************************/
-char *timestring(void )
-{
- static char TimeBuf[100];
- time_t t;
- t = time(NULL);
-#ifdef NO_STRFTIME
- strcpy(TimeBuf, asctime(LocalTime(&t,GMT_TO_LOCAL)));
-#elif defined(CLIX) || defined(CONVEX)
- strftime(TimeBuf,100,"%m/%d/%y %I:%M:%S %p",LocalTime(&t,GMT_TO_LOCAL));
-#elif defined(AMPM)
- strftime(TimeBuf,100,"%D %r",LocalTime(&t,GMT_TO_LOCAL));
-#elif defined(TZ_TIME)
- {
- strftime(TimeBuf,100,"%D:%T",LocalTime(&t,0));
- sprintf(TimeBuf+strlen(TimeBuf)," %+03d%02d",
- -TimeDiff(t)/(60*60),-(TimeDiff(t)/60)%60);
- }
-#else
- strftime(TimeBuf,100,"%D %T",LocalTime(&t,GMT_TO_LOCAL));
-#endif
- return(TimeBuf);
-}
+/*************************************************************************
+ Reads a list of numbers.
+ *************************************************************************/
-/****************************************************************************
-determine whether we are in the specified group
-****************************************************************************/
-BOOL in_group(gid_t group, int current_gid, int ngroups, int *groups)
+char *get_numlist(char *p, uint32 **num, int *count)
{
- int i;
-
- if (group == current_gid) return(True);
+ int val;
- for (i=0;i<ngroups;i++)
- if (group == groups[i])
- return(True);
-
- return(False);
-}
-
-/****************************************************************************
-this is a safer strcpy(), meant to prevent core dumps when nasty things happen
-****************************************************************************/
-char *StrCpy(char *dest,char *src)
-{
- char *d = dest;
+ if (num == NULL || count == NULL)
+ return NULL;
-#if AJT
- /* I don't want to get lazy with these ... */
- if (!dest || !src) {
- DEBUG(0,("ERROR: NULL StrCpy() called!\n"));
- ajt_panic();
- }
-#endif
+ (*count) = 0;
+ (*num ) = NULL;
- if (!dest) return(NULL);
- if (!src) {
- *dest = 0;
- return(dest);
- }
- while ((*d++ = *src++)) ;
- return(dest);
-}
+ while ((p = Atoic(p, &val, ":,")) != NULL && (*p) != ':') {
+ uint32 *tn;
+
+ tn = Realloc((*num), ((*count)+1) * sizeof(uint32));
+ if (tn == NULL)
+ {
+ SAFE_FREE(*num);
+ return NULL;
+ } else
+ (*num) = tn;
+ (*num)[(*count)] = val;
+ (*count)++;
+ p++;
+ }
-/****************************************************************************
-line strncpy but always null terminates. Make sure there is room!
-****************************************************************************/
-char *StrnCpy(char *dest,const char *src,int n)
-{
- char *d = dest;
- if (!dest) return(NULL);
- if (!src) {
- *dest = 0;
- return(dest);
- }
- while (n-- && (*d++ = *src++)) ;
- *d = 0;
- return(dest);
+ return p;
}
-
/*******************************************************************
-copy an IP address from one buffer to another
+ Check if a file exists - call vfs_file_exist for samba files.
********************************************************************/
-void putip(void *dest,void *src)
-{
- memcpy(dest,src,4);
-}
-
-/****************************************************************************
-interpret the weird netbios "name". Return the name type
-****************************************************************************/
-static int name_interpret(char *in,char *out)
+BOOL file_exist(const char *fname,SMB_STRUCT_STAT *sbuf)
{
- int ret;
- int len = (*in++) / 2;
-
- *out=0;
-
- if (len > 30 || len<1) return(0);
-
- while (len--)
- {
- if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
- *out = 0;
- return(0);
- }
- *out = ((in[0]-'A')<<4) + (in[1]-'A');
- in += 2;
- out++;
- }
- *out = 0;
- ret = out[-1];
-
-#ifdef NETBIOS_SCOPE
- /* Handle any scope names */
- while(*in)
- {
- *out++ = '.'; /* Scope names are separated by periods */
- len = *(unsigned char *)in++;
- StrnCpy(out, in, len);
- out += len;
- *out=0;
- in += len;
- }
-#endif
- return(ret);
-}
-
-/****************************************************************************
-mangle a name into netbios format
-****************************************************************************/
-int name_mangle(char *In,char *Out,char name_type)
-{
- fstring name;
- char buf[20];
- char *in = (char *)&buf[0];
- char *out = (char *)Out;
- char *p, *label;
- int i;
-
- if (In[0] != '*') {
- StrnCpy(name,In,sizeof(name)-1);
- sprintf(buf,"%-15.15s%c",name,name_type);
- } else {
- buf[0]='*';
- memset(&buf[1],0,16);
- }
-
- *out++ = 32;
- for (i=0;i<16;i++) {
- char c = toupper(in[i]);
- out[i*2] = (c>>4) + 'A';
- out[i*2+1] = (c & 0xF) + 'A';
- }
- out[32]=0;
- out += 32;
-
- label = scope;
- while (*label)
- {
- p = strchr(label, '.');
- if (p == 0)
- p = label + strlen(label);
- *out++ = p - label;
- memcpy(out, label, p - label);
- out += p - label;
- label += p - label + (*p == '.');
- }
- *out = 0;
- return(name_len(Out));
-}
-
-
-/*******************************************************************
- check if a file exists
-********************************************************************/
-BOOL file_exist(char *fname,struct stat *sbuf)
-{
- struct stat st;
- if (!sbuf) sbuf = &st;
+ SMB_STRUCT_STAT st;
+ if (!sbuf)
+ sbuf = &st;
if (sys_stat(fname,sbuf) != 0)
return(False);
@@ -996,11 +194,12 @@ BOOL file_exist(char *fname,struct stat *sbuf)
}
/*******************************************************************
-check a files mod time
+ Check a files mod time.
********************************************************************/
-time_t file_modtime(char *fname)
+
+time_t file_modtime(const char *fname)
{
- struct stat st;
+ SMB_STRUCT_STAT st;
if (sys_stat(fname,&st) != 0)
return(0);
@@ -1009,444 +208,99 @@ time_t file_modtime(char *fname)
}
/*******************************************************************
- check if a directory exists
+ Check if a directory exists.
********************************************************************/
-BOOL directory_exist(char *dname,struct stat *st)
+
+BOOL directory_exist(char *dname,SMB_STRUCT_STAT *st)
{
- struct stat st2;
+ SMB_STRUCT_STAT st2;
+ BOOL ret;
+
if (!st) st = &st2;
if (sys_stat(dname,st) != 0)
return(False);
- return(S_ISDIR(st->st_mode));
+ ret = S_ISDIR(st->st_mode);
+ if(!ret)
+ errno = ENOTDIR;
+ return ret;
}
/*******************************************************************
returns the size in bytes of the named file
********************************************************************/
-uint32 file_size(char *file_name)
+SMB_OFF_T get_file_size(char *file_name)
{
- struct stat buf;
+ SMB_STRUCT_STAT buf;
buf.st_size = 0;
- sys_stat(file_name,&buf);
+ if(sys_stat(file_name,&buf) != 0)
+ return (SMB_OFF_T)-1;
return(buf.st_size);
}
-/****************************************************************************
-check if it's a null mtime
-****************************************************************************/
-static BOOL null_mtime(time_t mtime)
-{
- if (mtime == 0 || mtime == 0xFFFFFFFF)
- return(True);
- return(False);
-}
-
-/*******************************************************************
- create a 16 bit dos packed date
-********************************************************************/
-static uint16 make_dos_date1(time_t unixdate,struct tm *t)
-{
- uint16 ret=0;
- ret = (((unsigned)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1);
- ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5));
- return(ret);
-}
-
-/*******************************************************************
- create a 16 bit dos packed time
-********************************************************************/
-static uint16 make_dos_time1(time_t unixdate,struct tm *t)
-{
- uint16 ret=0;
- ret = ((((unsigned)t->tm_min >> 3)&0x7) | (((unsigned)t->tm_hour) << 3));
- ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5));
- return(ret);
-}
-
-/*******************************************************************
- create a 32 bit dos packed date/time from some parameters
- This takes a GMT time and returns a packed localtime structure
-********************************************************************/
-static uint32 make_dos_date(time_t unixdate)
-{
- struct tm *t;
- uint32 ret=0;
-
- t = LocalTime(&unixdate,GMT_TO_LOCAL);
-
- ret = make_dos_date1(unixdate,t);
- ret = ((ret&0xFFFF)<<16) | make_dos_time1(unixdate,t);
-
- return(ret);
-}
-
-/*******************************************************************
-put a dos date into a buffer (time/date format)
-This takes GMT time and puts local time in the buffer
-********************************************************************/
-void put_dos_date(char *buf,int offset,time_t unixdate)
-{
- uint32 x = make_dos_date(unixdate);
- SIVAL(buf,offset,x);
-}
-
-/*******************************************************************
-put a dos date into a buffer (date/time format)
-This takes GMT time and puts local time in the buffer
-********************************************************************/
-void put_dos_date2(char *buf,int offset,time_t unixdate)
-{
- uint32 x = make_dos_date(unixdate);
- x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
- SIVAL(buf,offset,x);
-}
-
-/*******************************************************************
-put a dos 32 bit "unix like" date into a buffer. This routine takes
-GMT and converts it to LOCAL time before putting it (most SMBs assume
-localtime for this sort of date)
-********************************************************************/
-void put_dos_date3(char *buf,int offset,time_t unixdate)
-{
- if (!null_mtime(unixdate))
- unixdate += GMT_TO_LOCAL*TimeDiff(unixdate);
- SIVAL(buf,offset,unixdate);
-}
-
-/*******************************************************************
- interpret a 32 bit dos packed date/time to some parameters
-********************************************************************/
-static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second)
-{
- uint32 p0,p1,p2,p3;
-
- p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF;
- p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF;
-
- *second = 2*(p0 & 0x1F);
- *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3);
- *hour = (p1>>3)&0xFF;
- *day = (p2&0x1F);
- *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1;
- *year = ((p3>>1)&0xFF) + 80;
-}
-
-/*******************************************************************
- create a unix date (int GMT) from a dos date (which is actually in
- localtime)
-********************************************************************/
-time_t make_unix_date(void *date_ptr)
-{
- uint32 dos_date=0;
- struct tm t;
- time_t ret;
-
- dos_date = IVAL(date_ptr,0);
-
- if (dos_date == 0) return(0);
-
- interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
- &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
- t.tm_wday = 1;
- t.tm_yday = 1;
- t.tm_isdst = -1;
-
- /* mktime() also does the local to GMT time conversion for us. XXXXX
- Do all unixes do this the same?? */
- ret = mktime(&t);
-
- return(ret);
-}
-
-/*******************************************************************
-like make_unix_date() but the words are reversed
-********************************************************************/
-time_t make_unix_date2(void *date_ptr)
-{
- uint32 x,x2;
-
- x = IVAL(date_ptr,0);
- x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
- SIVAL(&x,0,x2);
-
- return(make_unix_date((void *)&x));
-}
-
-/*******************************************************************
- create a unix GMT date from a dos date in 32 bit "unix like" format
-these generally arrive as localtimes, with corresponding DST
-********************************************************************/
-time_t make_unix_date3(void *date_ptr)
-{
- time_t t = IVAL(date_ptr,0);
- if (!null_mtime(t))
- t += LOCAL_TO_GMT*TimeDiff(t);
- return(t);
-}
-
/*******************************************************************
return a string representing an attribute for a file
********************************************************************/
-char *attrib_string(int mode)
+char *attrib_string(uint16 mode)
{
- static char attrstr[10];
+ static fstring attrstr;
attrstr[0] = 0;
- if (mode & aVOLID) strcat(attrstr,"V");
- if (mode & aDIR) strcat(attrstr,"D");
- if (mode & aARCH) strcat(attrstr,"A");
- if (mode & aHIDDEN) strcat(attrstr,"H");
- if (mode & aSYSTEM) strcat(attrstr,"S");
- if (mode & aRONLY) strcat(attrstr,"R");
+ if (mode & aVOLID) fstrcat(attrstr,"V");
+ if (mode & aDIR) fstrcat(attrstr,"D");
+ if (mode & aARCH) fstrcat(attrstr,"A");
+ if (mode & aHIDDEN) fstrcat(attrstr,"H");
+ if (mode & aSYSTEM) fstrcat(attrstr,"S");
+ if (mode & aRONLY) fstrcat(attrstr,"R");
return(attrstr);
}
-
/*******************************************************************
- case insensitive string compararison
-********************************************************************/
-int StrCaseCmp(char *s, char *t)
-{
- for (; tolower(*s) == tolower(*t); ++s, ++t)
- if (!*s) return 0;
-
- return tolower(*s) - tolower(*t);
-}
-
-/*******************************************************************
- case insensitive string compararison, length limited
-********************************************************************/
-int StrnCaseCmp(char *s, char *t, int n)
-{
- while (n-- && *s && *t) {
- if (tolower(*s) != tolower(*t)) return(tolower(*s) - tolower(*t));
- s++; t++;
- }
- if (n) return(tolower(*s) - tolower(*t));
-
- return(0);
-}
-
-/*******************************************************************
- compare 2 strings
-********************************************************************/
-BOOL strequal(char *s1,char *s2)
-{
- if (s1 == s2) return(True);
- if (!s1 || !s2) return(False);
-
- return(StrCaseCmp(s1,s2)==0);
-}
-
-/*******************************************************************
- compare 2 strings up to and including the nth char.
- ******************************************************************/
-BOOL strnequal(char *s1,char *s2,int n)
-{
- if (s1 == s2) return(True);
- if (!s1 || !s2 || !n) return(False);
-
- return(StrnCaseCmp(s1,s2,n)==0);
-}
-
-/*******************************************************************
- compare 2 strings (case sensitive)
-********************************************************************/
-BOOL strcsequal(char *s1,char *s2)
-{
- if (s1 == s2) return(True);
- if (!s1 || !s2) return(False);
-
- return(strcmp(s1,s2)==0);
-}
-
-
-/*******************************************************************
- convert a string to lower case
-********************************************************************/
-void strlower(char *s)
-{
- while (*s)
- {
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (isupper(*s))
- *s = tolower(*s);
- s++;
- }
-#else
- if (isupper(*s))
- *s = tolower(*s);
- s++;
-#endif /* KANJI */
- }
-}
-
-/*******************************************************************
- convert a string to upper case
+ show a smb message structure
********************************************************************/
-void strupper(char *s)
+void show_msg(char *buf)
{
- while (*s)
- {
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (islower(*s))
- *s = toupper(*s);
- s++;
+ int i;
+ int bcc=0;
+
+ if (DEBUGLEVEL < 5) return;
+
+ DEBUG(5,("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\nsmb_flg=%d\nsmb_flg2=%d\n",
+ smb_len(buf),
+ (int)CVAL(buf,smb_com),
+ (int)CVAL(buf,smb_rcls),
+ (int)CVAL(buf,smb_reh),
+ (int)SVAL(buf,smb_err),
+ (int)CVAL(buf,smb_flg),
+ (int)SVAL(buf,smb_flg2)));
+ DEBUG(5,("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\nsmt_wct=%d\n",
+ (int)SVAL(buf,smb_tid),
+ (int)SVAL(buf,smb_pid),
+ (int)SVAL(buf,smb_uid),
+ (int)SVAL(buf,smb_mid),
+ (int)CVAL(buf,smb_wct)));
+
+ for (i=0;i<(int)CVAL(buf,smb_wct);i++)
+ {
+ DEBUG(5,("smb_vwv[%d]=%d (0x%X)\n",i,
+ SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i)));
}
-#else
- if (islower(*s))
- *s = toupper(*s);
- s++;
-#endif
- }
-}
-/*******************************************************************
- convert a string to "normal" form
-********************************************************************/
-void strnorm(char *s)
-{
- if (case_default == CASE_UPPER)
- strupper(s);
- else
- strlower(s);
-}
+ bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct)));
-/*******************************************************************
-check if a string is in "normal" case
-********************************************************************/
-BOOL strisnormal(char *s)
-{
- if (case_default == CASE_UPPER)
- return(!strhaslower(s));
-
- return(!strhasupper(s));
-}
+ DEBUG(5,("smb_bcc=%d\n",bcc));
+ if (DEBUGLEVEL < 10) return;
-/****************************************************************************
- string replace
-****************************************************************************/
-void string_replace(char *s,char oldc,char newc)
-{
- while (*s)
- {
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (oldc == *s)
- *s = newc;
- s++;
+ if (DEBUGLEVEL < 50)
+ {
+ bcc = MIN(bcc, 512);
}
-#else
- if (oldc == *s)
- *s = newc;
- s++;
-#endif /* KANJI */
- }
-}
-/****************************************************************************
- make a file into unix format
-****************************************************************************/
-void unix_format(char *fname)
-{
- pstring namecopy;
- string_replace(fname,'\\','/');
-#ifndef KANJI
- dos2unix_format(fname, True);
-#endif /* KANJI */
-
- if (*fname == '/')
- {
- strcpy(namecopy,fname);
- strcpy(fname,".");
- strcat(fname,namecopy);
- }
-}
-
-/****************************************************************************
- make a file into dos format
-****************************************************************************/
-void dos_format(char *fname)
-{
-#ifndef KANJI
- unix2dos_format(fname, True);
-#endif /* KANJI */
- string_replace(fname,'/','\\');
-}
-
-
-/*******************************************************************
- show a smb message structure
-********************************************************************/
-void show_msg(char *buf)
-{
- int i;
- int bcc=0;
- if (DEBUGLEVEL < 5)
- return;
-
- DEBUG(5,("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\nsmb_flg=%d\nsmb_flg2=%d\n",
- smb_len(buf),
- (int)CVAL(buf,smb_com),
- (int)CVAL(buf,smb_rcls),
- (int)CVAL(buf,smb_reh),
- (int)SVAL(buf,smb_err),
- (int)CVAL(buf,smb_flg),
- (int)SVAL(buf,smb_flg2)));
- DEBUG(5,("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\nsmt_wct=%d\n",
- (int)SVAL(buf,smb_tid),
- (int)SVAL(buf,smb_pid),
- (int)SVAL(buf,smb_uid),
- (int)SVAL(buf,smb_mid),
- (int)CVAL(buf,smb_wct)));
- for (i=0;i<(int)CVAL(buf,smb_wct);i++)
- DEBUG(5,("smb_vwv[%d]=%d (0x%X)\n",i,
- SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i)));
- bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct)));
- DEBUG(5,("smb_bcc=%d\n",bcc));
- if (DEBUGLEVEL < 10)
- return;
- for (i=0;i<MIN(bcc,128);i++)
- DEBUG(10,("%X ",CVAL(smb_buf(buf),i)));
- DEBUG(10,("\n"));
-}
-
-/*******************************************************************
- return the length of an smb packet
-********************************************************************/
-int smb_len(char *buf)
-{
- return( PVAL(buf,3) | (PVAL(buf,2)<<8) | ((PVAL(buf,1)&1)<<16) );
-}
-
-/*******************************************************************
- set the length of an smb packet
-********************************************************************/
-void _smb_setlen(char *buf,int len)
-{
- buf[0] = 0;
- buf[1] = (len&0x10000)>>16;
- buf[2] = (len&0xFF00)>>8;
- buf[3] = len&0xFF;
+ dump_data(10, smb_buf(buf), bcc);
}
/*******************************************************************
@@ -1456,10 +310,10 @@ void smb_setlen(char *buf,int len)
{
_smb_setlen(buf,len);
- CVAL(buf,4) = 0xFF;
- CVAL(buf,5) = 'S';
- CVAL(buf,6) = 'M';
- CVAL(buf,7) = 'B';
+ SCVAL(buf,4,0xFF);
+ SCVAL(buf,5,'S');
+ SCVAL(buf,6,'M');
+ SCVAL(buf,7,'B');
}
/*******************************************************************
@@ -1467,93 +321,35 @@ void smb_setlen(char *buf,int len)
********************************************************************/
int set_message(char *buf,int num_words,int num_bytes,BOOL zero)
{
- if (zero)
- bzero(buf + smb_size,num_words*2 + num_bytes);
- CVAL(buf,smb_wct) = num_words;
- SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
- smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
- return (smb_size + num_words*2 + num_bytes);
+ if (zero)
+ memset(buf + smb_size,'\0',num_words*2 + num_bytes);
+ SCVAL(buf,smb_wct,num_words);
+ SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
+ smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
+ return (smb_size + num_words*2 + num_bytes);
}
/*******************************************************************
-return the number of smb words
+ setup only the byte count for a smb message
********************************************************************/
-int smb_numwords(char *buf)
+int set_message_bcc(char *buf,int num_bytes)
{
- return (CVAL(buf,smb_wct));
+ int num_words = CVAL(buf,smb_wct);
+ SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
+ smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
+ return (smb_size + num_words*2 + num_bytes);
}
/*******************************************************************
-return the size of the smb_buf region of a message
+ setup only the byte count for a smb message, using the end of the
+ message as a marker
********************************************************************/
-int smb_buflen(char *buf)
+int set_message_end(void *outbuf,void *end_ptr)
{
- return(SVAL(buf,smb_vwv0 + smb_numwords(buf)*2));
+ return set_message_bcc((char *)outbuf,PTR_DIFF(end_ptr,smb_buf((char *)outbuf)));
}
/*******************************************************************
- return a pointer to the smb_buf data area
-********************************************************************/
-int smb_buf_ofs(char *buf)
-{
- return (smb_size + CVAL(buf,smb_wct)*2);
-}
-
-/*******************************************************************
- return a pointer to the smb_buf data area
-********************************************************************/
-char *smb_buf(char *buf)
-{
- return (buf + smb_buf_ofs(buf));
-}
-
-/*******************************************************************
-return the SMB offset into an SMB buffer
-********************************************************************/
-int smb_offset(char *p,char *buf)
-{
- return(PTR_DIFF(p,buf+4));
-}
-
-
-/*******************************************************************
-skip past some strings in a buffer
-********************************************************************/
-char *skip_string(char *buf,int n)
-{
- while (n--)
- buf += strlen(buf) + 1;
- return(buf);
-}
-
-/*******************************************************************
-trim the specified elements off the front and back of a string
-********************************************************************/
-BOOL trim_string(char *s,char *front,char *back)
-{
- BOOL ret = False;
- while (front && *front && strncmp(s,front,strlen(front)) == 0)
- {
- char *p = s;
- ret = True;
- while (1)
- {
- if (!(*p = p[strlen(front)]))
- break;
- p++;
- }
- }
- while (back && *back && strlen(s) >= strlen(back) &&
- (strncmp(s+strlen(s)-strlen(back),back,strlen(back))==0))
- {
- ret = True;
- s[strlen(s)-strlen(back)] = 0;
- }
- return(ret);
-}
-
-
-/*******************************************************************
reduce a file name, removing .. elements.
********************************************************************/
void dos_clean_name(char *s)
@@ -1563,25 +359,25 @@ void dos_clean_name(char *s)
DEBUG(3,("dos_clean_name [%s]\n",s));
/* remove any double slashes */
- string_sub(s, "\\\\", "\\");
+ all_string_sub(s, "\\\\", "\\", 0);
while ((p = strstr(s,"\\..\\")) != NULL)
{
pstring s1;
*p = 0;
- strcpy(s1,p+3);
+ pstrcpy(s1,p+3);
- if ((p=strrchr(s,'\\')) != NULL)
+ if ((p=strrchr_m(s,'\\')) != NULL)
*p = 0;
else
*s = 0;
- strcat(s,s1);
+ pstrcat(s,s1);
}
trim_string(s,NULL,"\\..");
- string_sub(s, "\\.\\", "\\");
+ all_string_sub(s, "\\.\\", "\\", 0);
}
/*******************************************************************
@@ -1594,474 +390,119 @@ void unix_clean_name(char *s)
DEBUG(3,("unix_clean_name [%s]\n",s));
/* remove any double slashes */
- string_sub(s, "//","/");
+ all_string_sub(s, "//","/", 0);
+
+ /* Remove leading ./ characters */
+ if(strncmp(s, "./", 2) == 0) {
+ trim_string(s, "./", NULL);
+ if(*s == 0)
+ pstrcpy(s,"./");
+ }
while ((p = strstr(s,"/../")) != NULL)
{
pstring s1;
*p = 0;
- strcpy(s1,p+3);
+ pstrcpy(s1,p+3);
- if ((p=strrchr(s,'/')) != NULL)
+ if ((p=strrchr_m(s,'/')) != NULL)
*p = 0;
else
*s = 0;
- strcat(s,s1);
+ pstrcat(s,s1);
}
trim_string(s,NULL,"/..");
}
-
/*******************************************************************
-a wrapper for the normal chdir() function
+convert '\' to '/'
+reduce a file name, removing or reducing /../ , /./ , // elements.
+remove also any trailing . and /
+return a new allocated string.
********************************************************************/
-int ChDir(char *path)
-{
- int res;
- static pstring LastDir="";
-
- if (strcsequal(path,".")) return(0);
-
- if (*path == '/' && strcsequal(LastDir,path)) return(0);
- DEBUG(3,("chdir to %s\n",path));
- res = sys_chdir(path);
- if (!res)
- strcpy(LastDir,path);
- return(res);
-}
-
-
-/*******************************************************************
- return the absolute current directory path. A dumb version.
-********************************************************************/
-static char *Dumb_GetWd(char *s)
-{
-#ifdef USE_GETCWD
- return ((char *)getcwd(s,sizeof(pstring)));
-#else
- return ((char *)getwd(s));
-#endif
-}
-
-
-/* number of list structures for a caching GetWd function. */
-#define MAX_GETWDCACHE (50)
-
-struct
-{
- ino_t inode;
- dev_t dev;
- char *text;
- BOOL valid;
-} ino_list[MAX_GETWDCACHE];
-
-BOOL use_getwd_cache=True;
-
-/*******************************************************************
- return the absolute current directory path
-********************************************************************/
-char *GetWd(char *str)
-{
- pstring s;
- static BOOL getwd_cache_init = False;
- struct stat st, st2;
- int i;
-
- *s = 0;
-
- if (!use_getwd_cache)
- return(Dumb_GetWd(str));
-
- /* init the cache */
- if (!getwd_cache_init)
- {
- getwd_cache_init = True;
- for (i=0;i<MAX_GETWDCACHE;i++)
- {
- string_init(&ino_list[i].text,"");
- ino_list[i].valid = False;
+smb_ucs2_t *unix_clean_path(const smb_ucs2_t *s)
+{
+ smb_ucs2_t *ns;
+ smb_ucs2_t *p, *r, *t;
+
+ DEBUG(3, ("unix_clean_path\n")); /* [%unicode]\n")); */
+ if(!s) return NULL;
+
+ /* convert '\' to '/' */
+ ns = strdup_w(s);
+ if (!ns) return NULL;
+ unix_format_w(ns);
+
+ /* remove all double slashes */
+ p = ns;
+ ns = all_string_sub_wa(p, "//", "/");
+ SAFE_FREE(p);
+ if (!ns) return NULL;
+
+ /* remove any /./ */
+ p = ns;
+ ns = all_string_sub_wa(p, "/./", "/");
+ SAFE_FREE(p);
+ if (!ns) return NULL;
+
+ /* reduce any /../ */
+ t = ns;
+ while (*t && (r = strstr_wa(t, "/.."))) {
+ t = &(r[3]);
+ if (*t == UCS2_CHAR('/') || *t == 0) {
+ *r = 0;
+ p = strrchr_w(ns, UCS2_CHAR('/'));
+ if (!p) p = ns;
+ if (*t == 0) *p = 0;
+ else memmove(p, t, (strlen_w(t) + 1) * sizeof(smb_ucs2_t));
+ t = p;
+ }
}
- }
-
- /* Get the inode of the current directory, if this doesn't work we're
- in trouble :-) */
-
- if (stat(".",&st) == -1)
- {
- DEBUG(0,("Very strange, couldn't stat \".\"\n"));
- return(Dumb_GetWd(str));
- }
-
-
- for (i=0; i<MAX_GETWDCACHE; i++)
- if (ino_list[i].valid)
- {
-
- /* If we have found an entry with a matching inode and dev number
- then find the inode number for the directory in the cached string.
- If this agrees with that returned by the stat for the current
- directory then all is o.k. (but make sure it is a directory all
- the same...) */
-
- if (st.st_ino == ino_list[i].inode &&
- st.st_dev == ino_list[i].dev)
- {
- if (stat(ino_list[i].text,&st2) == 0)
- {
- if (st.st_ino == st2.st_ino &&
- st.st_dev == st2.st_dev &&
- (st2.st_mode & S_IFMT) == S_IFDIR)
- {
- strcpy (str, ino_list[i].text);
-
- /* promote it for future use */
- array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
- return (str);
- }
- else
- {
- /* If the inode is different then something's changed,
- scrub the entry and start from scratch. */
- ino_list[i].valid = False;
- }
- }
- }
- }
+ /* remove any leading ./ trailing /. */
+ trim_string_wa(ns, "./", "/.");
- /* We don't have the information to hand so rely on traditional methods.
- The very slow getcwd, which spawns a process on some systems, or the
- not quite so bad getwd. */
-
- if (!Dumb_GetWd(s))
- {
- DEBUG(0,("Getwd failed, errno %d\n",errno));
- return (NULL);
- }
+ /* remove any leading and trailing / */
+ trim_string_wa(ns, "/", "/");
- strcpy(str,s);
-
- DEBUG(5,("GetWd %s, inode %d, dev %x\n",s,(int)st.st_ino,(int)st.st_dev));
-
- /* add it to the cache */
- i = MAX_GETWDCACHE - 1;
- string_set(&ino_list[i].text,s);
- ino_list[i].dev = st.st_dev;
- ino_list[i].inode = st.st_ino;
- ino_list[i].valid = True;
-
- /* put it at the top of the list */
- array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
-
- return (str);
+ return ns;
}
-
-
-/*******************************************************************
-reduce a file name, removing .. elements and checking that
-it is below dir in the heirachy. This uses GetWd() and so must be run
-on the system that has the referenced file system.
-
-widelinks are allowed if widelinks is true
-********************************************************************/
-BOOL reduce_name(char *s,char *dir,BOOL widelinks)
-{
-#ifndef REDUCE_PATHS
- return True;
-#else
- pstring dir2;
- pstring wd;
- pstring basename;
- pstring newname;
- char *p=NULL;
- BOOL relative = (*s != '/');
-
- *dir2 = *wd = *basename = *newname = 0;
-
- if (widelinks)
- {
- unix_clean_name(s);
- /* can't have a leading .. */
- if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/'))
- {
- DEBUG(3,("Illegal file name? (%s)\n",s));
- return(False);
- }
- return(True);
- }
-
- DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
-
- /* remove any double slashes */
- string_sub(s,"//","/");
-
- strcpy(basename,s);
- p = strrchr(basename,'/');
-
- if (!p)
- return(True);
-
- if (!GetWd(wd))
- {
- DEBUG(0,("couldn't getwd for %s %s\n",s,dir));
- return(False);
- }
-
- if (ChDir(dir) != 0)
- {
- DEBUG(0,("couldn't chdir to %s\n",dir));
- return(False);
- }
-
- if (!GetWd(dir2))
- {
- DEBUG(0,("couldn't getwd for %s\n",dir));
- ChDir(wd);
- return(False);
- }
-
-
- if (p && (p != basename))
- {
- *p = 0;
- if (strcmp(p+1,".")==0)
- p[1]=0;
- if (strcmp(p+1,"..")==0)
- *p = '/';
- }
-
- if (ChDir(basename) != 0)
- {
- ChDir(wd);
- DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,basename));
- return(False);
- }
-
- if (!GetWd(newname))
- {
- ChDir(wd);
- DEBUG(2,("couldn't get wd for %s %s\n",s,dir2));
- return(False);
- }
-
- if (p && (p != basename))
- {
- strcat(newname,"/");
- strcat(newname,p+1);
- }
-
- {
- int l = strlen(dir2);
- if (dir2[l-1] == '/')
- l--;
-
- if (strncmp(newname,dir2,l) != 0)
- {
- ChDir(wd);
- DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,l));
- return(False);
- }
-
- if (relative)
- {
- if (newname[l] == '/')
- strcpy(s,newname + l + 1);
- else
- strcpy(s,newname+l);
- }
- else
- strcpy(s,newname);
- }
-
- ChDir(wd);
-
- if (strlen(s) == 0)
- strcpy(s,"./");
-
- DEBUG(3,("reduced to %s\n",s));
- return(True);
-#endif
-}
-
-/****************************************************************************
-expand some *s
-****************************************************************************/
-static void expand_one(char *Mask,int len)
-{
- char *p1;
- while ((p1 = strchr(Mask,'*')) != NULL)
- {
- int lfill = (len+1) - strlen(Mask);
- int l1= (p1 - Mask);
- pstring tmp;
- strcpy(tmp,Mask);
- memset(tmp+l1,'?',lfill);
- strcpy(tmp + l1 + lfill,Mask + l1 + 1);
- strcpy(Mask,tmp);
- }
-}
-
-/****************************************************************************
-expand a wildcard expression, replacing *s with ?s
-****************************************************************************/
-void expand_mask(char *Mask,BOOL doext)
-{
- pstring mbeg,mext;
- pstring dirpart;
- pstring filepart;
- BOOL hasdot = False;
- char *p1;
- BOOL absolute = (*Mask == '\\');
-
- *mbeg = *mext = *dirpart = *filepart = 0;
-
- /* parse the directory and filename */
- if (strchr(Mask,'\\'))
- dirname_dos(Mask,dirpart);
-
- filename_dos(Mask,filepart);
-
- strcpy(mbeg,filepart);
- if ((p1 = strchr(mbeg,'.')) != NULL)
- {
- hasdot = True;
- *p1 = 0;
- p1++;
- strcpy(mext,p1);
- }
- else
- {
- strcpy(mext,"");
- if (strlen(mbeg) > 8)
- {
- strcpy(mext,mbeg + 8);
- mbeg[8] = 0;
- }
- }
-
- if (*mbeg == 0)
- strcpy(mbeg,"????????");
- if ((*mext == 0) && doext && !hasdot)
- strcpy(mext,"???");
-
- if (strequal(mbeg,"*") && *mext==0)
- strcpy(mext,"*");
-
- /* expand *'s */
- expand_one(mbeg,8);
- if (*mext)
- expand_one(mext,3);
-
- strcpy(Mask,dirpart);
- if (*dirpart || absolute) strcat(Mask,"\\");
- strcat(Mask,mbeg);
- strcat(Mask,".");
- strcat(Mask,mext);
-
- DEBUG(6,("Mask expanded to [%s]\n",Mask));
-}
-
-
-/****************************************************************************
-does a string have any uppercase chars in it?
-****************************************************************************/
-BOOL strhasupper(char *s)
-{
- while (*s)
- {
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (isupper(*s)) return(True);
- s++;
- }
-#else
- if (isupper(*s)) return(True);
- s++;
-#endif /* KANJI */
- }
- return(False);
-}
-
-/****************************************************************************
-does a string have any lowercase chars in it?
-****************************************************************************/
-BOOL strhaslower(char *s)
-{
- while (*s)
- {
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (islower(*s)) return(True);
- s++;
- }
-#else
- if (islower(*s)) return(True);
- s++;
-#endif /* KANJI */
- }
- return(False);
-}
-
-/****************************************************************************
-find the number of chars in a string
-****************************************************************************/
-int count_chars(char *s,char c)
-{
- int count=0;
- while (*s)
- {
- if (*s == c)
- count++;
- s++;
- }
- return(count);
-}
-
-
/****************************************************************************
make a dir struct
****************************************************************************/
-void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode,time_t date)
+void make_dir_struct(char *buf,char *mask,char *fname,SMB_OFF_T size,int mode,time_t date)
{
char *p;
pstring mask2;
- strcpy(mask2,mask);
+ pstrcpy(mask2,mask);
if ((mode & aDIR) != 0)
size = 0;
memset(buf+1,' ',11);
- if ((p = strchr(mask2,'.')) != NULL)
+ if ((p = strchr_m(mask2,'.')) != NULL)
{
*p = 0;
- memcpy(buf+1,mask2,MIN(strlen(mask2),8));
- memcpy(buf+9,p+1,MIN(strlen(p+1),3));
+ push_ascii(buf+1,mask2,8, 0);
+ push_ascii(buf+9,p+1,3, 0);
*p = '.';
}
else
- memcpy(buf+1,mask2,MIN(strlen(mask2),11));
+ push_ascii(buf+1,mask2,11, 0);
- bzero(buf+21,DIR_STRUCT_SIZE-21);
- CVAL(buf,21) = mode;
+ memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
+ SCVAL(buf,21,mode);
put_dos_date(buf,22,date);
SSVAL(buf,26,size & 0xFFFF);
- SSVAL(buf,28,size >> 16);
- StrnCpy(buf+30,fname,12);
+ SSVAL(buf,28,(size >> 16)&0xFFFF);
+ push_ascii(buf+30,fname,12, 0);
if (!case_sensitive)
strupper(buf+30);
- DEBUG(8,("put name [%s] into dir struct\n",buf+30));
+ DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
}
@@ -2072,12 +513,15 @@ void close_low_fds(void)
{
int fd;
int i;
- close(0); close(1); close(2);
+ close(0); close(1);
+#ifndef __INSURE__
+ close(2);
+#endif
/* try and use up these file descriptors, so silly
library routines writing to stdout etc won't cause havoc */
for (i=0;i<3;i++) {
- fd = open("/dev/null",O_RDWR,0);
- if (fd < 0) fd = open("/dev/null",O_WRONLY,0);
+ fd = sys_open("/dev/null",O_RDWR,0);
+ if (fd < 0) fd = sys_open("/dev/null",O_WRONLY,0);
if (fd < 0) {
DEBUG(0,("Can't open /dev/null\n"));
return;
@@ -2089,48 +533,6 @@ void close_low_fds(void)
}
}
-
-/****************************************************************************
-write to a socket
-****************************************************************************/
-int write_socket(int fd,char *buf,int len)
-{
- int ret=0;
-
- if (passive)
- return(len);
- DEBUG(6,("write_socket(%d,%d)\n",fd,len));
- ret = write_data(fd,buf,len);
-
- DEBUG(6,("write_socket(%d,%d) wrote %d\n",fd,len,ret));
- return(ret);
-}
-
-/****************************************************************************
-read from a socket
-****************************************************************************/
-int read_udp_socket(int fd,char *buf,int len)
-{
- int ret;
- struct sockaddr sock;
- int socklen;
-
- socklen = sizeof(sock);
- bzero((char *)&sock,socklen);
- bzero((char *)&lastip,sizeof(lastip));
- ret = recvfrom(fd,buf,len,0,&sock,&socklen);
- if (ret <= 0)
- {
- DEBUG(2,("read socket failed. ERRNO=%d\n",errno));
- return(0);
- }
-
- lastip = *(struct in_addr *) &sock.sa_data[2];
- lastport = ntohs(((struct sockaddr_in *)&sock)->sin_port);
-
- return(ret);
-}
-
/****************************************************************************
Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
else
@@ -2139,7 +541,7 @@ if BSD use FNDELAY
****************************************************************************/
int set_blocking(int fd, BOOL set)
{
-int val;
+ int val;
#ifdef O_NONBLOCK
#define FLAG_TO_SET O_NONBLOCK
#else
@@ -2150,7 +552,7 @@ int val;
#endif
#endif
- if((val = fcntl(fd, F_GETFL, 0))==-1)
+ if((val = fcntl(fd, F_GETFL, 0)) == -1)
return -1;
if(set) /* Turn blocking on - ie. clear nonblock flag */
val &= ~FLAG_TO_SET;
@@ -2160,2351 +562,1656 @@ int val;
#undef FLAG_TO_SET
}
-
/****************************************************************************
-Calculate the difference in timeout values. Return 1 if val1 > val2,
-0 if val1 == val2, -1 if val1 < val2. Stores result in retval. retval
-may be == val1 or val2
+ Transfer some data between two fd's.
****************************************************************************/
-static int tval_sub( struct timeval *retval, struct timeval *val1, struct timeval *val2)
-{
- int usecdiff = val1->tv_usec - val2->tv_usec;
- int secdiff = val1->tv_sec - val2->tv_sec;
- if(usecdiff < 0) {
- usecdiff = 1000000 + usecdiff;
- secdiff--;
- }
- retval->tv_sec = secdiff;
- retval->tv_usec = usecdiff;
- if(secdiff < 0)
- return -1;
- if(secdiff > 0)
- return 1;
- return (usecdiff < 0 ) ? -1 : ((usecdiff > 0 ) ? 1 : 0);
-}
-/****************************************************************************
-read data from a device with a timout in msec.
-mincount = if timeout, minimum to read before returning
-maxcount = number to be read.
-****************************************************************************/
-int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact)
-{
- fd_set fds;
- int selrtn;
- int readret;
- int nread = 0;
- struct timeval timeout, tval1, tval2, tvaldiff;
- int error_limit = 5;
+#ifndef TRANSFER_BUF_SIZE
+#define TRANSFER_BUF_SIZE 65536
+#endif
- /* just checking .... */
- if (maxcnt <= 0) return(0);
+ssize_t transfer_file_internal(int infd, int outfd, size_t n, ssize_t (*read_fn)(int, void *, size_t),
+ ssize_t (*write_fn)(int, const void *, size_t))
+{
+ char *buf;
+ size_t total = 0;
+ ssize_t read_ret;
+ ssize_t write_ret;
+ size_t num_to_read_thistime;
+ size_t num_written = 0;
- if(time_out == -2)
- time_out = DEFAULT_PIPE_TIMEOUT;
+ if ((buf = malloc(TRANSFER_BUF_SIZE)) == NULL)
+ return -1;
- /* Blocking read */
- if(time_out < 0) {
- if (mincnt == 0) mincnt = maxcnt;
+ while (total < n) {
+ num_to_read_thistime = MIN((n - total), TRANSFER_BUF_SIZE);
- while (nread < mincnt)
- {
- readret = read(fd, buf + nread, maxcnt - nread);
- if (readret <= 0) return(nread);
- nread += readret;
- }
- return(nread);
- }
-
- /* Non blocking read */
- if(time_out == 0) {
- set_blocking(fd, False);
- nread = read_data(fd, buf, mincnt);
- if (nread < maxcnt)
- nread += read(fd,buf+nread,maxcnt-nread);
- if(nread == -1 && errno == EWOULDBLOCK)
- nread = 0;
- set_blocking(fd,True);
- return nread;
- }
+ read_ret = (*read_fn)(infd, buf, num_to_read_thistime);
+ if (read_ret == -1) {
+ DEBUG(0,("transfer_file_internal: read failure. Error = %s\n", strerror(errno) ));
+ SAFE_FREE(buf);
+ return -1;
+ }
+ if (read_ret == 0)
+ break;
- /* Most difficult - timeout read */
- /* If this is ever called on a disk file and
- mincnt is greater then the filesize then
- system performance will suffer severely as
- select always return true on disk files */
-
- /* Set initial timeout */
- timeout.tv_sec = time_out / 1000;
- timeout.tv_usec = 1000 * (time_out % 1000);
-
- /* As most UNIXes don't modify the value of timeout
- when they return from select we need to get the timeofday (in usec)
- now, and also after the select returns so we know
- how much time has elapsed */
-
- if (exact)
- GetTimeOfDay( &tval1);
- nread = 0; /* Number of bytes we have read */
-
- for(;;)
- {
- FD_ZERO(&fds);
- FD_SET(fd,&fds);
-
- selrtn = sys_select(&fds,&timeout);
-
- /* Check if error */
- if(selrtn == -1) {
- errno = EBADF;
- return -1;
- }
-
- /* Did we timeout ? */
- if (selrtn == 0) {
- if (nread < mincnt) return -1;
- break; /* Yes */
- }
-
- readret = read(fd, buf+nread, maxcnt-nread);
- if (readret == 0 && nread < mincnt) {
- /* error_limit should not really be needed, but some systems
- do strange things ... I don't want to just continue
- indefinately in case we get an infinite loop */
- if (error_limit--) continue;
- return(-1);
- }
+ num_written = 0;
+
+ while (num_written < read_ret) {
+ write_ret = (*write_fn)(outfd,buf + num_written, read_ret - num_written);
+
+ if (write_ret == -1) {
+ DEBUG(0,("transfer_file_internal: write failure. Error = %s\n", strerror(errno) ));
+ SAFE_FREE(buf);
+ return -1;
+ }
+ if (write_ret == 0)
+ return (ssize_t)total;
+
+ num_written += (size_t)write_ret;
+ }
- if (readret < 0) {
- /* force a particular error number for
- portability */
- DEBUG(5,("read gave error %s\n",strerror(errno)));
- errno = EBADF;
- return -1;
- }
-
- nread += readret;
-
- /* If we have read more than mincnt then return */
- if (nread >= mincnt)
- break;
-
- /* We need to do another select - but first reduce the
- time_out by the amount of time already elapsed - if
- this is less than zero then return */
- if (exact) {
- GetTimeOfDay(&tval2);
- (void)tval_sub( &tvaldiff, &tval2, &tval1);
-
- if (tval_sub(&timeout, &timeout, &tvaldiff) <= 0)
- break; /* We timed out */
- }
-
- /* Save the time of day as we need to do the select
- again (saves a system call) */
- tval1 = tval2;
- }
+ total += (size_t)read_ret;
+ }
- /* Return the number we got */
- return(nread);
+ SAFE_FREE(buf);
+ return (ssize_t)total;
}
-/****************************************************************************
-read data from the client. Maxtime is in milliseconds
-****************************************************************************/
-int read_max_udp(int fd,char *buffer,int bufsize,int maxtime)
+SMB_OFF_T transfer_file(int infd,int outfd,SMB_OFF_T n)
{
- fd_set fds;
- int selrtn;
- int nread;
- struct timeval timeout;
-
- FD_ZERO(&fds);
- FD_SET(fd,&fds);
-
- timeout.tv_sec = maxtime / 1000;
- timeout.tv_usec = (maxtime % 1000) * 1000;
-
- selrtn = sys_select(&fds,maxtime>0?&timeout:NULL);
-
- if (!FD_ISSET(fd,&fds))
- return 0;
-
- nread = read_udp_socket(fd, buffer, bufsize);
-
- /* return the number got */
- return(nread);
+ return (SMB_OFF_T)transfer_file_internal(infd, outfd, (size_t)n, read, write);
}
/*******************************************************************
-find the difference in milliseconds between two struct timeval
-values
+ Sleep for a specified number of milliseconds.
********************************************************************/
-int TvalDiff(struct timeval *tvalold,struct timeval *tvalnew)
-{
- return((tvalnew->tv_sec - tvalold->tv_sec)*1000 +
- ((int)tvalnew->tv_usec - (int)tvalold->tv_usec)/1000);
-}
-/****************************************************************************
-send a keepalive packet (rfc1002)
-****************************************************************************/
-BOOL send_keepalive(int client)
+void msleep(unsigned int t)
{
- unsigned char buf[4];
-
- buf[0] = 0x85;
- buf[1] = buf[2] = buf[3] = 0;
+ unsigned int tdiff=0;
+ struct timeval tval,t1,t2;
+ fd_set fds;
- return(write_data(client,(char *)buf,4) == 4);
+ GetTimeOfDay(&t1);
+ GetTimeOfDay(&t2);
+
+ while (tdiff < t) {
+ tval.tv_sec = (t-tdiff)/1000;
+ tval.tv_usec = 1000*((t-tdiff)%1000);
+
+ /* Never wait for more than 1 sec. */
+ if (tval.tv_sec > 1) {
+ tval.tv_sec = 1;
+ tval.tv_usec = 0;
+ }
+
+ FD_ZERO(&fds);
+ errno = 0;
+ sys_select_intr(0,&fds,NULL,NULL,&tval);
+
+ GetTimeOfDay(&t2);
+ if (t2.tv_sec < t1.tv_sec) {
+ /* Someone adjusted time... */
+ t1 = t2;
+ }
+
+ tdiff = TvalDiff(&t1,&t2);
+ }
}
-
-
/****************************************************************************
- read data from the client, reading exactly N bytes.
+ Become a daemon, discarding the controlling terminal.
****************************************************************************/
-int read_data(int fd,char *buffer,int N)
+
+void become_daemon(void)
{
- int ret;
- int total=0;
-
- while (total < N)
- {
- ret = read(fd,buffer + total,N - total);
+ if (sys_fork()) {
+ _exit(0);
+ }
- /* this is for portability */
- if (ret < 0)
- errno = EBADF;
+ /* detach from the terminal */
+#ifdef HAVE_SETSID
+ setsid();
+#elif defined(TIOCNOTTY)
+ {
+ int i = sys_open("/dev/tty", O_RDWR, 0);
+ if (i != -1) {
+ ioctl(i, (int) TIOCNOTTY, (char *)0);
+ close(i);
+ }
+ }
+#endif /* HAVE_SETSID */
- if (ret <= 0)
- return total;
- total += ret;
- }
- return total;
+ /* Close fd's 0,1,2. Needed if started by rsh */
+ close_low_fds();
}
/****************************************************************************
- write data to a fd
+put up a yes/no prompt
****************************************************************************/
-int write_data(int fd,char *buffer,int N)
+BOOL yesno(char *p)
{
- int total=0;
- int ret;
+ pstring ans;
+ printf("%s",p);
- while (total < N)
- {
- ret = write(fd,buffer + total,N - total);
+ if (!fgets(ans,sizeof(ans)-1,stdin))
+ return(False);
- if (ret <= 0)
- return total;
+ if (*ans == 'y' || *ans == 'Y')
+ return(True);
- total += ret;
- }
- return total;
+ return(False);
}
-
-/* variables used by the read prediction module */
-int rp_fd = -1;
-int rp_offset = 0;
-int rp_length = 0;
-int rp_alloced = 0;
-int rp_predict_fd = -1;
-int rp_predict_offset = 0;
-int rp_predict_length = 0;
-int rp_timeout = 5;
-time_t rp_time = 0;
-char *rp_buffer = NULL;
-BOOL predict_skip=False;
-time_t smb_last_time=(time_t)0;
-
/****************************************************************************
-handle read prediction on a file
+ Expand a pointer to be a particular size.
****************************************************************************/
-int read_predict(int fd,int offset,char *buf,char **ptr,int num)
-{
- int ret = 0;
- int possible = rp_length - (offset - rp_offset);
-
- possible = MIN(possible,num);
-
- /* give data if possible */
- if (fd == rp_fd &&
- offset >= rp_offset &&
- possible>0 &&
- smb_last_time-rp_time < rp_timeout)
- {
- ret = possible;
- if (buf)
- memcpy(buf,rp_buffer + (offset-rp_offset),possible);
- else
- *ptr = rp_buffer + (offset-rp_offset);
- DEBUG(5,("read-prediction gave %d bytes of %d\n",ret,num));
- }
- if (ret == num) {
- predict_skip = True;
- } else {
- predict_skip = False;
+void *Realloc(void *p,size_t size)
+{
+ void *ret=NULL;
- /* prepare the next prediction */
- rp_predict_fd = fd;
- rp_predict_offset = offset + num;
- rp_predict_length = num;
+ if (size == 0) {
+ SAFE_FREE(p);
+ DEBUG(5,("Realloc asked for 0 bytes\n"));
+ return NULL;
}
- if (ret < 0) ret = 0;
+ if (!p)
+ ret = (void *)malloc(size);
+ else
+ ret = (void *)realloc(p,size);
+
+ if (!ret)
+ DEBUG(0,("Memory allocation error: failed to expand to %d bytes\n",(int)size));
return(ret);
}
/****************************************************************************
-pre-read some data
+ Free memory, checks for NULL.
+use directly SAFE_FREE()
+exist only because we need to pass a function pointer somewhere --SSS
****************************************************************************/
-void do_read_prediction()
+
+void safe_free(void *p)
{
- if (predict_skip) return;
+ SAFE_FREE(p);
+}
- if (rp_predict_fd == -1)
- return;
+/****************************************************************************
+ Get my own name and IP.
+****************************************************************************/
- rp_fd = rp_predict_fd;
- rp_offset = rp_predict_offset;
- rp_length = 0;
+BOOL get_myname(char *my_name)
+{
+ pstring hostname;
- rp_predict_fd = -1;
+ *hostname = 0;
- rp_predict_length = MIN(rp_predict_length,2*ReadSize);
- rp_predict_length = MAX(rp_predict_length,1024);
- rp_offset = (rp_offset/1024)*1024;
- rp_predict_length = (rp_predict_length/1024)*1024;
+ /* get my host name */
+ if (gethostname(hostname, sizeof(hostname)) == -1) {
+ DEBUG(0,("gethostname failed\n"));
+ return False;
+ }
- if (rp_predict_length > rp_alloced)
- {
- rp_buffer = Realloc(rp_buffer,rp_predict_length);
- rp_alloced = rp_predict_length;
- if (!rp_buffer)
- {
- DEBUG(0,("can't allocate read-prediction buffer\n"));
- rp_predict_fd = -1;
- rp_fd = -1;
- rp_alloced = 0;
- return;
- }
- }
+ /* Ensure null termination. */
+ hostname[sizeof(hostname)-1] = '\0';
- if (lseek(rp_fd,rp_offset,SEEK_SET) != rp_offset) {
- rp_fd = -1;
- rp_predict_fd = -1;
- return;
- }
+ if (my_name) {
+ /* split off any parts after an initial . */
+ char *p = strchr_m(hostname,'.');
- rp_length = read(rp_fd,rp_buffer,rp_predict_length);
- rp_time = time(NULL);
- if (rp_length < 0)
- rp_length = 0;
+ if (p)
+ *p = 0;
+
+ fstrcpy(my_name,hostname);
+ }
+
+ return(True);
}
/****************************************************************************
-invalidate read-prediction on a fd
+ Interpret a protocol description string, with a default.
****************************************************************************/
-void invalidate_read_prediction(int fd)
+
+int interpret_protocol(char *str,int def)
{
- if (rp_fd == fd)
- rp_fd = -1;
- if (rp_predict_fd == fd)
- rp_predict_fd = -1;
+ if (strequal(str,"NT1"))
+ return(PROTOCOL_NT1);
+ if (strequal(str,"LANMAN2"))
+ return(PROTOCOL_LANMAN2);
+ if (strequal(str,"LANMAN1"))
+ return(PROTOCOL_LANMAN1);
+ if (strequal(str,"CORE"))
+ return(PROTOCOL_CORE);
+ if (strequal(str,"COREPLUS"))
+ return(PROTOCOL_COREPLUS);
+ if (strequal(str,"CORE+"))
+ return(PROTOCOL_COREPLUS);
+
+ DEBUG(0,("Unrecognised protocol level %s\n",str));
+
+ return(def);
}
-
/****************************************************************************
-transfer some data between two fd's
+ Return true if a string could be a pure IP address.
****************************************************************************/
-int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align)
+
+BOOL is_ipaddress(const char *str)
{
- static char *buf=NULL;
- char *buf1,*abuf;
- static int size = 0;
- int total = 0;
+ BOOL pure_address = True;
+ int i;
+
+ for (i=0; pure_address && str[i]; i++)
+ if (!(isdigit((int)str[i]) || str[i] == '.'))
+ pure_address = False;
- DEBUG(4,("transfer_file %d (head=%d) called\n",n,headlen));
+ /* Check that a pure number is not misinterpreted as an IP */
+ pure_address = pure_address && (strchr_m(str, '.') != NULL);
- if ((size < ReadSize) && buf) {
- free(buf);
- buf = NULL;
- }
+ return pure_address;
+}
- size = MAX(ReadSize,1024);
+/****************************************************************************
+interpret an internet address or name into an IP address in 4 byte form
+****************************************************************************/
- while (!buf && size>0) {
- buf = (char *)Realloc(buf,size+8);
- if (!buf) size /= 2;
- }
- if (!buf) {
- DEBUG(0,("Can't allocate transfer buffer!\n"));
- exit(1);
- }
+uint32 interpret_addr(const char *str)
+{
+ struct hostent *hp;
+ uint32 res;
- abuf = buf + (align%8);
+ if (strcmp(str,"0.0.0.0") == 0) return(0);
+ if (strcmp(str,"255.255.255.255") == 0) return(0xFFFFFFFF);
- if (header)
- n += headlen;
+ /* if it's in the form of an IP address then get the lib to interpret it */
+ if (is_ipaddress(str)) {
+ res = inet_addr(str);
+ } else {
+ /* otherwise assume it's a network name of some sort and use
+ sys_gethostbyname */
+ if ((hp = sys_gethostbyname(str)) == 0) {
+ DEBUG(3,("sys_gethostbyname: Unknown host. %s\n",str));
+ return 0;
+ }
+ if(hp->h_addr == NULL) {
+ DEBUG(3,("sys_gethostbyname: host address is invalid for host %s\n",str));
+ return 0;
+ }
+ putip((char *)&res,(char *)hp->h_addr);
+ }
- while (n > 0)
- {
- int s = MIN(n,size);
- int ret,ret2=0;
-
- ret = 0;
-
- if (header && (headlen >= MIN(s,1024))) {
- buf1 = header;
- s = headlen;
- ret = headlen;
- headlen = 0;
- header = NULL;
- } else {
- buf1 = abuf;
- }
+ if (res == (uint32)-1) return(0);
- if (header && headlen > 0)
- {
- ret = MIN(headlen,size);
- memcpy(buf1,header,ret);
- headlen -= ret;
- header += ret;
- if (headlen <= 0) header = NULL;
- }
+ return(res);
+}
- if (s > ret)
- ret += read(infd,buf1+ret,s-ret);
+/*******************************************************************
+ a convenient addition to interpret_addr()
+ ******************************************************************/
+struct in_addr *interpret_addr2(const char *str)
+{
+ static struct in_addr ret;
+ uint32 a = interpret_addr(str);
+ ret.s_addr = a;
+ return(&ret);
+}
- if (ret > 0)
- {
- ret2 = (outfd>=0?write_data(outfd,buf1,ret):ret);
- if (ret2 > 0) total += ret2;
- /* if we can't write then dump excess data */
- if (ret2 != ret)
- transfer_file(infd,-1,n-(ret+headlen),NULL,0,0);
- }
- if (ret <= 0 || ret2 != ret)
- return(total);
- n -= ret;
- }
- return(total);
+/*******************************************************************
+ check if an IP is the 0.0.0.0
+ ******************************************************************/
+BOOL is_zero_ip(struct in_addr ip)
+{
+ uint32 a;
+ putip((char *)&a,(char *)&ip);
+ return(a == 0);
}
+/* Set an IP to 0.0.0.0 */
-/****************************************************************************
-read 4 bytes of a smb packet and return the smb length of the packet
-possibly store the result in the buffer
-****************************************************************************/
-int read_smb_length(int fd,char *inbuf,int timeout)
+void zero_ip(struct in_addr *ip)
{
- char *buffer;
- char buf[4];
- int len=0, msg_type;
- BOOL ok=False;
+ static BOOL init;
+ static struct in_addr ipzero;
- if (inbuf)
- buffer = inbuf;
- else
- buffer = buf;
+ if (!init) {
+ ipzero = *interpret_addr2("0.0.0.0");
+ init = True;
+ }
- while (!ok)
- {
- if (timeout > 0)
- ok = (read_with_timeout(fd,buffer,4,4,timeout,False) == 4);
- else
- ok = (read_data(fd,buffer,4) == 4);
+ *ip = ipzero;
+}
- if (!ok)
- {
- if (timeout>0)
- {
- DEBUG(10,("select timeout (%d)\n", timeout));
- return(-1);
- }
- else
- {
- DEBUG(6,("couldn't read from client\n"));
- exit(1);
- }
- }
+#if (defined(HAVE_NETGROUP) && defined(WITH_AUTOMOUNT))
+/******************************************************************
+ Remove any mount options such as -rsize=2048,wsize=2048 etc.
+ Based on a fix from <Thomas.Hepper@icem.de>.
+*******************************************************************/
- len = smb_len(buffer);
- msg_type = CVAL(buffer,0);
+static void strip_mount_options( pstring *str)
+{
+ if (**str == '-')
+ {
+ char *p = *str;
+ while(*p && !isspace(*p))
+ p++;
+ while(*p && isspace(*p))
+ p++;
+ if(*p) {
+ pstring tmp_str;
- if (msg_type == 0x85)
- {
- DEBUG(5,( "Got keepalive packet\n"));
- ok = False;
- }
+ pstrcpy(tmp_str, p);
+ pstrcpy(*str, tmp_str);
}
-
- DEBUG(10,("got smb length of %d\n",len));
-
- return(len);
+ }
}
+/*******************************************************************
+ Patch from jkf@soton.ac.uk
+ Split Luke's automount_server into YP lookup and string splitter
+ so can easily implement automount_path().
+ As we may end up doing both, cache the last YP result.
+*******************************************************************/
-
-/****************************************************************************
- read an smb from a fd and return it's length
-The timeout is in milli seconds
-****************************************************************************/
-BOOL receive_smb(int fd,char *buffer,int timeout)
+#ifdef WITH_NISPLUS_HOME
+char *automount_lookup(const char *user_name)
{
- int len;
- BOOL ok;
-
- bzero(buffer,smb_size + 100);
-
- len = read_smb_length(fd,buffer,timeout);
- if (len == -1)
- return(False);
-
- if (len > BUFFER_SIZE)
+ static fstring last_key = "";
+ static pstring last_value = "";
+
+ char *nis_map = (char *)lp_nis_home_map_name();
+
+ char buffer[NIS_MAXATTRVAL + 1];
+ nis_result *result;
+ nis_object *object;
+ entry_obj *entry;
+
+ if (strcmp(user_name, last_key))
+ {
+ slprintf(buffer, sizeof(buffer)-1, "[key=%s],%s", user_name, nis_map);
+ DEBUG(5, ("NIS+ querystring: %s\n", buffer));
+
+ if (result = nis_list(buffer, FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP, NULL, NULL))
{
- DEBUG(0,("Invalid packet length! (%d bytes)\n",len));
- if (len > BUFFER_SIZE + (SAFETY_MARGIN/2))
- exit(1);
+ if (result->status != NIS_SUCCESS)
+ {
+ DEBUG(3, ("NIS+ query failed: %s\n", nis_sperrno(result->status)));
+ fstrcpy(last_key, ""); pstrcpy(last_value, "");
+ }
+ else
+ {
+ object = result->objects.objects_val;
+ if (object->zo_data.zo_type == ENTRY_OBJ)
+ {
+ entry = &object->zo_data.objdata_u.en_data;
+ DEBUG(5, ("NIS+ entry type: %s\n", entry->en_type));
+ DEBUG(3, ("NIS+ result: %s\n", entry->en_cols.en_cols_val[1].ec_value.ec_value_val));
+
+ pstrcpy(last_value, entry->en_cols.en_cols_val[1].ec_value.ec_value_val);
+ pstring_sub(last_value, "&", user_name);
+ fstrcpy(last_key, user_name);
+ }
+ }
}
+ nis_freeresult(result);
+ }
- ok = (read_data(fd,buffer+4,len) == len);
+ strip_mount_options(&last_value);
- if (!ok)
- {
- close_sockets();
- exit(1);
- }
-
- return(True);
+ DEBUG(4, ("NIS+ Lookup: %s resulted in %s\n", user_name, last_value));
+ return last_value;
}
+#else /* WITH_NISPLUS_HOME */
+char *automount_lookup(const char *user_name)
+{
+ static fstring last_key = "";
+ static pstring last_value = "";
+ int nis_error; /* returned by yp all functions */
+ char *nis_result; /* yp_match inits this */
+ int nis_result_len; /* and set this */
+ char *nis_domain; /* yp_get_default_domain inits this */
+ char *nis_map = (char *)lp_nis_home_map_name();
-/****************************************************************************
- send an smb to a fd
-****************************************************************************/
-BOOL send_smb(int fd,char *buffer)
-{
- int len;
- int ret,nwritten=0;
- len = smb_len(buffer) + 4;
+ if ((nis_error = yp_get_default_domain(&nis_domain)) != 0) {
+ DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error)));
+ return last_value;
+ }
- while (nwritten < len)
- {
- ret = write_socket(fd,buffer+nwritten,len - nwritten);
- if (ret <= 0)
- {
- DEBUG(0,("Error writing %d bytes to client. %d. Exiting\n",len,ret));
- close_sockets();
- exit(1);
- }
- nwritten += ret;
+ DEBUG(5, ("NIS Domain: %s\n", nis_domain));
+
+ if (!strcmp(user_name, last_key)) {
+ nis_result = last_value;
+ nis_result_len = strlen(last_value);
+ nis_error = 0;
+
+ } else {
+
+ if ((nis_error = yp_match(nis_domain, nis_map,
+ user_name, strlen(user_name),
+ &nis_result, &nis_result_len)) == 0) {
+ if (!nis_error && nis_result_len >= sizeof(pstring)) {
+ nis_result_len = sizeof(pstring)-1;
+ }
+ fstrcpy(last_key, user_name);
+ strncpy(last_value, nis_result, nis_result_len);
+ last_value[nis_result_len] = '\0';
+ strip_mount_options(&last_value);
+
+ } else if(nis_error == YPERR_KEY) {
+
+ /* If Key lookup fails user home server is not in nis_map
+ use default information for server, and home directory */
+ last_value[0] = 0;
+ DEBUG(3, ("YP Key not found: while looking up \"%s\" in map \"%s\"\n",
+ user_name, nis_map));
+ DEBUG(3, ("using defaults for server and home directory\n"));
+ } else {
+ DEBUG(3, ("YP Error: \"%s\" while looking up \"%s\" in map \"%s\"\n",
+ yperr_string(nis_error), user_name, nis_map));
}
+ }
- return True;
+ DEBUG(4, ("YP Lookup: %s resulted in %s\n", user_name, last_value));
+ return last_value;
}
+#endif /* WITH_NISPLUS_HOME */
+#endif
-/****************************************************************************
-find a pointer to a netbios name
-****************************************************************************/
-char *name_ptr(char *buf,int ofs)
+/*******************************************************************
+are two IPs on the same subnet?
+********************************************************************/
+BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask)
{
- unsigned char c = *(unsigned char *)(buf+ofs);
+ uint32 net1,net2,nmask;
- if ((c & 0xC0) == 0xC0)
- {
- uint16 l;
- char p[2];
- memcpy(p,buf+ofs,2);
- p[0] &= ~0xC0;
- l = RSVAL(p,0);
- DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l));
- return(buf + l);
- }
- else
- return(buf+ofs);
-}
+ nmask = ntohl(mask.s_addr);
+ net1 = ntohl(ip1.s_addr);
+ net2 = ntohl(ip2.s_addr);
+
+ return((net1 & nmask) == (net2 & nmask));
+}
-/****************************************************************************
-extract a netbios name from a buf
-****************************************************************************/
-int name_extract(char *buf,int ofs,char *name)
-{
- char *p = name_ptr(buf,ofs);
- int d = PTR_DIFF(p,buf+ofs);
- strcpy(name,"");
- if (d < -50 || d > 50) return(0);
- return(name_interpret(p,name));
-}
-
/****************************************************************************
-return the total storage length of a mangled name
+check if a process exists. Does this work on all unixes?
****************************************************************************/
-int name_len(char *s)
-{
- char *s0=s;
- unsigned char c = *(unsigned char *)s;
- if ((c & 0xC0) == 0xC0)
- return(2);
- while (*s) s += (*s)+1;
- return(PTR_DIFF(s,s0)+1);
-}
-/****************************************************************************
-send a single packet to a port on another machine
-****************************************************************************/
-BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type)
+BOOL process_exists(pid_t pid)
{
- BOOL ret;
- int out_fd;
- struct sockaddr_in sock_out;
+ /* Doing kill with a non-positive pid causes messages to be
+ * sent to places we don't want. */
+ SMB_ASSERT(pid > 0);
+ return(kill(pid,0) == 0 || errno != ESRCH);
+}
- if (passive)
- return(True);
- /* create a socket to write to */
- out_fd = socket(AF_INET, type, 0);
- if (out_fd == -1)
- {
- DEBUG(0,("socket failed"));
- return False;
- }
-
- /* set the address and port */
- bzero((char *)&sock_out,sizeof(sock_out));
- putip((char *)&sock_out.sin_addr,(char *)&ip);
- sock_out.sin_port = htons( port );
- sock_out.sin_family = AF_INET;
-
- if (DEBUGLEVEL > 0)
- DEBUG(3,("sending a packet of len %d to (%s) on port %d of type %s\n",
- len,inet_ntoa(ip),port,type==SOCK_DGRAM?"DGRAM":"STREAM"));
-
- /* send it */
- ret = (sendto(out_fd,buf,len,0,(struct sockaddr *)&sock_out,sizeof(sock_out)) >= 0);
+/*******************************************************************
+ Convert a uid into a user name.
+********************************************************************/
- if (!ret)
- DEBUG(0,("Packet send to %s(%d) failed ERRNO=%d\n",
- inet_ntoa(ip),port,errno));
+char *uidtoname(uid_t uid)
+{
+ static fstring name;
+ struct passwd *pass;
- close(out_fd);
- return(ret);
+ pass = sys_getpwuid(uid);
+ if (pass) return(pass->pw_name);
+ slprintf(name, sizeof(name) - 1, "%d",(int)uid);
+ return(name);
}
+
/*******************************************************************
-sleep for a specified number of milliseconds
+ Convert a gid into a group name.
********************************************************************/
-void msleep(int t)
-{
- int tdiff=0;
- struct timeval tval,t1,t2;
- fd_set fds;
- GetTimeOfDay(&t1);
- GetTimeOfDay(&t2);
-
- while (tdiff < t) {
- tval.tv_sec = (t-tdiff)/1000;
- tval.tv_usec = 1000*((t-tdiff)%1000);
-
- FD_ZERO(&fds);
- errno = 0;
- sys_select(&fds,&tval);
+char *gidtoname(gid_t gid)
+{
+ static fstring name;
+ struct group *grp;
- GetTimeOfDay(&t2);
- tdiff = TvalDiff(&t1,&t2);
- }
+ grp = getgrgid(gid);
+ if (grp) return(grp->gr_name);
+ slprintf(name,sizeof(name) - 1, "%d",(int)gid);
+ return(name);
}
-/****************************************************************************
-check if a string is part of a list
-****************************************************************************/
-BOOL in_list(char *s,char *list,BOOL casesensitive)
+/*******************************************************************
+ Convert a user name into a uid. If winbindd is present uses this.
+********************************************************************/
+
+uid_t nametouid(char *name)
{
- pstring tok;
- char *p=list;
+ struct passwd *pass;
+ char *p;
+ uid_t u;
- if (!list) return(False);
+ u = (uid_t)strtol(name, &p, 0);
+ if ((p != name) && (*p == '\0'))
+ return u;
- while (next_token(&p,tok,LIST_SEP))
- {
- if (casesensitive) {
- if (strcmp(tok,s) == 0)
- return(True);
- } else {
- if (StrCaseCmp(tok,s) == 0)
- return(True);
- }
- }
- return(False);
+ pass = getpwnam_alloc(name);
+ if (pass) {
+ return(pass->pw_uid);
+ passwd_free(&pass);
+ }
+ return (uid_t)-1;
}
-/* this is used to prevent lots of mallocs of size 1 */
-static char *null_string = NULL;
+/*******************************************************************
+ Convert a name to a gid_t if possible. Return -1 if not a group. If winbindd
+ is present does a shortcut lookup...
+********************************************************************/
-/****************************************************************************
-set a string value, allocing the space for the string
-****************************************************************************/
-BOOL string_init(char **dest,char *src)
+gid_t nametogid(const char *name)
{
- int l;
- if (!src)
- src = "";
+ struct group *grp;
+ char *p;
+ gid_t g;
- l = strlen(src);
+ g = (gid_t)strtol(name, &p, 0);
+ if ((p != name) && (*p == '\0'))
+ return g;
- if (l == 0)
- {
- if (!null_string)
- null_string = (char *)malloc(1);
-
- *null_string = 0;
- *dest = null_string;
- }
- else
- {
- *dest = (char *)malloc(l+1);
- strcpy(*dest,src);
- }
- return(True);
+ grp = getgrnam(name);
+ if (grp)
+ return(grp->gr_gid);
+ return (gid_t)-1;
}
-/****************************************************************************
-free a string value
-****************************************************************************/
-void string_free(char **s)
+/*******************************************************************
+something really nasty happened - panic!
+********************************************************************/
+void smb_panic(char *why)
{
- if (!s || !(*s)) return;
- if (*s == null_string)
- *s = NULL;
- if (*s) free(*s);
- *s = NULL;
+ char *cmd = lp_panic_action();
+ if (cmd && *cmd) {
+ system(cmd);
+ }
+ DEBUG(0,("PANIC: %s\n", why));
+ dbgflush();
+ abort();
}
-/****************************************************************************
-set a string value, allocing the space for the string, and deallocating any
-existing space
-****************************************************************************/
-BOOL string_set(char **dest,char *src)
-{
- string_free(dest);
-
- return(string_init(dest,src));
-}
-/****************************************************************************
-substitute a string for a pattern in another string. Make sure there is
-enough room!
+/*******************************************************************
+a readdir wrapper which just returns the file name
+********************************************************************/
+char *readdirname(DIR *p)
+{
+ SMB_STRUCT_DIRENT *ptr;
+ char *dname;
-This routine looks for pattern in s and replaces it with
-insert. It may do multiple replacements.
+ if (!p) return(NULL);
+
+ ptr = (SMB_STRUCT_DIRENT *)sys_readdir(p);
+ if (!ptr) return(NULL);
-return True if a substitution was done.
-****************************************************************************/
-BOOL string_sub(char *s,char *pattern,char *insert)
-{
- BOOL ret = False;
- char *p;
- int ls,lp,li;
+ dname = ptr->d_name;
- if (!insert || !pattern || !s) return(False);
+#ifdef NEXT2
+ if (telldir(p) < 0) return(NULL);
+#endif
- ls = strlen(s);
- lp = strlen(pattern);
- li = strlen(insert);
+#ifdef HAVE_BROKEN_READDIR
+ /* using /usr/ucb/cc is BAD */
+ dname = dname - 2;
+#endif
- if (!*pattern) return(False);
+ {
+ static pstring buf;
+ int len = NAMLEN(ptr);
+ memcpy(buf, dname, len);
+ buf[len] = 0;
+ dname = buf;
+ }
- while (lp <= ls && (p = strstr(s,pattern)))
- {
- ret = True;
- memmove(p+li,p+lp,ls + 1 - (PTR_DIFF(p,s) + lp));
- memcpy(p,insert,li);
- s = p + li;
- ls = strlen(s);
- }
- return(ret);
+ return(dname);
}
+/*******************************************************************
+ Utility function used to decide if the last component
+ of a path matches a (possibly wildcarded) entry in a namelist.
+********************************************************************/
-
-/*********************************************************
-* Recursive routine that is called by mask_match.
-* Does the actual matching.
-*********************************************************/
-BOOL do_match(char *str, char *regexp, int case_sig)
+BOOL is_in_path(char *name, name_compare_entry *namelist)
{
+ pstring last_component;
char *p;
- for( p = regexp; *p && *str; ) {
- switch(*p) {
- case '?':
- str++; p++;
- break;
+ DEBUG(8, ("is_in_path: %s\n", name));
- case '*':
- /* Look for a character matching
- the one after the '*' */
- p++;
- if(!*p)
- return True; /* Automatic match */
- while(*str) {
- while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str))))
- str++;
- if(do_match(str,p,case_sig))
- return True;
- if(!*str)
- return False;
- else
- str++;
- }
- return False;
-
- default:
- if(case_sig) {
- if(*str != *p)
- return False;
- } else {
- if(toupper(*str) != toupper(*p))
- return False;
- }
- str++, p++;
- break;
- }
+ /* if we have no list it's obviously not in the path */
+ if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL)))
+ {
+ DEBUG(8,("is_in_path: no name list.\n"));
+ return False;
}
- if(!*p && !*str)
- return True;
- if (!*p && str[0] == '.' && str[1] == 0)
- return(True);
-
- if (!*str && *p == '?')
+ /* Get the last component of the unix name. */
+ p = strrchr_m(name, '/');
+ strncpy(last_component, p ? ++p : name, sizeof(last_component)-1);
+ last_component[sizeof(last_component)-1] = '\0';
+
+ for(; namelist->name != NULL; namelist++)
+ {
+ if(namelist->is_wild)
{
- while (*p == '?') p++;
- return(!*p);
+ if (mask_match(last_component, namelist->name, case_sensitive))
+ {
+ DEBUG(8,("is_in_path: mask match succeeded\n"));
+ return True;
+ }
}
-
- if(!*str && (*p == '*' && p[1] == '\0'))
- return True;
+ else
+ {
+ if((case_sensitive && (strcmp(last_component, namelist->name) == 0))||
+ (!case_sensitive && (StrCaseCmp(last_component, namelist->name) == 0)))
+ {
+ DEBUG(8,("is_in_path: match succeeded\n"));
+ return True;
+ }
+ }
+ }
+ DEBUG(8,("is_in_path: match not found\n"));
+
return False;
}
-
-/*********************************************************
-* Routine to match a given string with a regexp - uses
-* simplified regexp that takes * and ? only. Case can be
-* significant or not.
-*********************************************************/
-BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
+/*******************************************************************
+ Strip a '/' separated list into an array of
+ name_compare_enties structures suitable for
+ passing to is_in_path(). We do this for
+ speed so we can pre-parse all the names in the list
+ and don't do it for each call to is_in_path().
+ namelist is modified here and is assumed to be
+ a copy owned by the caller.
+ We also check if the entry contains a wildcard to
+ remove a potentially expensive call to mask_match
+ if possible.
+********************************************************************/
+
+void set_namearray(name_compare_entry **ppname_array, char *namelist)
{
- char *p;
- pstring p1, p2;
- fstring ebase,eext,sbase,sext;
-
- BOOL matched;
-
- /* Make local copies of str and regexp */
- StrnCpy(p1,regexp,sizeof(pstring)-1);
- StrnCpy(p2,str,sizeof(pstring)-1);
+ char *name_end;
+ char *nameptr = namelist;
+ int num_entries = 0;
+ int i;
- if (!strchr(p2,'.')) {
- strcat(p2,".");
- }
+ (*ppname_array) = NULL;
-/*
- if (!strchr(p1,'.')) {
- strcat(p1,".");
- }
-*/
+ if((nameptr == NULL ) || ((nameptr != NULL) && (*nameptr == '\0')))
+ return;
-#if 0
- if (strchr(p1,'.'))
+ /* We need to make two passes over the string. The
+ first to count the number of elements, the second
+ to split it.
+ */
+ while(*nameptr)
{
- string_sub(p1,"*.*","*");
- string_sub(p1,".*","*");
- }
-#endif
-
- /* Remove any *? and ** as they are meaningless */
- for(p = p1; *p; p++)
- while( *p == '*' && (p[1] == '?' ||p[1] == '*'))
- (void)strcpy( &p[1], &p[2]);
-
- if (strequal(p1,"*")) return(True);
+ if ( *nameptr == '/' )
+ {
+ /* cope with multiple (useless) /s) */
+ nameptr++;
+ continue;
+ }
+ /* find the next / */
+ name_end = strchr_m(nameptr, '/');
- DEBUG(5,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
+ /* oops - the last check for a / didn't find one. */
+ if (name_end == NULL)
+ break;
- if (trans2) {
- strcpy(ebase,p1);
- strcpy(sbase,p2);
- } else {
- if ((p=strrchr(p1,'.'))) {
- *p = 0;
- strcpy(ebase,p1);
- strcpy(eext,p+1);
- } else {
- strcpy(ebase,p1);
- eext[0] = 0;
+ /* next segment please */
+ nameptr = name_end + 1;
+ num_entries++;
}
- if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) {
- *p = 0;
- strcpy(sbase,p2);
- strcpy(sext,p+1);
- } else {
- strcpy(sbase,p2);
- strcpy(sext,"");
- }
- }
+ if(num_entries == 0)
+ return;
- matched = do_match(sbase,ebase,case_sig) &&
- (trans2 || do_match(sext,eext,case_sig));
+ if(( (*ppname_array) = (name_compare_entry *)malloc(
+ (num_entries + 1) * sizeof(name_compare_entry))) == NULL)
+ {
+ DEBUG(0,("set_namearray: malloc fail\n"));
+ return;
+ }
+
+ /* Now copy out the names */
+ nameptr = namelist;
+ i = 0;
+ while(*nameptr)
+ {
+ if ( *nameptr == '/' )
+ {
+ /* cope with multiple (useless) /s) */
+ nameptr++;
+ continue;
+ }
+ /* find the next / */
+ if ((name_end = strchr_m(nameptr, '/')) != NULL)
+ {
+ *name_end = 0;
+ }
- DEBUG(5,("mask_match returning %d\n", matched));
+ /* oops - the last check for a / didn't find one. */
+ if(name_end == NULL)
+ break;
- return matched;
-}
+ (*ppname_array)[i].is_wild = ms_has_wild(nameptr);
+ if(((*ppname_array)[i].name = strdup(nameptr)) == NULL)
+ {
+ DEBUG(0,("set_namearray: malloc fail (1)\n"));
+ return;
+ }
+ /* next segment please */
+ nameptr = name_end + 1;
+ i++;
+ }
+
+ (*ppname_array)[i].name = NULL;
+ return;
+}
/****************************************************************************
-become a daemon, discarding the controlling terminal
+routine to free a namearray.
****************************************************************************/
-void become_daemon(void)
+
+void free_namearray(name_compare_entry *name_array)
{
-#ifndef NO_FORK_DEBUG
- if (fork())
- exit(0);
+ if(name_array == NULL)
+ return;
- /* detach from the terminal */
-#ifdef USE_SETSID
- setsid();
-#else
-#ifdef TIOCNOTTY
- {
- int i = open("/dev/tty", O_RDWR);
- if (i >= 0)
- {
- ioctl(i, (int) TIOCNOTTY, (char *)0);
- close(i);
- }
- }
-#endif
-#endif
-#endif
+ SAFE_FREE(name_array->name);
+ SAFE_FREE(name_array);
}
/****************************************************************************
-calculate the default netmask for an address
+ Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping
+ is dealt with in posix.c
****************************************************************************/
-static void default_netmask(struct in_addr *inm, struct in_addr *iad)
-{
- unsigned long ad = ntohl(iad->s_addr);
- unsigned long nm;
- /*
- ** Guess a netmask based on the class of the IP address given.
- */
- if ( (ad & 0x80000000) == 0 ) {
- /* class A address */
- nm = 0xFF000000;
- } else if ( (ad & 0xC0000000) == 0x80000000 ) {
- /* class B address */
- nm = 0xFFFF0000;
- } else if ( (ad & 0xE0000000) == 0xC0000000 ) {
- /* class C address */
- nm = 0xFFFFFF00;
- } else {
- /* class D or E; netmask doesn't make much sense - guess 4 bits */
- nm = 0xFFFFFFF0;
- }
- inm->s_addr = htonl(nm);
-}
-/****************************************************************************
- get the broadcast address for our address
-(troyer@saifr00.ateng.az.honeywell.com)
-****************************************************************************/
-void get_broadcast(struct in_addr *if_ipaddr,
- struct in_addr *if_bcast,
- struct in_addr *if_nmask)
-{
- BOOL found = False;
-#ifndef NO_GET_BROADCAST
- int sock = -1; /* AF_INET raw socket desc */
- char buff[1024];
- struct ifreq *ifr=NULL;
- int i;
+BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
+{
+ SMB_STRUCT_FLOCK lock;
+ int ret;
-#if defined(EVEREST)
- int n_interfaces;
- struct ifconf ifc;
- struct ifreq *ifreqs;
-#elif defined(USE_IFREQ)
- struct ifreq ifreq;
- struct strioctl strioctl;
- struct ifconf *ifc;
-#else
- struct ifconf ifc;
-#endif
-#endif
+ DEBUG(8,("fcntl_lock %d %d %.0f %.0f %d\n",fd,op,(double)offset,(double)count,type));
- /* get a default netmask and broadcast */
- default_netmask(if_nmask, if_ipaddr);
+ lock.l_type = type;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = offset;
+ lock.l_len = count;
+ lock.l_pid = 0;
-#ifndef NO_GET_BROADCAST
- /* Create a socket to the INET kernel. */
-#if USE_SOCKRAW
- if ((sock = socket(AF_INET, SOCK_RAW, PF_INET )) < 0)
-#else
- if ((sock = socket(AF_INET, SOCK_DGRAM, 0 )) < 0)
-#endif
- {
- DEBUG(0,( "Unable to open socket to get broadcast address\n"));
- return;
- }
-
- /* Get a list of the configured interfaces */
-#ifdef EVEREST
- /* This is part of SCO Openserver 5: The ioctls are no longer part
- if the lower level STREAMS interface glue. They are now real
- ioctl calls */
-
- if (ioctl(sock, SIOCGIFANUM, &n_interfaces) < 0) {
- DEBUG(0,( "SIOCGIFANUM: %s\n", strerror(errno)));
- } else {
- DEBUG(0,( "number of interfaces returned is: %d\n", n_interfaces));
+ errno = 0;
- ifc.ifc_len = sizeof(struct ifreq) * n_interfaces;
- ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len);
+ ret = fcntl(fd,op,&lock);
- if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
- DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno)));
- else {
- ifr = ifc.ifc_req;
+ if (errno != 0)
+ DEBUG(3,("fcntl_lock: fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
- for (i = 0; i < n_interfaces; ++i) {
- if (if_ipaddr->s_addr ==
- ((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr.s_addr) {
- found = True;
- break;
- }
- }
- }
- }
-#elif defined(USE_IFREQ)
- ifc = (struct ifconf *)buff;
- ifc->ifc_len = BUFSIZ - sizeof(struct ifconf);
- strioctl.ic_cmd = SIOCGIFCONF;
- strioctl.ic_dp = (char *)ifc;
- strioctl.ic_len = sizeof(buff);
- if (ioctl(sock, I_STR, &strioctl) < 0) {
- DEBUG(0,( "I_STR/SIOCGIFCONF: %s\n", strerror(errno)));
- } else {
- ifr = (struct ifreq *)ifc->ifc_req;
-
- /* Loop through interfaces, looking for given IP address */
- for (i = ifc->ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
- if (if_ipaddr->s_addr ==
- (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
- found = True;
- break;
- }
- }
- }
-#elif defined(__FreeBSD__) || defined(NETBSD)
- ifc.ifc_len = sizeof(buff);
- ifc.ifc_buf = buff;
- if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
- DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
- } else {
- ifr = ifc.ifc_req;
- /* Loop through interfaces, looking for given IP address */
- i = ifc.ifc_len;
- while (i > 0) {
- if (if_ipaddr->s_addr ==
- (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
- found = True;
- break;
- }
- i -= ifr->ifr_addr.sa_len + IFNAMSIZ;
- ifr = (struct ifreq*) ((char*) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ);
- }
- }
-#else
- ifc.ifc_len = sizeof(buff);
- ifc.ifc_buf = buff;
- if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
- DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
- } else {
- ifr = ifc.ifc_req;
-
- /* Loop through interfaces, looking for given IP address */
- for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
-#ifdef BSDI
- if (ioctl(sock, SIOCGIFADDR, ifr) < 0) break;
-#endif
- if (if_ipaddr->s_addr ==
- (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
- found = True;
- break;
- }
+ /* a lock query */
+ if (op == SMB_F_GETLK)
+ {
+ if ((ret != -1) &&
+ (lock.l_type != F_UNLCK) &&
+ (lock.l_pid != 0) &&
+ (lock.l_pid != sys_getpid()))
+ {
+ DEBUG(3,("fcntl_lock: fd %d is locked by pid %d\n",fd,(int)lock.l_pid));
+ return(True);
}
- }
-#endif
-
- if (!found) {
- DEBUG(0,("No interface found for address %s\n", inet_ntoa(*if_ipaddr)));
- } else {
- /* Get the netmask address from the kernel */
-#ifdef USE_IFREQ
- ifreq = *ifr;
-
- strioctl.ic_cmd = SIOCGIFNETMASK;
- strioctl.ic_dp = (char *)&ifreq;
- strioctl.ic_len = sizeof(struct ifreq);
- if (ioctl(sock, I_STR, &strioctl) < 0)
- DEBUG(0,("Failed I_STR/SIOCGIFNETMASK: %s\n", strerror(errno)));
- else
- *if_nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
-#else
- if (ioctl(sock, SIOCGIFNETMASK, ifr) < 0)
- DEBUG(0,("SIOCGIFNETMASK failed\n"));
- else
- *if_nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
-#endif
- DEBUG(2,("Netmask for %s = %s\n", ifr->ifr_name,
- inet_ntoa(*if_nmask)));
+ /* it must be not locked or locked by me */
+ return(False);
}
- /* Close up shop */
- (void) close(sock);
-
-#endif
-
- /* sanity check on the netmask */
+ /* a lock set or unset */
+ if (ret == -1)
{
- unsigned long nm = ntohl(if_nmask->s_addr);
- if ((nm >> 24) != 0xFF) {
- DEBUG(0,("Impossible netmask %s - using defaults\n",inet_ntoa(*if_nmask)));
- default_netmask(if_nmask, if_ipaddr);
- }
+ DEBUG(3,("fcntl_lock: lock failed at offset %.0f count %.0f op %d type %d (%s)\n",
+ (double)offset,(double)count,op,type,strerror(errno)));
+ return(False);
}
- /* derive the broadcast assuming a 1's broadcast, as this is what
- all MS operating systems do, we have to comply even if the unix
- box is setup differently */
- {
- unsigned long ad = ntohl(if_ipaddr->s_addr);
- unsigned long nm = ntohl(if_nmask->s_addr);
- unsigned long bc = (ad & nm) | (0xffffffff & ~nm);
- if_bcast->s_addr = htonl(bc);
- }
-
- DEBUG(2,("Derived broadcast address %s\n", inet_ntoa(*if_bcast)));
-} /* get_broadcast */
+ /* everything went OK */
+ DEBUG(8,("fcntl_lock: Lock call successful\n"));
+ return(True);
+}
-/****************************************************************************
-put up a yes/no prompt
-****************************************************************************/
-BOOL yesno(char *p)
+/*******************************************************************
+is the name specified one of my netbios names
+returns true is it is equal, false otherwise
+********************************************************************/
+BOOL is_myname(char *s)
{
- pstring ans;
- printf("%s",p);
-
- if (!fgets(ans,sizeof(ans)-1,stdin))
- return(False);
-
- if (*ans == 'y' || *ans == 'Y')
- return(True);
+ int n;
+ BOOL ret = False;
- return(False);
+ for (n=0; my_netbios_names[n]; n++) {
+ if (strequal(my_netbios_names[n], s))
+ ret=True;
+ }
+ DEBUG(8, ("is_myname(\"%s\") returns %d\n", s, ret));
+ return(ret);
}
-/****************************************************************************
-read a line from a file with possible \ continuation chars.
-Blanks at the start or end of a line are stripped.
-The string will be allocated if s2 is NULL
-****************************************************************************/
-char *fgets_slash(char *s2,int maxlen,FILE *f)
+BOOL is_myname_or_ipaddr(char *s)
{
- char *s=s2;
- int len = 0;
- int c;
- BOOL start_of_line = True;
-
- if (feof(f))
- return(NULL);
-
- if (!s2)
- {
- maxlen = MIN(maxlen,8);
- s = (char *)Realloc(s,maxlen);
- }
-
- if (!s || maxlen < 2) return(NULL);
-
- *s = 0;
+ char **ptr;
+
+ /* optimize for the common case */
+ if (strequal(s, global_myname))
+ return True;
- while (len < maxlen-1)
- {
- c = getc(f);
- switch (c)
+ /* maybe its an IP address? */
+ if (is_ipaddress(s))
{
- case '\r':
- break;
- case '\n':
- while (len > 0 && s[len-1] == ' ')
- {
- s[--len] = 0;
- }
- if (len > 0 && s[len-1] == '\\')
- {
- s[--len] = 0;
- start_of_line = True;
- break;
- }
- return(s);
- case EOF:
- if (len <= 0 && !s2)
- free(s);
- return(len>0?s:NULL);
- case ' ':
- if (start_of_line)
- break;
- default:
- start_of_line = False;
- s[len++] = c;
- s[len] = 0;
- }
- if (!s2 && len > maxlen-3)
+ struct iface_struct nics[MAX_INTERFACES];
+ int i, n;
+ uint32 ip;
+
+ ip = interpret_addr(s);
+ if ((ip==0) || (ip==0xffffffff))
+ return False;
+
+ n = get_interfaces(nics, MAX_INTERFACES);
+ for (i=0; i<n; i++) {
+ if (ip == nics[i].ip.s_addr)
+ return True;
+ }
+ }
+
+ /* check for an alias */
+ ptr = lp_netbios_aliases();
+ for ( ; *ptr; ptr++ )
{
- maxlen *= 2;
- s = (char *)Realloc(s,maxlen);
- if (!s) return(NULL);
+ if (StrCaseCmp(s, *ptr) == 0)
+ return True;
}
- }
- return(s);
-}
-
-
-
-/****************************************************************************
-set the length of a file from a filedescriptor.
-Returns 0 on success, -1 on failure.
-****************************************************************************/
-int set_filelen(int fd, long len)
-{
-/* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
- extend a file with ftruncate. Provide alternate implementation
- for this */
-
-#if FTRUNCATE_CAN_EXTEND
- return ftruncate(fd, len);
-#else
- struct stat st;
- char c = 0;
- long currpos = lseek(fd, 0L, SEEK_CUR);
-
- if(currpos < 0)
- return -1;
- /* Do an fstat to see if the file is longer than
- the requested size (call ftruncate),
- or shorter, in which case seek to len - 1 and write 1
- byte of zero */
- if(fstat(fd, &st)<0)
- return -1;
-
-#ifdef S_ISFIFO
- if (S_ISFIFO(st.st_mode)) return 0;
-#endif
+
+
+ /* no match */
+ return False;
- if(st.st_size == len)
- return 0;
- if(st.st_size > len)
- return ftruncate(fd, len);
-
- if(lseek(fd, len-1, SEEK_SET) != len -1)
- return -1;
- if(write(fd, &c, 1)!=1)
- return -1;
- /* Seek to where we were */
- lseek(fd, currpos, SEEK_SET);
- return 0;
-#endif
}
-/****************************************************************************
-return the byte checksum of some data
-****************************************************************************/
-int byte_checksum(char *buf,int len)
+/*******************************************************************
+set the horrid remote_arch string based on an enum.
+********************************************************************/
+void set_remote_arch(enum remote_arch_types type)
{
- unsigned char *p = (unsigned char *)buf;
- int ret = 0;
- while (len--)
- ret += *p++;
- return(ret);
+ extern fstring remote_arch;
+ ra_type = type;
+ switch( type )
+ {
+ case RA_WFWG:
+ fstrcpy(remote_arch, "WfWg");
+ return;
+ case RA_OS2:
+ fstrcpy(remote_arch, "OS2");
+ return;
+ case RA_WIN95:
+ fstrcpy(remote_arch, "Win95");
+ return;
+ case RA_WINNT:
+ fstrcpy(remote_arch, "WinNT");
+ return;
+ case RA_WIN2K:
+ fstrcpy(remote_arch, "Win2K");
+ return;
+ case RA_SAMBA:
+ fstrcpy(remote_arch,"Samba");
+ return;
+ default:
+ ra_type = RA_UNKNOWN;
+ fstrcpy(remote_arch, "UNKNOWN");
+ break;
+ }
}
-
-
-#ifdef HPUX
-/****************************************************************************
-this is a version of setbuffer() for those machines that only have setvbuf
-****************************************************************************/
-void setbuffer(FILE *f,char *buf,int bufsize)
+/*******************************************************************
+ Get the remote_arch type.
+********************************************************************/
+enum remote_arch_types get_remote_arch(void)
{
- setvbuf(f,buf,_IOFBF,bufsize);
+ return ra_type;
}
-#endif
-/****************************************************************************
-parse out a directory name from a path name. Assumes dos style filenames.
-****************************************************************************/
-char *dirname_dos(char *path,char *buf)
+void out_ascii(FILE *f, unsigned char *buf,int len)
{
- char *p = strrchr(path,'\\');
-
- if (!p)
- strcpy(buf,path);
- else
- {
- *p = 0;
- strcpy(buf,path);
- *p = '\\';
- }
-
- return(buf);
+ int i;
+ for (i=0;i<len;i++)
+ {
+ fprintf(f, "%c", isprint(buf[i])?buf[i]:'.');
+ }
}
-
-/****************************************************************************
-parse out a filename from a path name. Assumes dos style filenames.
-****************************************************************************/
-static char *filename_dos(char *path,char *buf)
+void out_data(FILE *f,char *buf1,int len, int per_line)
{
- char *p = strrchr(path,'\\');
-
- if (!p)
- strcpy(buf,path);
- else
- strcpy(buf,p+1);
+ unsigned char *buf = (unsigned char *)buf1;
+ int i=0;
+ if (len<=0)
+ {
+ return;
+ }
- return(buf);
+ fprintf(f, "[%03X] ",i);
+ for (i=0;i<len;)
+ {
+ fprintf(f, "%02X ",(int)buf[i]);
+ i++;
+ if (i%(per_line/2) == 0) fprintf(f, " ");
+ if (i%per_line == 0)
+ {
+ out_ascii(f,&buf[i-per_line ],per_line/2); fprintf(f, " ");
+ out_ascii(f,&buf[i-per_line/2],per_line/2); fprintf(f, "\n");
+ if (i<len) fprintf(f, "[%03X] ",i);
+ }
+ }
+ if ((i%per_line) != 0)
+ {
+ int n;
+
+ n = per_line - (i%per_line);
+ fprintf(f, " ");
+ if (n>(per_line/2)) fprintf(f, " ");
+ while (n--)
+ {
+ fprintf(f, " ");
+ }
+ n = MIN(per_line/2,i%per_line);
+ out_ascii(f,&buf[i-(i%per_line)],n); fprintf(f, " ");
+ n = (i%per_line) - n;
+ if (n>0) out_ascii(f,&buf[i-n],n);
+ fprintf(f, "\n");
+ }
}
-
-
-/****************************************************************************
-expand a pointer to be a particular size
-****************************************************************************/
-void *Realloc(void *p,int size)
+void print_asc(int level, const unsigned char *buf,int len)
{
- void *ret=NULL;
- if (!p)
- ret = (void *)malloc(size);
- else
- ret = (void *)realloc(p,size);
-
- if (!ret)
- DEBUG(0,("Memory allocation error: failed to expand to %d bytes\n",size));
-
- return(ret);
+ int i;
+ for (i=0;i<len;i++)
+ DEBUG(level,("%c", isprint(buf[i])?buf[i]:'.'));
}
-/****************************************************************************
-set the time on a file
-****************************************************************************/
-BOOL set_filetime(char *fname,time_t mtime)
-{
- struct utimbuf times;
-
- if (null_mtime(mtime)) return(True);
-
- times.modtime = times.actime = mtime;
+void dump_data(int level, const char *buf1,int len)
+{
+ const unsigned char *buf = (const unsigned char *)buf1;
+ int i=0;
+ if (len<=0) return;
- if (sys_utime(fname,&times)) {
- DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
+ DEBUG(level,("[%03X] ",i));
+ for (i=0;i<len;) {
+ DEBUG(level,("%02X ",(int)buf[i]));
+ i++;
+ if (i%8 == 0) DEBUG(level,(" "));
+ if (i%16 == 0) {
+ print_asc(level,&buf[i-16],8); DEBUG(level,(" "));
+ print_asc(level,&buf[i-8],8); DEBUG(level,("\n"));
+ if (i<len) DEBUG(level,("[%03X] ",i));
+ }
+ }
+ if (i%16) {
+ int n;
+
+ n = 16 - (i%16);
+ DEBUG(level,(" "));
+ if (n>8) DEBUG(level,(" "));
+ while (n--) DEBUG(level,(" "));
+
+ n = MIN(8,i%16);
+ print_asc(level,&buf[i-(i%16)],n); DEBUG(level,(" "));
+ n = (i%16) - n;
+ if (n>0) print_asc(level,&buf[i-n],n);
+ DEBUG(level,("\n"));
}
-
- return(True);
}
-
-#ifdef NOSTRDUP
-/****************************************************************************
-duplicate a string
-****************************************************************************/
-char *strdup(char *s)
+char *tab_depth(int depth)
{
- char *ret = NULL;
- if (!s) return(NULL);
- ret = (char *)malloc(strlen(s)+1);
- if (!ret) return(NULL);
- strcpy(ret,s);
- return(ret);
+ static pstring spaces;
+ memset(spaces, ' ', depth * 4);
+ spaces[depth * 4] = 0;
+ return spaces;
}
-#endif
-
-/****************************************************************************
- Signal handler for SIGPIPE (write on a disconnected socket)
-****************************************************************************/
-void Abort(void )
+/*****************************************************************************
+ * Provide a checksum on a string
+ *
+ * Input: s - the null-terminated character string for which the checksum
+ * will be calculated.
+ *
+ * Output: The checksum value calculated for s.
+ *
+ * ****************************************************************************
+ */
+int str_checksum(const char *s)
{
- DEBUG(0,("Probably got SIGPIPE\nExiting\n"));
- exit(2);
-}
-
+ int res = 0;
+ int c;
+ int i=0;
+
+ while(*s) {
+ c = *s;
+ res ^= (c << (i % 15)) ^ (c >> (15-(i%15)));
+ s++;
+ i++;
+ }
+ return(res);
+} /* str_checksum */
-#ifdef REPLACE_STRLEN
-/****************************************************************************
-a replacement strlen() that returns int for solaris
-****************************************************************************/
-int Strlen(char *s)
-{
- int ret=0;
- if (!s) return(0);
- while (*s++) ret++;
- return(ret);
-}
-#endif
-/****************************************************************************
-return a time at the start of the current month
-****************************************************************************/
-time_t start_of_month(void)
+/*****************************************************************
+zero a memory area then free it. Used to catch bugs faster
+*****************************************************************/
+void zero_free(void *p, size_t size)
{
- time_t t = time(NULL);
- struct tm *t2;
-
- t2 = gmtime(&t);
-
- t2->tm_mday = 1;
- t2->tm_hour = 0;
- t2->tm_min = 0;
- t2->tm_sec = 0;
-
- return(mktime(t2));
+ memset(p, 0, size);
+ SAFE_FREE(p);
}
-/*******************************************************************
- check for a sane unix date
-********************************************************************/
-BOOL sane_unix_date(time_t unixdate)
+/*****************************************************************
+set our open file limit to a requested max and return the limit
+*****************************************************************/
+int set_maxfiles(int requested_max)
{
- struct tm t,today;
- time_t t_today = time(NULL);
-
- t = *(LocalTime(&unixdate,LOCAL_TO_GMT));
- today = *(LocalTime(&t_today,LOCAL_TO_GMT));
-
- if (t.tm_year < 80)
- return(False);
-
- if (t.tm_year > today.tm_year)
- return(False);
-
- if (t.tm_year == today.tm_year &&
- t.tm_mon > today.tm_mon)
- return(False);
-
-
- if (t.tm_year == today.tm_year &&
- t.tm_mon == today.tm_mon &&
- t.tm_mday > (today.tm_mday+1))
- return(False);
-
- return(True);
-}
+#if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
+ struct rlimit rlp;
+ int saved_current_limit;
+ if(getrlimit(RLIMIT_NOFILE, &rlp)) {
+ DEBUG(0,("set_maxfiles: getrlimit (1) for RLIMIT_NOFILE failed with error %s\n",
+ strerror(errno) ));
+ /* just guess... */
+ return requested_max;
+ }
+ /*
+ * Set the fd limit to be real_max_open_files + MAX_OPEN_FUDGEFACTOR to
+ * account for the extra fd we need
+ * as well as the log files and standard
+ * handles etc. Save the limit we want to set in case
+ * we are running on an OS that doesn't support this limit (AIX)
+ * which always returns RLIM_INFINITY for rlp.rlim_max.
+ */
-#ifdef NO_FTRUNCATE
- /*******************************************************************
-ftruncate for operating systems that don't have it
-********************************************************************/
-int ftruncate(int f,long l)
-{
- struct flock fl;
+ /* Try raising the hard (max) limit to the requested amount. */
- fl.l_whence = 0;
- fl.l_len = 0;
- fl.l_start = l;
- fl.l_type = F_WRLCK;
- return fcntl(f, F_FREESP, &fl);
-}
-#endif
+#if defined(RLIM_INFINITY)
+ if (rlp.rlim_max != RLIM_INFINITY) {
+ int orig_max = rlp.rlim_max;
+ if ( rlp.rlim_max < requested_max )
+ rlp.rlim_max = requested_max;
+ /* This failing is not an error - many systems (Linux) don't
+ support our default request of 10,000 open files. JRA. */
-/****************************************************************************
-get my own name and IP
-****************************************************************************/
-BOOL get_myname(char *myname,struct in_addr *ip)
-{
- struct hostent *hp;
- pstring hostname;
+ if(setrlimit(RLIMIT_NOFILE, &rlp)) {
+ DEBUG(3,("set_maxfiles: setrlimit for RLIMIT_NOFILE for %d max files failed with error %s\n",
+ (int)rlp.rlim_max, strerror(errno) ));
- *hostname = 0;
+ /* Set failed - restore original value from get. */
+ rlp.rlim_max = orig_max;
+ }
+ }
+#endif
- /* get my host name */
- if (gethostname(hostname, MAXHOSTNAMELEN) == -1)
- {
- DEBUG(0,("gethostname failed\n"));
- return False;
- }
+ /* Now try setting the soft (current) limit. */
- /* get host info */
- if ((hp = Get_Hostbyname(hostname)) == 0)
- {
- DEBUG(0,( "Get_Hostbyname: Unknown host %s.\n",hostname));
- return False;
- }
+ saved_current_limit = rlp.rlim_cur = MIN(requested_max,rlp.rlim_max);
- if (myname)
- {
- /* split off any parts after an initial . */
- char *p = strchr(hostname,'.');
- if (p) *p = 0;
+ if(setrlimit(RLIMIT_NOFILE, &rlp)) {
+ DEBUG(0,("set_maxfiles: setrlimit for RLIMIT_NOFILE for %d files failed with error %s\n",
+ (int)rlp.rlim_cur, strerror(errno) ));
+ /* just guess... */
+ return saved_current_limit;
+ }
- strcpy(myname,hostname);
+ if(getrlimit(RLIMIT_NOFILE, &rlp)) {
+ DEBUG(0,("set_maxfiles: getrlimit (2) for RLIMIT_NOFILE failed with error %s\n",
+ strerror(errno) ));
+ /* just guess... */
+ return saved_current_limit;
}
- if (ip)
- putip((char *)ip,(char *)hp->h_addr);
-
- return(True);
-}
+#if defined(RLIM_INFINITY)
+ if(rlp.rlim_cur == RLIM_INFINITY)
+ return saved_current_limit;
+#endif
+ if((int)rlp.rlim_cur > saved_current_limit)
+ return saved_current_limit;
-/****************************************************************************
-true if two IP addresses are equal
-****************************************************************************/
-BOOL ip_equal(struct in_addr ip1,struct in_addr ip2)
-{
- unsigned long a1,a2;
- a1 = ntohl(ip1.s_addr);
- a2 = ntohl(ip2.s_addr);
- return(a1 == a2);
+ return rlp.rlim_cur;
+#else /* !defined(HAVE_GETRLIMIT) || !defined(RLIMIT_NOFILE) */
+ /*
+ * No way to know - just guess...
+ */
+ return requested_max;
+#endif
}
-
-/****************************************************************************
-open a socket of the specified type, port and address for incoming data
-****************************************************************************/
-int open_socket_in(int type, int port, int dlevel)
+/*****************************************************************
+ splits out the start of the key (HKLM or HKU) and the rest of the key
+ *****************************************************************/
+BOOL reg_split_key(char *full_keyname, uint32 *reg_type, char *key_name)
{
- struct hostent *hp;
- struct sockaddr_in sock;
- pstring host_name;
- int res;
-
- /* get my host name */
-#ifdef MAXHOSTNAMELEN
- if (gethostname(host_name, MAXHOSTNAMELEN) == -1)
-#else
- if (gethostname(host_name, sizeof(host_name)) == -1)
-#endif
- { DEBUG(0,("gethostname failed\n")); return -1; }
+ pstring tmp;
- /* get host info */
- if ((hp = Get_Hostbyname(host_name)) == 0)
- {
- DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",host_name));
- return -1;
- }
-
- bzero((char *)&sock,sizeof(sock));
- memcpy((char *)&sock.sin_addr,(char *)hp->h_addr, hp->h_length);
-#if defined(__FreeBSD__) || defined(NETBSD) /* XXX not the right ifdef */
- sock.sin_len = sizeof(sock);
-#endif
- sock.sin_port = htons( port );
- sock.sin_family = hp->h_addrtype;
- sock.sin_addr.s_addr = INADDR_ANY;
- res = socket(hp->h_addrtype, type, 0);
- if (res == -1)
- { DEBUG(0,("socket failed\n")); return -1; }
-
- {
- int one=1;
- setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
- }
+ if (!next_token(&full_keyname, tmp, "\\", sizeof(tmp)))
+ {
+ return False;
+ }
- /* now we've got a socket - we need to bind it */
- if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0)
- {
- if (port) {
- if (port == 139 || port == 137)
- DEBUG(dlevel,("bind failed on port %d (%s)\n",
- port,strerror(errno)));
- close(res);
+ (*reg_type) = 0;
- if (dlevel > 0 && port < 1000)
- port = 7999;
+ DEBUG(10, ("reg_split_key: hive %s\n", tmp));
- if (port >= 1000 && port < 9000)
- return(open_socket_in(type,port+1,dlevel));
- }
+ if (strequal(tmp, "HKLM") || strequal(tmp, "HKEY_LOCAL_MACHINE"))
+ {
+ (*reg_type) = HKEY_LOCAL_MACHINE;
+ }
+ else if (strequal(tmp, "HKU") || strequal(tmp, "HKEY_USERS"))
+ {
+ (*reg_type) = HKEY_USERS;
+ }
+ else
+ {
+ DEBUG(10,("reg_split_key: unrecognised hive key %s\n", tmp));
+ return False;
+ }
+
+ if (next_token(&full_keyname, tmp, "\n\r", sizeof(tmp)))
+ {
+ fstrcpy(key_name, tmp);
+ }
+ else
+ {
+ key_name[0] = 0;
+ }
- return(-1);
- }
- DEBUG(3,("bind succeeded on port %d\n",port));
+ DEBUG(10, ("reg_split_key: name %s\n", key_name));
- return res;
+ return True;
}
-/****************************************************************************
- create an outgoing socket
- **************************************************************************/
-int open_socket_out(int type, struct in_addr *addr, int port )
+/*****************************************************************
+possibly replace mkstemp if it is broken
+*****************************************************************/
+int smb_mkstemp(char *template)
{
- struct sockaddr_in sock_out;
- int res;
-
- /* create a socket to write to */
- res = socket(PF_INET, type, 0);
- if (res == -1)
- { DEBUG(0,("socket error\n")); return -1; }
-
- if (type != SOCK_STREAM) return(res);
-
- bzero((char *)&sock_out,sizeof(sock_out));
- putip((char *)&sock_out.sin_addr,(char *)addr);
-
- sock_out.sin_port = htons( port );
- sock_out.sin_family = PF_INET;
-
- DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port));
-
- /* and connect it to the destination */
- if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))<0) {
- DEBUG(0,("connect error: %s\n",strerror(errno)));
- close(res);
- return(-1);
- }
-
- return res;
+#if HAVE_SECURE_MKSTEMP
+ return mkstemp(template);
+#else
+ /* have a reasonable go at emulating it. Hope that
+ the system mktemp() isn't completly hopeless */
+ char *p = mktemp(template);
+ if (!p) return -1;
+ return open(p, O_CREAT|O_EXCL|O_RDWR, 0600);
+#endif
}
-/****************************************************************************
-interpret a protocol description string, with a default
-****************************************************************************/
-int interpret_protocol(char *str,int def)
+/**
+ malloc that aborts with smb_panic on fail or zero size.
+**/
+void *smb_xmalloc(size_t size)
{
- if (strequal(str,"NT1"))
- return(PROTOCOL_NT1);
- if (strequal(str,"LANMAN2"))
- return(PROTOCOL_LANMAN2);
- if (strequal(str,"LANMAN1"))
- return(PROTOCOL_LANMAN1);
- if (strequal(str,"CORE"))
- return(PROTOCOL_CORE);
- if (strequal(str,"COREPLUS"))
- return(PROTOCOL_COREPLUS);
- if (strequal(str,"CORE+"))
- return(PROTOCOL_COREPLUS);
-
- DEBUG(0,("Unrecognised protocol level %s\n",str));
-
- return(def);
+ void *p;
+ if (size == 0)
+ smb_panic("smb_xmalloc: called with zero size.\n");
+ if ((p = malloc(size)) == NULL)
+ smb_panic("smb_xmalloc: malloc fail.\n");
+ return p;
}
-/****************************************************************************
-interpret a security level
-****************************************************************************/
-int interpret_security(char *str,int def)
+/**
+ Memdup with smb_panic on fail.
+**/
+void *smb_xmemdup(const void *p, size_t size)
{
- if (strequal(str,"SERVER"))
- return(SEC_SERVER);
- if (strequal(str,"USER"))
- return(SEC_USER);
- if (strequal(str,"SHARE"))
- return(SEC_SHARE);
-
- DEBUG(0,("Unrecognised security level %s\n",str));
-
- return(def);
+ void *p2;
+ p2 = smb_xmalloc(size);
+ memcpy(p2, p, size);
+ return p2;
}
-
-/****************************************************************************
-interpret an internet address or name into an IP address in 4 byte form
-****************************************************************************/
-unsigned long interpret_addr(char *str)
+/**
+ strdup that aborts on malloc fail.
+**/
+char *smb_xstrdup(const char *s)
{
- struct hostent *hp;
- unsigned long res;
-
- if (strcmp(str,"0.0.0.0") == 0) return(0);
- if (strcmp(str,"255.255.255.255") == 0) return(0xFFFFFFFF);
-
- /* if it's in the form of an IP address then get the lib to interpret it */
- if (isdigit(str[0])) {
- res = inet_addr(str);
- } else {
- /* otherwise assume it's a network name of some sort and use Get_Hostbyname */
- if ((hp = Get_Hostbyname(str)) == 0) {
- DEBUG(3,("Get_Hostbyname: Unknown host. %s\n",str));
- return 0;
- }
- putip((char *)&res,(char *)hp->h_addr);
- }
-
- if (res == (unsigned long)-1) return(0);
-
- return(res);
+ char *s1 = strdup(s);
+ if (!s1)
+ smb_panic("smb_xstrdup: malloc fail\n");
+ return s1;
}
-/*******************************************************************
- a convenient addition to interpret_addr()
- ******************************************************************/
-struct in_addr *interpret_addr2(char *str)
+/*
+ vasprintf that aborts on malloc fail
+*/
+int smb_xvasprintf(char **ptr, const char *format, va_list ap)
{
- static struct in_addr ret;
- unsigned long a = interpret_addr(str);
- putip((char *)&ret,(char *)&a);
- return(&ret);
+ int n;
+ n = vasprintf(ptr, format, ap);
+ if (n == -1 || ! *ptr) {
+ smb_panic("smb_xvasprintf: out of memory");
+ }
+ return n;
}
-/*******************************************************************
- check if an IP is the 0.0.0.0
- ******************************************************************/
-BOOL zero_ip(struct in_addr ip)
+/*****************************************************************
+like strdup but for memory
+ *****************************************************************/
+void *memdup(const void *p, size_t size)
{
- unsigned long a;
- putip((char *)&a,(char *)&ip);
- return(a == 0);
+ void *p2;
+ if (size == 0) return NULL;
+ p2 = malloc(size);
+ if (!p2) return NULL;
+ memcpy(p2, p, size);
+ return p2;
}
-#define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
-
-/****************************************************************************
-interpret an 8 byte "filetime" structure to a time_t
-It's originally in "100ns units since jan 1st 1601"
-
-It appears to be kludge-GMT (at least for file listings). This means
-its the GMT you get by taking a localtime and adding the
-serverzone. This is NOT the same as GMT in some cases. This routine
-converts this to real GMT.
-****************************************************************************/
-time_t interpret_long_date(char *p)
+/*****************************************************************
+get local hostname and cache result
+ *****************************************************************/
+char *myhostname(void)
{
- double d;
- time_t ret;
- uint32 tlow,thigh;
- tlow = IVAL(p,0);
- thigh = IVAL(p,4);
-
- if (thigh == 0) return(0);
-
- d = ((double)thigh)*4.0*(double)(1<<30);
- d += (tlow&0xFFF00000);
- d *= 1.0e-7;
-
- /* now adjust by 369 years to make the secs since 1970 */
- d -= TIME_FIXUP_CONSTANT;
-
- if (d>=MAXINT)
- return(0);
-
- ret = (time_t)(d+0.5);
-
- /* this takes us from kludge-GMT to real GMT */
- ret += TimeDiff(ret) - serverzone;
-
- return(ret);
+ static pstring ret;
+ if (ret[0] == 0) {
+ get_myname(ret);
+ }
+ return ret;
}
-/****************************************************************************
-put a 8 byte filetime from a time_t
-This takes real GMT as input and converts to kludge-GMT
-****************************************************************************/
-void put_long_date(char *p,time_t t)
+/*****************************************************************
+a useful function for returning a path in the Samba lock directory
+ *****************************************************************/
+char *lock_path(char *name)
{
- uint32 tlow,thigh;
- double d;
-
- if (t==0) {
- SIVAL(p,0,0); SIVAL(p,4,0);
- return;
- }
-
- /* this converts GMT to kludge-GMT */
- t -= TimeDiff(t) - serverzone;
-
- d = (double) (t);
+ static pstring fname;
- d += TIME_FIXUP_CONSTANT;
+ pstrcpy(fname,lp_lockdir());
+ trim_string(fname,"","/");
+
+ if (!directory_exist(fname,NULL)) {
+ mkdir(fname,0755);
+ }
+
+ pstrcat(fname,"/");
+ pstrcat(fname,name);
- d *= 1.0e7;
+ return fname;
+}
- thigh = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
- tlow = (uint32)(d - ((double)thigh)*4.0*(double)(1<<30));
- SIVAL(p,0,tlow);
- SIVAL(p,4,thigh);
+/**
+ * @brief Returns an absolute path to a file in the Samba lib directory.
+ *
+ * @param name File to find, relative to LIBDIR.
+ *
+ * @retval Pointer to a static #pstring containing the full path.
+ **/
+char *lib_path(char *name)
+{
+ static pstring fname;
+ snprintf(fname, sizeof(fname), "%s/%s", dyn_LIBDIR, name);
+ return fname;
}
/*******************************************************************
-sub strings with useful parameters
+ Given a filename - get its directory name
+ NB: Returned in static storage. Caveats:
+ o Not safe in thread environment.
+ o Caller must not free.
+ o If caller wishes to preserve, they should copy.
********************************************************************/
-void standard_sub_basic(char *s)
-{
- if (!strchr(s,'%')) return;
-
- string_sub(s,"%R",remote_proto);
- string_sub(s,"%a",remote_arch);
- string_sub(s,"%m",remote_machine);
- string_sub(s,"%L",local_machine);
- if (!strchr(s,'%')) return;
-
- string_sub(s,"%v",VERSION);
- string_sub(s,"%h",myhostname);
- string_sub(s,"%U",sesssetup_user);
-
- if (!strchr(s,'%')) return;
-
- string_sub(s,"%I",Client_info.addr);
- string_sub(s,"%M",Client_info.name);
- string_sub(s,"%T",timestring());
-
- if (!strchr(s,'%')) return;
-
- {
- char pidstr[10];
- sprintf(pidstr,"%d",(int)getpid());
- string_sub(s,"%d",pidstr);
- }
+char *parent_dirname(const char *path)
+{
+ static pstring dirpath;
+ char *p;
- if (!strchr(s,'%')) return;
+ if (!path)
+ return(NULL);
- {
- struct passwd *pass = Get_Pwnam(sesssetup_user,False);
- if (pass) {
- string_sub(s,"%G",gidtoname(pass->pw_gid));
- }
- }
+ pstrcpy(dirpath, path);
+ p = strrchr_m(dirpath, '/'); /* Find final '/', if any */
+ if (!p) {
+ pstrcpy(dirpath, "."); /* No final "/", so dir is "." */
+ } else {
+ if (p == dirpath)
+ ++p; /* For root "/", leave "/" in place */
+ *p = '\0';
+ }
+ return dirpath;
}
/*******************************************************************
-write a string in unicoode format
-********************************************************************/
-int PutUniCode(char *dst,char *src)
+determine if a pattern contains any Microsoft wildcard characters
+ *******************************************************************/
+BOOL ms_has_wild(char *s)
{
- int ret = 0;
- while (*src) {
- dst[ret++] = src[0];
- dst[ret++] = 0;
- src++;
- }
- dst[ret++]=0;
- dst[ret++]=0;
- return(ret);
+ char c;
+ while ((c = *s++)) {
+ switch (c) {
+ case '*':
+ case '?':
+ case '<':
+ case '>':
+ case '"':
+ return True;
+ }
+ }
+ return False;
+}
+
+BOOL ms_has_wild_w(const smb_ucs2_t *s)
+{
+ smb_ucs2_t c;
+ if (!s) return False;
+ while ((c = *s++)) {
+ switch (c) {
+ case UCS2_CHAR('*'):
+ case UCS2_CHAR('?'):
+ case UCS2_CHAR('<'):
+ case UCS2_CHAR('>'):
+ case UCS2_CHAR('"'):
+ return True;
+ }
+ }
+ return False;
}
-
-pstring smbrun_path = SMBRUN;
-
-/****************************************************************************
-run a command via system() using smbrun
-****************************************************************************/
-int smbrun(char *cmd,char *outfile)
+/*******************************************************************
+ a wrapper that handles case sensitivity and the special handling
+ of the ".." name
+ *******************************************************************/
+BOOL mask_match(char *string, char *pattern, BOOL is_case_sensitive)
{
- int ret;
- pstring syscmd;
+ fstring p2, s2;
- if (!file_exist(smbrun_path,NULL))
- {
- DEBUG(0,("SMBRUN ERROR: Can't find %s. Installation problem?\n",smbrun_path));
- return(1);
- }
-
- sprintf(syscmd,"%s \"(%s 2>&1) > %s\"",
- smbrun_path,cmd,
- outfile?outfile:"/dev/null");
+ if (strcmp(string,"..") == 0) string = ".";
+ if (strcmp(pattern,".") == 0) return False;
+
+ if (is_case_sensitive) {
+ return ms_fnmatch(pattern, string, Protocol) == 0;
+ }
- DEBUG(5,("smbrun - running %s ",syscmd));
- ret = system(syscmd);
- DEBUG(5,("gave %d\n",ret));
- return(ret);
+ fstrcpy(p2, pattern);
+ fstrcpy(s2, string);
+ strlower(p2);
+ strlower(s2);
+ return ms_fnmatch(p2, s2, Protocol) == 0;
}
+/*********************************************************
+ Recursive routine that is called by unix_wild_match.
+*********************************************************/
-/****************************************************************************
-a wrapper for gethostbyname() that tries with all lower and all upper case
-if the initial name fails
-****************************************************************************/
-struct hostent *Get_Hostbyname(char *name)
-{
- char *name2 = strdup(name);
- struct hostent *ret;
-
- if (!name2)
- {
- DEBUG(0,("Memory allocation error in Get_Hostbyname! panic\n"));
- exit(0);
- }
+static BOOL unix_do_match(char *regexp, char *str)
+{
+ char *p;
+
+ for( p = regexp; *p && *str; ) {
+
+ switch(*p) {
+ case '?':
+ str++;
+ p++;
+ break;
+
+ case '*':
+
+ /*
+ * Look for a character matching
+ * the one after the '*'.
+ */
+ p++;
+ if(!*p)
+ return True; /* Automatic match */
+ while(*str) {
+
+ while(*str && (*p != *str))
+ str++;
+
+ /*
+ * Patch from weidel@multichart.de. In the case of the regexp
+ * '*XX*' we want to ensure there are at least 2 'X' characters
+ * in the string after the '*' for a match to be made.
+ */
+
+ {
+ int matchcount=0;
+
+ /*
+ * Eat all the characters that match, but count how many there were.
+ */
+
+ while(*str && (*p == *str)) {
+ str++;
+ matchcount++;
+ }
+
+ /*
+ * Now check that if the regexp had n identical characters that
+ * matchcount had at least that many matches.
+ */
+
+ while ( *(p+1) && (*(p+1) == *p)) {
+ p++;
+ matchcount--;
+ }
+
+ if ( matchcount <= 0 )
+ return False;
+ }
+
+ str--; /* We've eaten the match char after the '*' */
+
+ if(unix_do_match(p, str))
+ return True;
+
+ if(!*str)
+ return False;
+ else
+ str++;
+ }
+ return False;
+
+ default:
+ if(*str != *p)
+ return False;
+ str++;
+ p++;
+ break;
+ }
+ }
- if (!isalnum(*name2))
- {
- free(name2);
- return(NULL);
- }
+ if(!*p && !*str)
+ return True;
- ret = gethostbyname(name2);
- if (ret != NULL)
- {
- free(name2);
- return(ret);
- }
+ if (!*p && str[0] == '.' && str[1] == 0)
+ return(True);
+
+ if (!*str && *p == '?') {
+ while (*p == '?')
+ p++;
+ return(!*p);
+ }
- /* try with all lowercase */
- strlower(name2);
- ret = gethostbyname(name2);
- if (ret != NULL)
- {
- free(name2);
- return(ret);
- }
+ if(!*str && (*p == '*' && p[1] == '\0'))
+ return True;
- /* try with all uppercase */
- strupper(name2);
- ret = gethostbyname(name2);
- if (ret != NULL)
- {
- free(name2);
- return(ret);
- }
-
- /* nothing works :-( */
- free(name2);
- return(NULL);
+ return False;
}
+/*******************************************************************
+ Simple case insensitive interface to a UNIX wildcard matcher.
+*******************************************************************/
-/****************************************************************************
-check if a process exists. Does this work on all unixes?
-****************************************************************************/
-BOOL process_exists(int pid)
+BOOL unix_wild_match(char *pattern, char *string)
{
-#ifdef LINUX
- fstring s;
- sprintf(s,"/proc/%d",pid);
- return(directory_exist(s,NULL));
-#else
- {
- static BOOL tested=False;
- static BOOL ok=False;
- fstring s;
- if (!tested) {
- tested = True;
- sprintf(s,"/proc/%05d",getpid());
- ok = file_exist(s,NULL);
- }
- if (ok) {
- sprintf(s,"/proc/%05d",pid);
- return(file_exist(s,NULL));
- }
- }
-
- /* a best guess for non root access */
- if (geteuid() != 0) return(True);
+ pstring p2, s2;
+ char *p;
- /* otherwise use kill */
- return(pid == getpid() || kill(pid,0) == 0);
-#endif
-}
+ pstrcpy(p2, pattern);
+ pstrcpy(s2, string);
+ strlower(p2);
+ strlower(s2);
+ /* Remove any *? and ** from the pattern as they are meaningless */
+ for(p = p2; *p; p++)
+ while( *p == '*' && (p[1] == '?' ||p[1] == '*'))
+ pstrcpy( &p[1], &p[2]);
+
+ if (strequal(p2,"*"))
+ return True;
-/*******************************************************************
-turn a uid into a user name
-********************************************************************/
-char *uidtoname(int uid)
-{
- static char name[40];
- struct passwd *pass = getpwuid(uid);
- if (pass) return(pass->pw_name);
- sprintf(name,"%d",uid);
- return(name);
+ return unix_do_match(p2, s2) == 0;
}
/*******************************************************************
-turn a gid into a group name
-********************************************************************/
-char *gidtoname(int gid)
+ free() a data blob
+*******************************************************************/
+static void free_data_blob(DATA_BLOB *d)
{
- static char name[40];
- struct group *grp = getgrgid(gid);
- if (grp) return(grp->gr_name);
- sprintf(name,"%d",gid);
- return(name);
+ if ((d) && (d->free)) {
+ SAFE_FREE(d->data);
+ }
}
/*******************************************************************
-block sigs
-********************************************************************/
-void BlockSignals(BOOL block)
+ construct a data blob, must be freed with data_blob_free()
+ you can pass NULL for p and get a blank data blob
+*******************************************************************/
+DATA_BLOB data_blob(const void *p, size_t length)
{
-#ifdef USE_SIGBLOCK
- int block_mask = (sigmask(SIGTERM)|sigmask(SIGQUIT)|sigmask(SIGSEGV)
- |sigmask(SIGCHLD)|sigmask(SIGQUIT)|sigmask(SIGBUS)|
- sigmask(SIGINT));
- if (block)
- sigblock(block_mask);
- else
- sigunblock(block_mask);
-#endif
-}
+ DATA_BLOB ret;
-#if AJT
-/*******************************************************************
-my own panic function - not suitable for general use
-********************************************************************/
-void ajt_panic(void)
-{
- pstring cmd = "/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT &";
- smbrun(cmd,NULL);
-}
-#endif
+ if (!length) {
+ ZERO_STRUCT(ret);
+ return ret;
+ }
-#ifdef USE_DIRECT
-#define DIRECT direct
-#else
-#define DIRECT dirent
-#endif
+ if (p) {
+ ret.data = smb_xmemdup(p, length);
+ } else {
+ ret.data = smb_xmalloc(length);
+ }
+ ret.length = length;
+ ret.free = free_data_blob;
+ return ret;
+}
/*******************************************************************
-a readdir wrapper which just returns the file name
-also return the inode number if requested
-********************************************************************/
-char *readdirname(void *p)
+ construct a data blob, using supplied TALLOC_CTX
+*******************************************************************/
+DATA_BLOB data_blob_talloc(TALLOC_CTX *mem_ctx, const void *p, size_t length)
{
- struct DIRECT *ptr;
- char *dname;
-
- if (!p) return(NULL);
-
- ptr = (struct DIRECT *)readdir(p);
- if (!ptr) return(NULL);
-
- dname = ptr->d_name;
-
-#ifdef KANJI
- {
- static pstring buf;
- strcpy(buf, dname);
- unix_to_dos(buf, True);
- dname = buf;
- }
-#endif
-
-#ifdef NEXT2
- if (telldir(p) < 0) return(NULL);
-#endif
-
-#ifdef SUNOS5
- /* this handles a broken compiler setup, causing a mixture
- of BSD and SYSV headers and libraries */
- {
- static BOOL broken_readdir = False;
- if (!broken_readdir && !(*(dname)) && strequal("..",dname-2))
- {
- DEBUG(0,("Your readdir() is broken. You have somehow mixed SYSV and BSD headers and libraries\n"));
- broken_readdir = True;
- }
- if (broken_readdir)
- return(dname-2);
- }
-#endif
-
- return(dname);
-}
-
-
-
-#if (defined(SecureWare) && defined(SCO))
-/* This is needed due to needing the nap() function but we don't want
- to include the Xenix libraries since that will break other things...
- BTW: system call # 0x0c28 is the same as calling nap() */
-long nap(long milliseconds) {
- return syscall(0x0c28, milliseconds);
-}
-#endif
-
-#ifdef NO_INITGROUPS
-#include <sys/types.h>
-#include <limits.h>
-#include <grp.h>
-
-#ifndef NULL
-#define NULL (void *)0
-#endif
+ DATA_BLOB ret;
-/****************************************************************************
- some systems don't have an initgroups call
-****************************************************************************/
-int initgroups(char *name,gid_t id)
-{
-#ifdef NO_SETGROUPS
- /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
- return(0);
-#else
- gid_t grouplst[NGROUPS_MAX];
- int i,j;
- struct group *g;
- char *gr;
-
- grouplst[0] = id;
- i = 1;
- while (i < NGROUPS_MAX &&
- ((g = (struct group *)getgrent()) != (struct group *)NULL))
- {
- if (g->gr_gid == id)
- continue;
- j = 0;
- gr = g->gr_mem[0];
- while (gr && (*gr != (char)NULL)) {
- if (strcmp(name,gr) == 0) {
- grouplst[i] = g->gr_gid;
- i++;
- gr = (char *)NULL;
- break;
+ if (!p || !length) {
+ ZERO_STRUCT(ret);
+ return ret;
}
- gr = g->gr_mem[++j];
- }
- }
- endgrent();
- return(setgroups(i,grouplst));
-#endif
-}
-#endif
-
-
-#if WRAP_MALLOC
-
-/* undo the wrapping temporarily */
-#undef malloc
-#undef realloc
-#undef free
-/****************************************************************************
-wrapper for malloc() to catch memory errors
-****************************************************************************/
-void *malloc_wrapped(int size,char *file,int line)
-{
-#ifdef xx_old_malloc
- void *res = xx_old_malloc(size);
-#else
- void *res = malloc(size);
-#endif
- DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n",
- file,line,
- size,(unsigned int)res));
- return(res);
-}
+ ret.data = talloc_memdup(mem_ctx, p, length);
+ if (ret.data == NULL)
+ smb_panic("data_blob_talloc: talloc_memdup failed.\n");
-/****************************************************************************
-wrapper for realloc() to catch memory errors
-****************************************************************************/
-void *realloc_wrapped(void *ptr,int size,char *file,int line)
-{
-#ifdef xx_old_realloc
- void *res = xx_old_realloc(ptr,size);
-#else
- void *res = realloc(ptr,size);
-#endif
- DEBUG(3,("Realloc\n"));
- DEBUG(3,("free called from %s(%d) with ptr=0x%X\n",
- file,line,
- (unsigned int)ptr));
- DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n",
- file,line,
- size,(unsigned int)res));
- return(res);
+ ret.length = length;
+ ret.free = NULL;
+ return ret;
}
-/****************************************************************************
-wrapper for free() to catch memory errors
-****************************************************************************/
-void free_wrapped(void *ptr,char *file,int line)
-{
-#ifdef xx_old_free
- xx_old_free(ptr);
-#else
- free(ptr);
-#endif
- DEBUG(3,("free called from %s(%d) with ptr=0x%X\n",
- file,line,(unsigned int)ptr));
- return;
-}
-
-/* and re-do the define for spots lower in this file */
-#define malloc(size) malloc_wrapped(size,__FILE__,__LINE__)
-#define realloc(ptr,size) realloc_wrapped(ptr,size,__FILE__,__LINE__)
-#define free(ptr) free_wrapped(ptr,__FILE__,__LINE__)
-
-#endif
-
-#ifdef REPLACE_STRSTR
-/****************************************************************************
-Mips version of strstr doesn't seem to work correctly.
-There is a #define in includes.h to redirect calls to this function.
-****************************************************************************/
-char *Strstr(char *s, char *p)
+/*******************************************************************
+free a data blob
+*******************************************************************/
+void data_blob_free(DATA_BLOB *d)
{
- int len = strlen(p);
-
- while ( *s != '\0' ) {
- if ( strncmp(s, p, len) == 0 )
- return s;
- s++;
+ if (d) {
+ if (d->free) {
+ (d->free)(d);
+ }
+ ZERO_STRUCTP(d);
}
-
- return NULL;
}
-#endif /* REPLACE_STRSTR */
-
-#ifdef REPLACE_MKTIME
/*******************************************************************
-a mktime() replacement for those who don't have it - contributed by
-C.A. Lademann <cal@zls.com>
-********************************************************************/
-#define MINUTE 60
-#define HOUR 60*MINUTE
-#define DAY 24*HOUR
-#define YEAR 365*DAY
-time_t Mktime(struct tm *t)
-{
- struct tm *u;
- time_t epoch = 0;
- int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
- y, m, i;
-
- if(t->tm_year < 70)
- return((time_t)-1);
-
- epoch = (t->tm_year - 70) * YEAR +
- (t->tm_year / 4 - 70 / 4 - t->tm_year / 100) * DAY;
-
- y = t->tm_year;
- m = 0;
-
- for(i = 0; i < t->tm_mon; i++) {
- epoch += mon [m] * DAY;
- if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
- epoch += DAY;
-
- if(++m > 11) {
- m = 0;
- y++;
- }
- }
-
- epoch += (t->tm_mday - 1) * DAY;
- epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
-
- if((u = localtime(&epoch)) != NULL) {
- t->tm_sec = u->tm_sec;
- t->tm_min = u->tm_min;
- t->tm_hour = u->tm_hour;
- t->tm_mday = u->tm_mday;
- t->tm_mon = u->tm_mon;
- t->tm_year = u->tm_year;
- t->tm_wday = u->tm_wday;
- t->tm_yday = u->tm_yday;
- t->tm_isdst = u->tm_isdst;
-#ifndef NO_TM_NAME
- memcpy(t->tm_name, u->tm_name, LTZNMAX);
-#endif
- }
-
- return(epoch);
-}
-#endif /* REPLACE_MKTIME */
-
-
-
-#ifdef REPLACE_RENAME
-/* Rename a file. (from libiberty in GNU binutils) */
-int
-rename (zfrom, zto)
- const char *zfrom;
- const char *zto;
+clear a DATA_BLOB's contents
+*******************************************************************/
+void data_blob_clear(DATA_BLOB *d)
{
- if (link (zfrom, zto) < 0)
- {
- if (errno != EEXIST)
- return -1;
- if (unlink (zto) < 0
- || link (zfrom, zto) < 0)
- return -1;
- }
- return unlink (zfrom);
+ if (d->data) {
+ memset(d->data, 0, d->length);
+ }
}
-#endif
-
-#ifdef REPLACE_INNETGR
-/*
- * Search for a match in a netgroup. This replaces it on broken systems.
- */
-int InNetGr(group, host, user, dom)
- char *group, *host, *user, *dom;
+/*******************************************************************
+free a data blob and clear its contents
+*******************************************************************/
+void data_blob_clear_free(DATA_BLOB *d)
{
- char *hst, *usr, *dm;
-
- setnetgrent(group);
- while (getnetgrent(&hst, &usr, &dm))
- if (((host == 0) || (hst == 0) || !strcmp(host, hst)) &&
- ((user == 0) || (usr == 0) || !strcmp(user, usr)) &&
- ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) {
- endnetgrent();
- return (1);
- }
- endnetgrent();
- return (0);
+ data_blob_clear(d);
+ data_blob_free(d);
}
-#endif
+#ifdef __INSURE__
-#if WRAP_MEMCPY
-#undef memcpy
/*******************************************************************
-a wrapper around memcpy for diagnostic purposes
+This routine is a trick to immediately catch errors when debugging
+with insure. A xterm with a gdb is popped up when insure catches
+a error. It is Linux specific.
********************************************************************/
-void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line)
-{
- if (l>64 && (((int)d)%4) != (((int)s)%4))
- DEBUG(4,("Misaligned memcpy(0x%X,0x%X,%d) at %s(%d)\n",d,s,l,fname,line));
-#ifdef xx_old_memcpy
- return(xx_old_memcpy(d,s,l));
-#else
- return(memcpy(d,s,l));
-#endif
-}
-#define memcpy(d,s,l) memcpy_wrapped(d,s,l,__FILE__,__LINE__)
-#endif
+int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
+{
+ static int (*fn)();
+ int ret;
+ char pidstr[10];
+ /* you can get /usr/bin/backtrace from
+ http://samba.org/ftp/unpacked/junkcode/backtrace */
+ pstring cmd = "/usr/bin/backtrace %d";
+
+ slprintf(pidstr, sizeof(pidstr)-1, "%d", sys_getpid());
+ pstring_sub(cmd, "%d", pidstr);
+
+ if (!fn) {
+ static void *h;
+ h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
+ fn = dlsym(h, "_Insure_trap_error");
+
+ if (!h || h == _Insure_trap_error) {
+ h = dlopen("/usr/local/parasoft/lib.linux2/libinsure.so", RTLD_LAZY);
+ fn = dlsym(h, "_Insure_trap_error");
+ }
+ }
+ ret = fn(a1, a2, a3, a4, a5, a6);
+ system(cmd);
+ return ret;
+}
+#endif
diff --git a/source3/lib/util_file.c b/source3/lib/util_file.c
new file mode 100644
index 0000000000..e80267f84b
--- /dev/null
+++ b/source3/lib/util_file.c
@@ -0,0 +1,595 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+static int gotalarm;
+
+/***************************************************************
+ Signal function to tell us we timed out.
+****************************************************************/
+
+static void gotalarm_sig(void)
+{
+ gotalarm = 1;
+}
+
+/***************************************************************
+ Lock or unlock a fd for a known lock type. Abandon after waitsecs
+ seconds.
+****************************************************************/
+
+BOOL do_file_lock(int fd, int waitsecs, int type)
+{
+ SMB_STRUCT_FLOCK lock;
+ int ret;
+
+ gotalarm = 0;
+ CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+
+ lock.l_type = type;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 1;
+ lock.l_pid = 0;
+
+ alarm(waitsecs);
+ ret = fcntl(fd, SMB_F_SETLKW, &lock);
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
+
+ if (gotalarm) {
+ DEBUG(0, ("do_file_lock: failed to %s file.\n",
+ type == F_UNLCK ? "unlock" : "lock"));
+ return False;
+ }
+
+ return (ret == 0);
+}
+
+
+/***************************************************************
+ Lock an fd. Abandon after waitsecs seconds.
+****************************************************************/
+
+BOOL file_lock(int fd, int type, int secs, int *plock_depth)
+{
+ if (fd < 0)
+ return False;
+
+ (*plock_depth)++;
+
+ if ((*plock_depth) == 0)
+ {
+ if (!do_file_lock(fd, secs, type)) {
+ DEBUG(10,("file_lock: locking file failed, error = %s.\n",
+ strerror(errno)));
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/***************************************************************
+ Unlock an fd. Abandon after waitsecs seconds.
+****************************************************************/
+
+BOOL file_unlock(int fd, int *plock_depth)
+{
+ BOOL ret=True;
+
+ if(*plock_depth == 1)
+ ret = do_file_lock(fd, 5, F_UNLCK);
+
+ (*plock_depth)--;
+
+ if(!ret)
+ DEBUG(10,("file_unlock: unlocking file failed, error = %s.\n",
+ strerror(errno)));
+ return ret;
+}
+
+/***************************************************************
+ locks a file for enumeration / modification.
+ update to be set = True if modification is required.
+****************************************************************/
+
+void *startfilepwent(char *pfile, char *s_readbuf, int bufsize,
+ int *file_lock_depth, BOOL update)
+{
+ FILE *fp = NULL;
+
+ if (!*pfile)
+ {
+ DEBUG(0, ("startfilepwent: No file set\n"));
+ return (NULL);
+ }
+ DEBUG(10, ("startfilepwent: opening file %s\n", pfile));
+
+ fp = sys_fopen(pfile, update ? "r+b" : "rb");
+
+ if (fp == NULL) {
+ DEBUG(0, ("startfilepwent: unable to open file %s\n", pfile));
+ return NULL;
+ }
+
+ /* Set a buffer to do more efficient reads */
+ setvbuf(fp, s_readbuf, _IOFBF, bufsize);
+
+ if (!file_lock(fileno(fp), (update ? F_WRLCK : F_RDLCK), 5, file_lock_depth))
+ {
+ DEBUG(0, ("startfilepwent: unable to lock file %s\n", pfile));
+ fclose(fp);
+ return NULL;
+ }
+
+ /* Make sure it is only rw by the owner */
+ chmod(pfile, 0600);
+
+ /* We have a lock on the file. */
+ return (void *)fp;
+}
+
+/***************************************************************
+ End enumeration of the file.
+****************************************************************/
+void endfilepwent(void *vp, int *file_lock_depth)
+{
+ FILE *fp = (FILE *)vp;
+
+ file_unlock(fileno(fp), file_lock_depth);
+ fclose(fp);
+ DEBUG(7, ("endfilepwent: closed file.\n"));
+}
+
+/*************************************************************************
+ Return the current position in the file list as an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+*************************************************************************/
+SMB_BIG_UINT getfilepwpos(void *vp)
+{
+ return (SMB_BIG_UINT)sys_ftell((FILE *)vp);
+}
+
+/*************************************************************************
+ Set the current position in the file list from an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+*************************************************************************/
+BOOL setfilepwpos(void *vp, SMB_BIG_UINT tok)
+{
+ return !sys_fseek((FILE *)vp, (SMB_OFF_T)tok, SEEK_SET);
+}
+
+/*************************************************************************
+ gets a line out of a file.
+ line is of format "xxxx:xxxxxx:xxxxx:".
+ lines with "#" at the front are ignored.
+*************************************************************************/
+int getfileline(void *vp, char *linebuf, int linebuf_size)
+{
+ /* Static buffers we will return. */
+ FILE *fp = (FILE *)vp;
+ unsigned char c;
+ unsigned char *p;
+ size_t linebuf_len;
+
+ if (fp == NULL)
+ {
+ DEBUG(0,("getfileline: Bad file pointer.\n"));
+ return -1;
+ }
+
+ /*
+ * Scan the file, a line at a time.
+ */
+ while (!feof(fp))
+ {
+ linebuf[0] = '\0';
+
+ fgets(linebuf, linebuf_size, fp);
+ if (ferror(fp))
+ {
+ return -1;
+ }
+
+ /*
+ * Check if the string is terminated with a newline - if not
+ * then we must keep reading and discard until we get one.
+ */
+
+ linebuf_len = strlen(linebuf);
+ if (linebuf_len == 0)
+ {
+ linebuf[0] = '\0';
+ return 0;
+ }
+
+ if (linebuf[linebuf_len - 1] != '\n')
+ {
+ c = '\0';
+ while (!ferror(fp) && !feof(fp))
+ {
+ c = fgetc(fp);
+ if (c == '\n')
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ linebuf[linebuf_len - 1] = '\0';
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("getfileline: got line |%s|\n", linebuf));
+#endif
+ if ((linebuf[0] == 0) && feof(fp))
+ {
+ DEBUG(4, ("getfileline: end of file reached\n"));
+ return 0;
+ }
+
+ if (linebuf[0] == '#' || linebuf[0] == '\0')
+ {
+ DEBUG(6, ("getfileline: skipping comment or blank line\n"));
+ continue;
+ }
+
+ p = (unsigned char *) strchr_m(linebuf, ':');
+ if (p == NULL)
+ {
+ DEBUG(0, ("getfileline: malformed line entry (no :)\n"));
+ continue;
+ }
+ return linebuf_len;
+ }
+ return -1;
+}
+
+
+/****************************************************************************
+read a line from a file with possible \ continuation chars.
+Blanks at the start or end of a line are stripped.
+The string will be allocated if s2 is NULL
+****************************************************************************/
+char *fgets_slash(char *s2,int maxlen,XFILE *f)
+{
+ char *s=s2;
+ int len = 0;
+ int c;
+ BOOL start_of_line = True;
+
+ if (x_feof(f))
+ return(NULL);
+
+ if (maxlen <2) return(NULL);
+
+ if (!s2)
+ {
+ maxlen = MIN(maxlen,8);
+ s = (char *)malloc(maxlen);
+ }
+
+ if (!s) return(NULL);
+
+ *s = 0;
+
+ while (len < maxlen-1)
+ {
+ c = x_getc(f);
+ switch (c)
+ {
+ case '\r':
+ break;
+ case '\n':
+ while (len > 0 && s[len-1] == ' ')
+ {
+ s[--len] = 0;
+ }
+ if (len > 0 && s[len-1] == '\\')
+ {
+ s[--len] = 0;
+ start_of_line = True;
+ break;
+ }
+ return(s);
+ case EOF:
+ if (len <= 0 && !s2)
+ SAFE_FREE(s);
+ return(len>0?s:NULL);
+ case ' ':
+ if (start_of_line)
+ break;
+ default:
+ start_of_line = False;
+ s[len++] = c;
+ s[len] = 0;
+ }
+ if (!s2 && len > maxlen-3)
+ {
+ char *t;
+
+ maxlen *= 2;
+ t = (char *)Realloc(s,maxlen);
+ if (!t) {
+ DEBUG(0,("fgets_slash: failed to expand buffer!\n"));
+ SAFE_FREE(s);
+ return(NULL);
+ } else s = t;
+ }
+ }
+ return(s);
+}
+
+
+/****************************************************************************
+load from a pipe into memory
+****************************************************************************/
+char *file_pload(char *syscmd, size_t *size)
+{
+ int fd, n;
+ char *p, *tp;
+ pstring buf;
+ size_t total;
+
+ fd = sys_popen(syscmd);
+ if (fd == -1) return NULL;
+
+ p = NULL;
+ total = 0;
+
+ while ((n = read(fd, buf, sizeof(buf))) > 0) {
+ tp = Realloc(p, total + n + 1);
+ if (!tp) {
+ DEBUG(0,("file_pload: failed to exand buffer!\n"));
+ close(fd);
+ SAFE_FREE(p);
+ return NULL;
+ } else p = tp;
+ memcpy(p+total, buf, n);
+ total += n;
+ }
+ if (p) p[total] = 0;
+
+ sys_pclose(fd);
+
+ if (size) *size = total;
+
+ return p;
+}
+
+/****************************************************************************
+load a file into memory from a fd.
+****************************************************************************/
+
+char *fd_load(int fd, size_t *size)
+{
+ SMB_STRUCT_STAT sbuf;
+ char *p;
+
+ if (sys_fstat(fd, &sbuf) != 0) return NULL;
+
+ p = (char *)malloc(sbuf.st_size+1);
+ if (!p) return NULL;
+
+ if (read(fd, p, sbuf.st_size) != sbuf.st_size) {
+ SAFE_FREE(p);
+ return NULL;
+ }
+ p[sbuf.st_size] = 0;
+
+ if (size) *size = sbuf.st_size;
+
+ return p;
+}
+
+/****************************************************************************
+load a file into memory
+****************************************************************************/
+char *file_load(const char *fname, size_t *size)
+{
+ int fd;
+ char *p;
+
+ if (!fname || !*fname) return NULL;
+
+ fd = open(fname,O_RDONLY);
+ if (fd == -1) return NULL;
+
+ p = fd_load(fd, size);
+
+ close(fd);
+
+ return p;
+}
+
+
+/*******************************************************************
+mmap (if possible) or read a file
+********************************************************************/
+void *map_file(char *fname, size_t size)
+{
+ size_t s2 = 0;
+ void *p = NULL;
+#ifdef HAVE_MMAP
+ if (lp_use_mmap()) {
+ int fd;
+ fd = open(fname, O_RDONLY, 0);
+ if (fd == -1) {
+ DEBUG(2,("Failed to load %s - %s\n", fname, strerror(errno)));
+ return NULL;
+ }
+ p = mmap(NULL, size, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
+ close(fd);
+ if (p == MAP_FAILED) {
+ DEBUG(1,("Failed to mmap %s - %s\n", fname, strerror(errno)));
+ return NULL;
+ }
+ }
+#endif
+ if (!p) {
+ p = file_load(fname, &s2);
+ if (!p || s2 != size) {
+ DEBUG(1,("incorrect size for %s - got %d expected %d\n",
+ fname, s2, size));
+ if (p) free(p);
+ return NULL;
+ }
+ }
+
+ return p;
+}
+
+
+/****************************************************************************
+parse a buffer into lines
+****************************************************************************/
+static char **file_lines_parse(char *p, size_t size, int *numlines)
+{
+ int i;
+ char *s, **ret;
+
+ if (!p) return NULL;
+
+ for (s = p, i=0; s < p+size; s++) {
+ if (s[0] == '\n') i++;
+ }
+
+ ret = (char **)malloc(sizeof(ret[0])*(i+2));
+ if (!ret) {
+ SAFE_FREE(p);
+ return NULL;
+ }
+ memset(ret, 0, sizeof(ret[0])*(i+2));
+ if (numlines) *numlines = i;
+
+ ret[0] = p;
+ for (s = p, i=0; s < p+size; s++) {
+ if (s[0] == '\n') {
+ s[0] = 0;
+ i++;
+ ret[i] = s+1;
+ }
+ if (s[0] == '\r') s[0] = 0;
+ }
+
+ return ret;
+}
+
+
+/****************************************************************************
+load a file into memory and return an array of pointers to lines in the file
+must be freed with file_lines_free().
+****************************************************************************/
+char **file_lines_load(const char *fname, int *numlines)
+{
+ char *p;
+ size_t size;
+
+ p = file_load(fname, &size);
+ if (!p) return NULL;
+
+ return file_lines_parse(p, size, numlines);
+}
+
+/****************************************************************************
+load a fd into memory and return an array of pointers to lines in the file
+must be freed with file_lines_free(). If convert is true calls unix_to_dos on
+the list.
+****************************************************************************/
+char **fd_lines_load(int fd, int *numlines)
+{
+ char *p;
+ size_t size;
+
+ p = fd_load(fd, &size);
+ if (!p) return NULL;
+
+ return file_lines_parse(p, size, numlines);
+}
+
+
+/****************************************************************************
+load a pipe into memory and return an array of pointers to lines in the data
+must be freed with file_lines_free().
+****************************************************************************/
+char **file_lines_pload(char *syscmd, int *numlines)
+{
+ char *p;
+ size_t size;
+
+ p = file_pload(syscmd, &size);
+ if (!p) return NULL;
+
+ return file_lines_parse(p, size, numlines);
+}
+
+/****************************************************************************
+free lines loaded with file_lines_load
+****************************************************************************/
+void file_lines_free(char **lines)
+{
+ if (!lines) return;
+ SAFE_FREE(lines[0]);
+ SAFE_FREE(lines);
+}
+
+
+/****************************************************************************
+take a lislist of lines and modify them to produce a list where \ continues
+a line
+****************************************************************************/
+void file_lines_slashcont(char **lines)
+{
+ int i, j;
+
+ for (i=0; lines[i];) {
+ int len = strlen(lines[i]);
+ if (lines[i][len-1] == '\\') {
+ lines[i][len-1] = ' ';
+ if (lines[i+1]) {
+ char *p = &lines[i][len];
+ while (p < lines[i+1]) *p++ = ' ';
+ for (j = i+1; lines[j]; j++) lines[j] = lines[j+1];
+ }
+ } else {
+ i++;
+ }
+ }
+}
+
+/*
+ save a lump of data into a file. Mostly used for debugging
+*/
+BOOL file_save(const char *fname, void *packet, size_t length)
+{
+ int fd;
+ fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (fd == -1) {
+ return False;
+ }
+ if (write(fd, packet, length) != length) {
+ return False;
+ }
+ close(fd);
+ return True;
+}
diff --git a/source3/lib/util_getent.c b/source3/lib/util_getent.c
new file mode 100644
index 0000000000..02e4b932de
--- /dev/null
+++ b/source3/lib/util_getent.c
@@ -0,0 +1,318 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Jeremy Allison 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#if 0
+static void print_grent_list(struct sys_grent *glist)
+{
+ DEBUG(100, ("print_grent_list: %x\n", glist ));
+ while (glist) {
+ DEBUG(100,("glist: %x ", glist));
+ if (glist->gr_name)
+ DEBUG(100,(": gr_name = (%x) %s ", glist->gr_name, glist->gr_name));
+ if (glist->gr_passwd)
+ DEBUG(100,(": gr_passwd = (%x) %s ", glist->gr_passwd, glist->gr_passwd));
+ if (glist->gr_mem) {
+ int i;
+ for (i = 0; glist->gr_mem[i]; i++)
+ DEBUG(100,(" : gr_mem[%d] = (%x) %s ", i, glist->gr_mem[i], glist->gr_mem[i]));
+ }
+ DEBUG(100,(": gr_next = %x\n", glist->next ));
+ glist = glist->next;
+ }
+ DEBUG(100,("FINISHED !\n\n"));
+}
+#endif
+
+/****************************************************************
+ Returns a single linked list of group entries.
+ Use grent_free() to free it after use.
+****************************************************************/
+
+struct sys_grent * getgrent_list(void)
+{
+ struct sys_grent *glist;
+ struct sys_grent *gent;
+ struct group *grp;
+
+ gent = (struct sys_grent *) malloc(sizeof(struct sys_grent));
+ if (gent == NULL) {
+ DEBUG (0, ("Out of memory in getgrent_list!\n"));
+ return NULL;
+ }
+ memset(gent, '\0', sizeof(struct sys_grent));
+ glist = gent;
+
+ setgrent();
+ grp = getgrent();
+ if (grp == NULL) {
+ endgrent();
+ SAFE_FREE(glist);
+ return NULL;
+ }
+
+ while (grp != NULL) {
+ int i,num;
+
+ if (grp->gr_name) {
+ if ((gent->gr_name = strdup(grp->gr_name)) == NULL)
+ goto err;
+ }
+ if (grp->gr_passwd) {
+ if ((gent->gr_passwd = strdup(grp->gr_passwd)) == NULL)
+ goto err;
+ }
+ gent->gr_gid = grp->gr_gid;
+
+ /* number of strings in gr_mem */
+ for (num = 0; grp->gr_mem[num]; num++)
+ ;
+
+ /* alloc space for gr_mem string pointers */
+ if ((gent->gr_mem = (char **) malloc((num+1) * sizeof(char *))) == NULL)
+ goto err;
+
+ memset(gent->gr_mem, '\0', (num+1) * sizeof(char *));
+
+ for (i=0; i < num; i++) {
+ if ((gent->gr_mem[i] = strdup(grp->gr_mem[i])) == NULL)
+ goto err;
+ }
+ gent->gr_mem[num] = NULL;
+
+ grp = getgrent();
+ if (grp) {
+ gent->next = (struct sys_grent *) malloc(sizeof(struct sys_grent));
+ if (gent->next == NULL)
+ goto err;
+ gent = gent->next;
+ memset(gent, '\0', sizeof(struct sys_grent));
+ }
+ }
+
+ endgrent();
+ return glist;
+
+ err:
+
+ endgrent();
+ DEBUG(0, ("Out of memory in getgrent_list!\n"));
+ grent_free(glist);
+ return NULL;
+}
+
+/****************************************************************
+ Free the single linked list of group entries made by
+ getgrent_list()
+****************************************************************/
+
+void grent_free (struct sys_grent *glist)
+{
+ while (glist) {
+ struct sys_grent *prev;
+
+ SAFE_FREE(glist->gr_name);
+ SAFE_FREE(glist->gr_passwd);
+ if (glist->gr_mem) {
+ int i;
+ for (i = 0; glist->gr_mem[i]; i++)
+ SAFE_FREE(glist->gr_mem[i]);
+ SAFE_FREE(glist->gr_mem);
+ }
+ prev = glist;
+ glist = glist->next;
+ SAFE_FREE(prev);
+ }
+}
+
+/****************************************************************
+ Returns a single linked list of passwd entries.
+ Use pwent_free() to free it after use.
+****************************************************************/
+
+struct sys_pwent * getpwent_list(void)
+{
+ struct sys_pwent *plist;
+ struct sys_pwent *pent;
+ struct passwd *pwd;
+
+ pent = (struct sys_pwent *) malloc(sizeof(struct sys_pwent));
+ if (pent == NULL) {
+ DEBUG (0, ("Out of memory in getpwent_list!\n"));
+ return NULL;
+ }
+ plist = pent;
+
+ setpwent();
+ pwd = getpwent();
+ while (pwd != NULL) {
+ memset(pent, '\0', sizeof(struct sys_pwent));
+ if (pwd->pw_name) {
+ if ((pent->pw_name = strdup(pwd->pw_name)) == NULL)
+ goto err;
+ }
+ if (pwd->pw_passwd) {
+ if ((pent->pw_passwd = strdup(pwd->pw_passwd)) == NULL)
+ goto err;
+ }
+ pent->pw_uid = pwd->pw_uid;
+ pent->pw_gid = pwd->pw_gid;
+ if (pwd->pw_gecos) {
+ if ((pent->pw_name = strdup(pwd->pw_gecos)) == NULL)
+ goto err;
+ }
+ if (pwd->pw_dir) {
+ if ((pent->pw_name = strdup(pwd->pw_dir)) == NULL)
+ goto err;
+ }
+ if (pwd->pw_shell) {
+ if ((pent->pw_name = strdup(pwd->pw_shell)) == NULL)
+ goto err;
+ }
+
+ pwd = getpwent();
+ if (pwd) {
+ pent->next = (struct sys_pwent *) malloc(sizeof(struct sys_pwent));
+ if (pent->next == NULL)
+ goto err;
+ pent = pent->next;
+ }
+ }
+
+ endpwent();
+ return plist;
+
+ err:
+
+ endpwent();
+ DEBUG(0, ("Out of memory in getpwent_list!\n"));
+ pwent_free(plist);
+ return NULL;
+}
+
+/****************************************************************
+ Free the single linked list of passwd entries made by
+ getpwent_list()
+****************************************************************/
+
+void pwent_free (struct sys_pwent *plist)
+{
+ while (plist) {
+ struct sys_pwent *prev;
+
+ SAFE_FREE(plist->pw_name);
+ SAFE_FREE(plist->pw_passwd);
+ SAFE_FREE(plist->pw_gecos);
+ SAFE_FREE(plist->pw_dir);
+ SAFE_FREE(plist->pw_shell);
+
+ prev = plist;
+ plist = plist->next;
+ SAFE_FREE(prev);
+ }
+}
+
+/****************************************************************
+ Add the individual group users onto the list.
+****************************************************************/
+
+static struct sys_userlist *add_members_to_userlist(struct sys_userlist *list_head, const struct group *grp)
+{
+ size_t num_users, i;
+
+ /* Count the number of users. */
+ for (num_users = 0; grp->gr_mem[num_users]; num_users++)
+ ;
+
+ for (i = 0; i < num_users; i++) {
+ struct sys_userlist *entry = (struct sys_userlist *)malloc(sizeof(*entry));
+ size_t len = strlen(grp->gr_mem[i])+1;
+ if (entry == NULL) {
+ free_userlist(list_head);
+ return NULL;
+ }
+ entry->unix_name = (char *)malloc(len);
+ if (entry->unix_name == NULL) {
+ SAFE_FREE(entry);
+ free_userlist(list_head);
+ return NULL;
+ }
+ safe_strcpy(entry->unix_name, grp->gr_mem[i],len);
+ DLIST_ADD(list_head, entry);
+ }
+ return list_head;
+}
+
+/****************************************************************
+ Get the list of UNIX users in a group.
+ We have to enumerate the /etc/group file as some UNIX getgrnam()
+ calls won't do that for us (notably Tru64 UNIX).
+****************************************************************/
+
+struct sys_userlist *get_users_in_group(const char *gname)
+{
+ struct sys_userlist *list_head = NULL;
+ struct group *gptr;
+ fstring domain;
+ fstring groupname;
+ DOM_SID sid;
+ enum SID_NAME_USE name_type;
+
+ (void) split_domain_and_name(gname, domain, groupname);
+
+ /*
+ * If we're doing this via winbindd, don't do the
+ * entire group list enumeration as we know this is
+ * pointless (and slow).
+ */
+
+ if (winbind_lookup_name(domain, groupname, &sid, &name_type) && name_type == SID_NAME_DOM_GRP) {
+ if ((gptr = (struct group *)getgrnam(gname)) == NULL)
+ return NULL;
+ return add_members_to_userlist(list_head, gptr);
+ }
+
+ setgrent();
+ while((gptr = getgrent()) != NULL) {
+ if (strequal(gname, gptr->gr_name)) {
+ list_head = add_members_to_userlist(list_head, gptr);
+ if (list_head == NULL)
+ return NULL;
+ }
+ }
+ endgrent();
+ return list_head;
+}
+
+/****************************************************************
+ Free list allocated above.
+****************************************************************/
+
+void free_userlist(struct sys_userlist *list_head)
+{
+ while (list_head) {
+ struct sys_userlist *old_head = list_head;
+ DLIST_REMOVE(list_head, list_head);
+ SAFE_FREE(old_head->unix_name);
+ SAFE_FREE(old_head);
+ }
+}
diff --git a/source3/lib/util_pw.c b/source3/lib/util_pw.c
new file mode 100644
index 0000000000..259649a064
--- /dev/null
+++ b/source3/lib/util_pw.c
@@ -0,0 +1,133 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Safe versions of getpw* calls
+
+ Copyright (C) Andrew Bartlett 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+struct passwd *make_modifyable_passwd(const struct passwd *from)
+{
+ struct passwd *ret = smb_xmalloc(sizeof(*ret));
+/* This is the assumed shape of the members by certain parts of the code...
+ fstring pw_name;
+ fstring pw_passwd;
+ fstring pw_gecos;
+ pstring pw_dir;
+ pstring pw_shell;
+*/
+ char *pw_name = smb_xmalloc(sizeof(fstring));
+ char *pw_passwd = smb_xmalloc(sizeof(fstring));
+ char *pw_gecos = smb_xmalloc(sizeof(fstring));
+ char *pw_dir = smb_xmalloc(sizeof(pstring));
+ char *pw_shell = smb_xmalloc(sizeof(pstring));
+
+ ZERO_STRUCTP(ret);
+
+ /*
+ * Now point the struct's members as the
+ * newly allocated buffers:
+ */
+
+ ret->pw_name = pw_name;
+ fstrcpy(ret->pw_name, from->pw_name);
+
+ ret->pw_passwd = pw_passwd;
+ fstrcpy(ret->pw_passwd, from->pw_passwd);
+
+ ret->pw_uid = from->pw_uid;
+ ret->pw_gid = from->pw_gid;
+
+ ret->pw_gecos = pw_gecos;
+ fstrcpy(ret->pw_gecos, from->pw_gecos);
+
+ ret->pw_dir = pw_dir;
+ pstrcpy(ret->pw_dir, from->pw_dir);
+
+ ret->pw_shell = pw_shell;
+ pstrcpy(ret->pw_shell, from->pw_shell);
+
+ return ret;
+}
+
+static struct passwd *alloc_copy_passwd(const struct passwd *from)
+{
+ struct passwd *ret = smb_xmalloc(sizeof(struct passwd));
+ ZERO_STRUCTP(ret);
+ ret->pw_name = smb_xstrdup(from->pw_name);
+ ret->pw_passwd = smb_xstrdup(from->pw_passwd);
+ ret->pw_uid = from->pw_uid;
+ ret->pw_gid = from->pw_gid;
+ ret->pw_gecos = smb_xstrdup(from->pw_gecos);
+ ret->pw_dir = smb_xstrdup(from->pw_dir);
+ ret->pw_shell = smb_xstrdup(from->pw_shell);
+ return ret;
+}
+
+void passwd_free (struct passwd **buf)
+{
+ if (!*buf) {
+ DEBUG(0, ("attempted double-free of allocated passwd\n"));
+ return;
+ }
+
+ SAFE_FREE((*buf)->pw_name);
+ SAFE_FREE((*buf)->pw_passwd);
+ SAFE_FREE((*buf)->pw_gecos);
+ SAFE_FREE((*buf)->pw_dir);
+ SAFE_FREE((*buf)->pw_shell);
+
+ SAFE_FREE(*buf);
+}
+
+struct passwd *getpwnam_alloc(const char *name)
+{
+ struct passwd *temp;
+
+ temp = getpwnam(name);
+
+ if (!temp) {
+#if 0
+ if (errno == ENOMEM) {
+ /* what now? */
+ }
+#endif
+ return NULL;
+ }
+
+ return alloc_copy_passwd(temp);
+}
+
+struct passwd *getpwuid_alloc(uid_t uid)
+{
+ struct passwd *temp;
+
+ temp = getpwuid(uid);
+
+ if (!temp) {
+#if 0
+ if (errno == ENOMEM) {
+ /* what now? */
+ }
+#endif
+ return NULL;
+ }
+
+ return alloc_copy_passwd(temp);
+}
diff --git a/source3/lib/util_seaccess.c b/source3/lib/util_seaccess.c
new file mode 100644
index 0000000000..8ed266aced
--- /dev/null
+++ b/source3/lib/util_seaccess.c
@@ -0,0 +1,446 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000.
+ Copyright (C) Tim Potter 2000.
+ Copyright (C) Re-written by Jeremy Allison 2000.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "nterr.h"
+#include "sids.h"
+
+/**********************************************************************************
+ Check if this ACE has a SID in common with the token.
+**********************************************************************************/
+
+static BOOL token_sid_in_ace(const NT_USER_TOKEN *token, const SEC_ACE *ace)
+{
+ size_t i;
+
+ for (i = 0; i < token->num_sids; i++) {
+ if (sid_equal(&ace->trustee, &token->user_sids[i]))
+ return True;
+ }
+
+ return False;
+}
+
+/*********************************************************************************
+ Check an ACE against a SID. We return the remaining needed permission
+ bits not yet granted. Zero means permission allowed (no more needed bits).
+**********************************************************************************/
+
+static uint32 check_ace(SEC_ACE *ace, NT_USER_TOKEN *token, uint32 acc_desired,
+ NTSTATUS *status)
+{
+ uint32 mask = ace->info.mask;
+
+ /*
+ * Inherit only is ignored.
+ */
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ return acc_desired;
+ }
+
+ /*
+ * If this ACE has no SID in common with the token,
+ * ignore it as it cannot be used to make an access
+ * determination.
+ */
+
+ if (!token_sid_in_ace( token, ace))
+ return acc_desired;
+
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ /*
+ * This is explicitly allowed.
+ * Remove the bits from the remaining
+ * access required. Return the remaining
+ * bits needed.
+ */
+ acc_desired &= ~mask;
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ /*
+ * This is explicitly denied.
+ * If any bits match terminate here,
+ * we are denied.
+ */
+ if (acc_desired & mask) {
+ *status = NT_STATUS_ACCESS_DENIED;
+ return 0xFFFFFFFF;
+ }
+ break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM:
+ case SEC_ACE_TYPE_SYSTEM_AUDIT:
+ *status = NT_STATUS_NOT_IMPLEMENTED;
+ return 0xFFFFFFFF;
+ default:
+ *status = NT_STATUS_INVALID_PARAMETER;
+ return 0xFFFFFFFF;
+ }
+
+ return acc_desired;
+}
+
+/*********************************************************************************
+ Maximum access was requested. Calculate the max possible. Fail if it doesn't
+ include other bits requested.
+**********************************************************************************/
+
+static BOOL get_max_access( SEC_ACL *the_acl, NT_USER_TOKEN *token, uint32 *granted,
+ uint32 desired,
+ NTSTATUS *status)
+{
+ uint32 acc_denied = 0;
+ uint32 acc_granted = 0;
+ size_t i;
+
+ for ( i = 0 ; i < the_acl->num_aces; i++) {
+ SEC_ACE *ace = &the_acl->ace[i];
+ uint32 mask = ace->info.mask;
+
+ if (!token_sid_in_ace( token, ace))
+ continue;
+
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ acc_granted |= (mask & ~acc_denied);
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ acc_denied |= (mask & ~acc_granted);
+ break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM:
+ case SEC_ACE_TYPE_SYSTEM_AUDIT:
+ *status = NT_STATUS_NOT_IMPLEMENTED;
+ *granted = 0;
+ return False;
+ default:
+ *status = NT_STATUS_INVALID_PARAMETER;
+ *granted = 0;
+ return False;
+ }
+ }
+
+ /*
+ * If we were granted no access, or we desired bits that we
+ * didn't get, then deny.
+ */
+
+ if ((acc_granted == 0) || ((acc_granted & desired) != desired)) {
+ *status = NT_STATUS_ACCESS_DENIED;
+ *granted = 0;
+ return False;
+ }
+
+ /*
+ * Return the access we did get.
+ */
+
+ *granted = acc_granted;
+ *status = NT_STATUS_OK;
+ return True;
+}
+
+/* Map generic access rights to object specific rights. This technique is
+ used to give meaning to assigning read, write, execute and all access to
+ objects. Each type of object has its own mapping of generic to object
+ specific access rights. */
+
+void se_map_generic(uint32 *access_mask, struct generic_mapping *mapping)
+{
+ uint32 old_mask = *access_mask;
+
+ if (*access_mask & GENERIC_READ_ACCESS) {
+ *access_mask &= ~GENERIC_READ_ACCESS;
+ *access_mask |= mapping->generic_read;
+ }
+
+ if (*access_mask & GENERIC_WRITE_ACCESS) {
+ *access_mask &= ~GENERIC_WRITE_ACCESS;
+ *access_mask |= mapping->generic_write;
+ }
+
+ if (*access_mask & GENERIC_EXECUTE_ACCESS) {
+ *access_mask &= ~GENERIC_EXECUTE_ACCESS;
+ *access_mask |= mapping->generic_execute;
+ }
+
+ if (*access_mask & GENERIC_ALL_ACCESS) {
+ *access_mask &= ~GENERIC_ALL_ACCESS;
+ *access_mask |= mapping->generic_all;
+ }
+
+ if (old_mask != *access_mask) {
+ DEBUG(10, ("se_map_generic(): mapped mask 0x%08x to 0x%08x\n",
+ old_mask, *access_mask));
+ }
+}
+
+/* Map standard access rights to object specific rights. This technique is
+ used to give meaning to assigning read, write, execute and all access to
+ objects. Each type of object has its own mapping of standard to object
+ specific access rights. */
+
+void se_map_standard(uint32 *access_mask, struct standard_mapping *mapping)
+{
+ uint32 old_mask = *access_mask;
+
+ if (*access_mask & READ_CONTROL_ACCESS) {
+ *access_mask &= ~READ_CONTROL_ACCESS;
+ *access_mask |= mapping->std_read;
+ }
+
+ if (*access_mask & (DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|SYNCHRONIZE_ACCESS)) {
+ *access_mask &= ~(DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|SYNCHRONIZE_ACCESS);
+ *access_mask |= mapping->std_all;
+ }
+
+ if (old_mask != *access_mask) {
+ DEBUG(10, ("se_map_standard(): mapped mask 0x%08x to 0x%08x\n",
+ old_mask, *access_mask));
+ }
+}
+
+/*****************************************************************************
+ Check access rights of a user against a security descriptor. Look at
+ each ACE in the security descriptor until an access denied ACE denies
+ any of the desired rights to the user or any of the users groups, or one
+ or more ACEs explicitly grant all requested access rights. See
+ "Access-Checking" document in MSDN.
+*****************************************************************************/
+
+BOOL se_access_check(SEC_DESC *sd, NT_USER_TOKEN *token,
+ uint32 acc_desired, uint32 *acc_granted,
+ NTSTATUS *status)
+{
+ extern NT_USER_TOKEN anonymous_token;
+ size_t i;
+ SEC_ACL *the_acl;
+ fstring sid_str;
+ uint32 tmp_acc_desired = acc_desired;
+
+ if (!status || !acc_granted)
+ return False;
+
+ if (!token)
+ token = &anonymous_token;
+
+ *status = NT_STATUS_OK;
+ *acc_granted = 0;
+
+ DEBUG(10,("se_access_check: requested access 0x%08x, for NT token with %u entries and first sid %s.\n",
+ (unsigned int)acc_desired, (unsigned int)token->num_sids,
+ sid_to_string(sid_str, &token->user_sids[0])));
+
+ /*
+ * No security descriptor or security descriptor with no DACL
+ * present allows all access.
+ */
+
+ /* ACL must have something in it */
+
+ if (!sd || (sd && (!(sd->type & SEC_DESC_DACL_PRESENT) || sd->dacl == NULL))) {
+ *status = NT_STATUS_OK;
+ *acc_granted = acc_desired;
+ DEBUG(5, ("se_access_check: no sd or blank DACL, access allowed\n"));
+ return True;
+ }
+
+ /* The user sid is the first in the token */
+
+ DEBUG(3, ("se_access_check: user sid is %s\n", sid_to_string(sid_str, &token->user_sids[PRIMARY_USER_SID_INDEX]) ));
+
+ for (i = 1; i < token->num_sids; i++) {
+ DEBUG(3, ("se_access_check: also %s\n",
+ sid_to_string(sid_str, &token->user_sids[i])));
+ }
+
+ /* Is the token the owner of the SID ? */
+
+ if (sd->owner_sid) {
+ for (i = 0; i < token->num_sids; i++) {
+ if (sid_equal(&token->user_sids[i], sd->owner_sid)) {
+ /*
+ * The owner always has SEC_RIGHTS_WRITE_DAC & READ_CONTROL.
+ */
+ if (tmp_acc_desired & WRITE_DAC_ACCESS)
+ tmp_acc_desired &= ~WRITE_DAC_ACCESS;
+ if (tmp_acc_desired & READ_CONTROL_ACCESS)
+ tmp_acc_desired &= ~READ_CONTROL_ACCESS;
+ }
+ }
+ }
+
+ the_acl = sd->dacl;
+
+ if (tmp_acc_desired & MAXIMUM_ALLOWED_ACCESS) {
+ tmp_acc_desired &= ~MAXIMUM_ALLOWED_ACCESS;
+ return get_max_access( the_acl, token, acc_granted, tmp_acc_desired,
+ status);
+ }
+
+ for ( i = 0 ; i < the_acl->num_aces && tmp_acc_desired != 0; i++) {
+ SEC_ACE *ace = &the_acl->ace[i];
+
+ DEBUG(10,("se_access_check: ACE %u: type %d, flags = 0x%02x, SID = %s mask = %x, current desired = %x\n",
+ (unsigned int)i, ace->type, ace->flags,
+ sid_to_string(sid_str, &ace->trustee),
+ (unsigned int) ace->info.mask,
+ (unsigned int)tmp_acc_desired ));
+
+ tmp_acc_desired = check_ace( ace, token, tmp_acc_desired, status);
+ if (NT_STATUS_V(*status)) {
+ *acc_granted = 0;
+ DEBUG(5,("se_access_check: ACE %u denied with status %s.\n", (unsigned int)i, nt_errstr(*status)));
+ return False;
+ }
+ }
+
+ /*
+ * If there are no more desired permissions left then
+ * access was allowed.
+ */
+
+ if (tmp_acc_desired == 0) {
+ *acc_granted = acc_desired;
+ *status = NT_STATUS_OK;
+ DEBUG(5,("se_access_check: access (%x) granted.\n", (unsigned int)acc_desired ));
+ return True;
+ }
+
+ *acc_granted = 0;
+ *status = NT_STATUS_ACCESS_DENIED;
+ DEBUG(5,("se_access_check: access (%x) denied.\n", (unsigned int)acc_desired ));
+ return False;
+}
+
+/* Create a child security descriptor using another security descriptor as
+ the parent container. This child object can either be a container or
+ non-container object. */
+
+SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr,
+ BOOL child_container)
+{
+ SEC_DESC_BUF *sdb;
+ SEC_DESC *sd;
+ SEC_ACL *new_dacl, *the_acl;
+ SEC_ACE *new_ace_list = NULL;
+ int new_ace_list_ndx = 0, i;
+ size_t size;
+
+ /* Currently we only process the dacl when creating the child. The
+ sacl should also be processed but this is left out as sacls are
+ not implemented in Samba at the moment.*/
+
+ the_acl = parent_ctr->dacl;
+
+ if (!(new_ace_list = talloc(ctx, sizeof(SEC_ACE) * the_acl->num_aces)))
+ return NULL;
+
+ for (i = 0; the_acl && i < the_acl->num_aces; i++) {
+ SEC_ACE *ace = &the_acl->ace[i];
+ SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
+ uint8 new_flags = 0;
+ BOOL inherit = False;
+ fstring sid_str;
+
+ /* The OBJECT_INHERIT_ACE flag causes the ACE to be
+ inherited by non-container children objects. Container
+ children objects will inherit it as an INHERIT_ONLY
+ ACE. */
+
+ if (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
+
+ if (!child_container) {
+ new_flags |= SEC_ACE_FLAG_OBJECT_INHERIT;
+ } else {
+ new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+ }
+
+ inherit = True;
+ }
+
+ /* The CONAINER_INHERIT_ACE flag means all child container
+ objects will inherit and use the ACE. */
+
+ if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
+ if (!child_container) {
+ inherit = False;
+ } else {
+ new_flags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
+ }
+ }
+
+ /* The INHERIT_ONLY_ACE is not used by the se_access_check()
+ function for the parent container, but is inherited by
+ all child objects as a normal ACE. */
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ /* Move along, nothing to see here */
+ }
+
+ /* The SEC_ACE_FLAG_NO_PROPAGATE_INHERIT flag means the ACE
+ is inherited by child objects but not grandchildren
+ objects. We clear the object inherit and container
+ inherit flags in the inherited ACE. */
+
+ if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
+ new_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT);
+ }
+
+ /* Add ACE to ACE list */
+
+ if (!inherit)
+ continue;
+
+ init_sec_access(&new_ace->info, ace->info.mask);
+ init_sec_ace(new_ace, &ace->trustee, ace->type,
+ new_ace->info, new_flags);
+
+ sid_to_string(sid_str, &ace->trustee);
+
+ DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
+ " inherited as %s:%d/0x%02x/0x%08x\n", sid_str,
+ ace->type, ace->flags, ace->info.mask,
+ sid_str, new_ace->type, new_ace->flags,
+ new_ace->info.mask));
+
+ new_ace_list_ndx++;
+ }
+
+ /* Create child security descriptor to return */
+
+ new_dacl = make_sec_acl(ctx, ACL_REVISION, new_ace_list_ndx, new_ace_list);
+
+ /* Use the existing user and group sids. I don't think this is
+ correct. Perhaps the user and group should be passed in as
+ parameters by the caller? */
+
+ sd = make_sec_desc(ctx, SEC_DESC_REVISION,
+ parent_ctr->owner_sid,
+ parent_ctr->grp_sid,
+ parent_ctr->sacl,
+ new_dacl, &size);
+
+ sdb = make_sec_desc_buf(ctx, size, sd);
+
+ return sdb;
+}
diff --git a/source3/lib/util_sec.c b/source3/lib/util_sec.c
new file mode 100644
index 0000000000..d59b1b0471
--- /dev/null
+++ b/source3/lib/util_sec.c
@@ -0,0 +1,422 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Jeremy Allison 1998.
+ rewritten for version 2.0.6 by Tridge
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef AUTOCONF_TEST
+#include "includes.h"
+#else
+/* we are running this code in autoconf test mode to see which type of setuid
+ function works */
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_PRIV_H
+#include <sys/priv.h>
+#endif
+#ifdef HAVE_SYS_ID_H
+#include <sys/id.h>
+#endif
+
+#define DEBUG(x, y) printf y
+#define smb_panic(x) exit(1)
+#define BOOL int
+#endif
+
+/* are we running as non-root? This is used by the regresison test code,
+ and potentially also for sites that want non-root smbd */
+static uid_t initial_uid;
+static gid_t initial_gid;
+
+/****************************************************************************
+remember what uid we got started as - this allows us to run correctly
+as non-root while catching trapdoor systems
+****************************************************************************/
+void sec_init(void)
+{
+ initial_uid = geteuid();
+ initial_gid = getegid();
+}
+
+/****************************************************************************
+some code (eg. winbindd) needs to know what uid we started as
+****************************************************************************/
+uid_t sec_initial_uid(void)
+{
+ return initial_uid;
+}
+
+/****************************************************************************
+some code (eg. winbindd, profiling shm) needs to know what gid we started as
+****************************************************************************/
+gid_t sec_initial_gid(void)
+{
+ return initial_gid;
+}
+
+/****************************************************************************
+are we running in non-root mode?
+****************************************************************************/
+BOOL non_root_mode(void)
+{
+ return (initial_uid != (uid_t)0);
+}
+
+/****************************************************************************
+abort if we haven't set the uid correctly
+****************************************************************************/
+static void assert_uid(uid_t ruid, uid_t euid)
+{
+ if ((euid != (uid_t)-1 && geteuid() != euid) ||
+ (ruid != (uid_t)-1 && getuid() != ruid)) {
+ if (!non_root_mode()) {
+ DEBUG(0,("Failed to set uid privileges to (%d,%d) now set to (%d,%d)\n",
+ (int)ruid, (int)euid,
+ (int)getuid(), (int)geteuid()));
+ smb_panic("failed to set uid\n");
+ exit(1);
+ }
+ }
+}
+
+/****************************************************************************
+abort if we haven't set the gid correctly
+****************************************************************************/
+static void assert_gid(gid_t rgid, gid_t egid)
+{
+ if ((egid != (gid_t)-1 && getegid() != egid) ||
+ (rgid != (gid_t)-1 && getgid() != rgid)) {
+ if (!non_root_mode()) {
+ DEBUG(0,("Failed to set gid privileges to (%d,%d) now set to (%d,%d) uid=(%d,%d)\n",
+ (int)rgid, (int)egid,
+ (int)getgid(), (int)getegid(),
+ (int)getuid(), (int)geteuid()));
+ smb_panic("failed to set gid\n");
+ exit(1);
+ }
+ }
+}
+
+/****************************************************************************
+ Gain root privilege before doing something.
+ We want to end up with ruid==euid==0
+****************************************************************************/
+void gain_root_privilege(void)
+{
+#if USE_SETRESUID
+ setresuid(0,0,0);
+#endif
+
+#if USE_SETEUID
+ seteuid(0);
+#endif
+
+#if USE_SETREUID
+ setreuid(0, 0);
+#endif
+
+#if USE_SETUIDX
+ setuidx(ID_EFFECTIVE, 0);
+ setuidx(ID_REAL, 0);
+#endif
+
+ /* this is needed on some systems */
+ setuid(0);
+
+ assert_uid(0, 0);
+}
+
+
+/****************************************************************************
+ Ensure our real and effective groups are zero.
+ we want to end up with rgid==egid==0
+****************************************************************************/
+void gain_root_group_privilege(void)
+{
+#if USE_SETRESUID
+ setresgid(0,0,0);
+#endif
+
+#if USE_SETREUID
+ setregid(0,0);
+#endif
+
+#if USE_SETEUID
+ setegid(0);
+#endif
+
+#if USE_SETUIDX
+ setgidx(ID_EFFECTIVE, 0);
+ setgidx(ID_REAL, 0);
+#endif
+
+ setgid(0);
+
+ assert_gid(0, 0);
+}
+
+
+/****************************************************************************
+ Set *only* the effective uid.
+ we want to end up with ruid==0 and euid==uid
+****************************************************************************/
+void set_effective_uid(uid_t uid)
+{
+#if USE_SETRESUID
+ setresuid(-1,uid,-1);
+#endif
+
+#if USE_SETREUID
+ setreuid(-1,uid);
+#endif
+
+#if USE_SETEUID
+ seteuid(uid);
+#endif
+
+#if USE_SETUIDX
+ setuidx(ID_EFFECTIVE, uid);
+#endif
+
+ assert_uid(-1, uid);
+}
+
+/****************************************************************************
+ Set *only* the effective gid.
+ we want to end up with rgid==0 and egid==gid
+****************************************************************************/
+void set_effective_gid(gid_t gid)
+{
+#if USE_SETRESUID
+ setresgid(-1,gid,-1);
+#endif
+
+#if USE_SETREUID
+ setregid(-1,gid);
+#endif
+
+#if USE_SETEUID
+ setegid(gid);
+#endif
+
+#if USE_SETUIDX
+ setgidx(ID_EFFECTIVE, gid);
+#endif
+
+ assert_gid(-1, gid);
+}
+
+static uid_t saved_euid, saved_ruid;
+
+/****************************************************************************
+ save the real and effective uid for later restoration. Used by the quotas
+ code
+****************************************************************************/
+void save_re_uid(void)
+{
+ saved_ruid = getuid();
+ saved_euid = geteuid();
+}
+
+
+/****************************************************************************
+ and restore them!
+****************************************************************************/
+void restore_re_uid(void)
+{
+ set_effective_uid(0);
+
+#if USE_SETRESUID
+ setresuid(saved_ruid, saved_euid, -1);
+#elif USE_SETREUID
+ setreuid(saved_ruid, -1);
+ setreuid(-1,saved_euid);
+#elif USE_SETUIDX
+ setuidx(ID_REAL, saved_ruid);
+ setuidx(ID_EFFECTIVE, saved_euid);
+#else
+ set_effective_uid(saved_euid);
+ if (getuid() != saved_ruid)
+ setuid(saved_ruid);
+ set_effective_uid(saved_euid);
+#endif
+
+ assert_uid(saved_ruid, saved_euid);
+}
+
+/****************************************************************************
+ set the real AND effective uid to the current effective uid in a way that
+ allows root to be regained.
+ This is only possible on some platforms.
+****************************************************************************/
+int set_re_uid(void)
+{
+ uid_t uid = geteuid();
+
+#if USE_SETRESUID
+ setresuid(geteuid(), -1, -1);
+#endif
+
+#if USE_SETREUID
+ setreuid(0, 0);
+ setreuid(uid, -1);
+ setreuid(-1, uid);
+#endif
+
+#if USE_SETEUID
+ /* can't be done */
+ return -1;
+#endif
+
+#if USE_SETUIDX
+ /* can't be done */
+ return -1;
+#endif
+
+ assert_uid(uid, uid);
+ return 0;
+}
+
+
+/****************************************************************************
+ Become the specified uid and gid - permanently !
+ there should be no way back if possible
+****************************************************************************/
+void become_user_permanently(uid_t uid, gid_t gid)
+{
+ /*
+ * First - gain root privilege. We do this to ensure
+ * we can lose it again.
+ */
+
+ gain_root_privilege();
+ gain_root_group_privilege();
+
+#if USE_SETRESUID
+ setresgid(gid,gid,gid);
+ setgid(gid);
+ setresuid(uid,uid,uid);
+ setuid(uid);
+#endif
+
+#if USE_SETREUID
+ setregid(gid,gid);
+ setgid(gid);
+ setreuid(uid,uid);
+ setuid(uid);
+#endif
+
+#if USE_SETEUID
+ setegid(gid);
+ setgid(gid);
+ setuid(uid);
+ seteuid(uid);
+ setuid(uid);
+#endif
+
+#if USE_SETUIDX
+ setgidx(ID_REAL, gid);
+ setgidx(ID_EFFECTIVE, gid);
+ setgid(gid);
+ setuidx(ID_REAL, uid);
+ setuidx(ID_EFFECTIVE, uid);
+ setuid(uid);
+#endif
+
+ assert_uid(uid, uid);
+ assert_gid(gid, gid);
+}
+
+#ifdef AUTOCONF_TEST
+
+/****************************************************************************
+this function just checks that we don't get ENOSYS back
+****************************************************************************/
+static int have_syscall(void)
+{
+ errno = 0;
+
+#if USE_SETRESUID
+ setresuid(-1,-1,-1);
+#endif
+
+#if USE_SETREUID
+ setreuid(-1,-1);
+#endif
+
+#if USE_SETEUID
+ seteuid(-1);
+#endif
+
+#if USE_SETUIDX
+ setuidx(ID_EFFECTIVE, -1);
+#endif
+
+ if (errno == ENOSYS) return -1;
+
+ return 0;
+}
+
+main()
+{
+ if (getuid() != 0) {
+#if (defined(AIX) && defined(USE_SETREUID))
+ /* setreuid is badly broken on AIX 4.1, we avoid it completely */
+ fprintf(stderr,"avoiding possibly broken setreuid\n");
+ exit(1);
+#endif
+
+ /* if not running as root then at least check to see if we get ENOSYS - this
+ handles Linux 2.0.x with glibc 2.1 */
+ fprintf(stderr,"not running as root: checking for ENOSYS\n");
+ exit(have_syscall());
+ }
+
+ gain_root_privilege();
+ gain_root_group_privilege();
+ set_effective_gid(1);
+ set_effective_uid(1);
+ save_re_uid();
+ restore_re_uid();
+ gain_root_privilege();
+ gain_root_group_privilege();
+ become_user_permanently(1, 1);
+ setuid(0);
+ if (getuid() == 0) {
+ fprintf(stderr,"uid not set permanently\n");
+ exit(1);
+ }
+
+ printf("OK\n");
+
+ exit(0);
+}
+#endif
+
+/****************************************************************************
+Check if we are setuid root. Used in libsmb and smbpasswd paranoia checks.
+****************************************************************************/
+BOOL is_setuid_root(void)
+{
+ return (geteuid() == (uid_t)0) && (getuid() != (uid_t)0);
+}
diff --git a/source3/lib/util_sid.c b/source3/lib/util_sid.c
new file mode 100644
index 0000000000..cd7b64bb70
--- /dev/null
+++ b/source3/lib/util_sid.c
@@ -0,0 +1,720 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Luke Kenneth Caseson Leighton 1998-1999
+ Copyright (C) Jeremy Allison 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* NOTE! the global_sam_sid is the SID of our local SAM. This is only
+ equal to the domain SID when we are a DC, otherwise its our
+ workstation SID */
+DOM_SID global_sam_sid;
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+
+/*
+ * Some useful sids
+ */
+
+DOM_SID global_sid_Builtin; /* Local well-known domain */
+DOM_SID global_sid_World_Domain; /* Everyone domain */
+DOM_SID global_sid_World; /* Everyone */
+DOM_SID global_sid_Creator_Owner_Domain; /* Creator Owner domain */
+DOM_SID global_sid_Creator_Owner; /* Creator Owner */
+DOM_SID global_sid_Creator_Group; /* Creator Group */
+DOM_SID global_sid_NT_Authority; /* NT Authority */
+DOM_SID global_sid_NULL; /* NULL sid */
+DOM_SID global_sid_Builtin_Guests; /* Builtin guest users */
+DOM_SID global_sid_Authenticated_Users; /* All authenticated rids */
+DOM_SID global_sid_Network; /* Network rids */
+DOM_SID global_sid_Anonymous; /* Anonymous login */
+
+const DOM_SID *global_sid_everyone = &global_sid_World;
+
+typedef struct _known_sid_users {
+ uint32 rid;
+ enum SID_NAME_USE sid_name_use;
+ char *known_user_name;
+} known_sid_users;
+
+/* static known_sid_users no_users[] = {{0, 0, NULL}}; */
+
+static known_sid_users everyone_users[] = {
+ { 0, SID_NAME_WKN_GRP, "Everyone" },
+ {0, (enum SID_NAME_USE)0, NULL}};
+
+static known_sid_users creator_owner_users[] = {
+ { 0, SID_NAME_ALIAS, "Creator Owner" },
+ {0, (enum SID_NAME_USE)0, NULL}};
+
+static known_sid_users nt_authority_users[] = {
+ { 1, SID_NAME_ALIAS, "Dialup" },
+ { 2, SID_NAME_ALIAS, "Network"},
+ { 3, SID_NAME_ALIAS, "Batch"},
+ { 4, SID_NAME_ALIAS, "Interactive"},
+ { 6, SID_NAME_ALIAS, "Service"},
+ { 7, SID_NAME_ALIAS, "AnonymousLogon"},
+ { 8, SID_NAME_ALIAS, "Proxy"},
+ { 9, SID_NAME_ALIAS, "ServerLogon"},
+ { 11, SID_NAME_ALIAS, "Authenticated Users"},
+ { 18, SID_NAME_ALIAS, "SYSTEM"},
+ { 0, (enum SID_NAME_USE)0, NULL}};
+
+static known_sid_users builtin_groups[] = {
+ { BUILTIN_ALIAS_RID_ADMINS, SID_NAME_ALIAS, "Administrators" },
+ { BUILTIN_ALIAS_RID_USERS, SID_NAME_ALIAS, "Users" },
+ { BUILTIN_ALIAS_RID_GUESTS, SID_NAME_ALIAS, "Guests" },
+ { BUILTIN_ALIAS_RID_ACCOUNT_OPS, SID_NAME_ALIAS, "Account Operators" },
+ { BUILTIN_ALIAS_RID_SYSTEM_OPS, SID_NAME_ALIAS, "Server Operators" },
+ { BUILTIN_ALIAS_RID_PRINT_OPS, SID_NAME_ALIAS, "Print Operators" },
+ { BUILTIN_ALIAS_RID_BACKUP_OPS, SID_NAME_ALIAS, "Backup Operators" },
+ { 0, (enum SID_NAME_USE)0, NULL}};
+
+#define MAX_SID_NAMES 7
+
+static struct sid_name_map_info
+{
+ DOM_SID *sid;
+ char *name;
+ known_sid_users *known_users;
+} sid_name_map[MAX_SID_NAMES];
+
+static BOOL sid_name_map_initialized = False;
+
+/*
+ * An NT compatible anonymous token.
+ */
+
+static DOM_SID anon_sid_array[3];
+
+NT_USER_TOKEN anonymous_token = {
+ 3,
+ anon_sid_array
+};
+
+/**************************************************************************
+ quick init function
+ *************************************************************************/
+static void init_sid_name_map (void)
+{
+ int i = 0;
+
+ if (sid_name_map_initialized) return;
+
+
+ if ((lp_security() == SEC_USER) && lp_domain_logons()) {
+ sid_name_map[i].sid = &global_sam_sid;
+ sid_name_map[i].name = global_myworkgroup;
+ sid_name_map[i].known_users = NULL;
+ i++;
+ sid_name_map[i].sid = &global_sam_sid;
+ sid_name_map[i].name = global_myname;
+ sid_name_map[i].known_users = NULL;
+ i++;
+ }
+ else {
+ sid_name_map[i].sid = &global_sam_sid;
+ sid_name_map[i].name = global_myname;
+ sid_name_map[i].known_users = NULL;
+ i++;
+ }
+
+ sid_name_map[i].sid = &global_sid_Builtin;
+ sid_name_map[i].name = "BUILTIN";
+ sid_name_map[i].known_users = &builtin_groups[0];
+ i++;
+
+ sid_name_map[i].sid = &global_sid_World_Domain;
+ sid_name_map[i].name = "";
+ sid_name_map[i].known_users = &everyone_users[0];
+ i++;
+
+ sid_name_map[i].sid = &global_sid_Creator_Owner_Domain;
+ sid_name_map[i].name = "";
+ sid_name_map[i].known_users = &creator_owner_users[0];
+ i++;
+
+ sid_name_map[i].sid = &global_sid_NT_Authority;
+ sid_name_map[i].name = "NT Authority";
+ sid_name_map[i].known_users = &nt_authority_users[0];
+ i++;
+
+
+ /* end of array */
+ sid_name_map[i].sid = NULL;
+ sid_name_map[i].name = NULL;
+ sid_name_map[i].known_users = NULL;
+
+ sid_name_map_initialized = True;
+
+ return;
+
+}
+
+/****************************************************************************
+ Creates some useful well known sids
+****************************************************************************/
+
+void generate_wellknown_sids(void)
+{
+ string_to_sid(&global_sid_Builtin, "S-1-5-32");
+ string_to_sid(&global_sid_Builtin_Guests, "S-1-5-32-546");
+ string_to_sid(&global_sid_World_Domain, "S-1-1");
+ string_to_sid(&global_sid_World, "S-1-1-0");
+ string_to_sid(&global_sid_Creator_Owner_Domain, "S-1-3");
+ string_to_sid(&global_sid_Creator_Owner, "S-1-3-0");
+ string_to_sid(&global_sid_Creator_Group, "S-1-3-1");
+ string_to_sid(&global_sid_NT_Authority, "S-1-5");
+ string_to_sid(&global_sid_NULL, "S-1-0-0");
+ string_to_sid(&global_sid_Authenticated_Users, "S-1-5-11");
+ string_to_sid(&global_sid_Network, "S-1-5-2");
+ string_to_sid(&global_sid_Anonymous, "S-1-5-7");
+
+ /* Create the anon token. */
+ sid_copy( &anonymous_token.user_sids[0], &global_sid_World);
+ sid_copy( &anonymous_token.user_sids[1], &global_sid_Network);
+ sid_copy( &anonymous_token.user_sids[2], &global_sid_Anonymous);
+}
+
+/**************************************************************************
+ Turns a domain SID into a name, returned in the nt_domain argument.
+***************************************************************************/
+
+BOOL map_domain_sid_to_name(DOM_SID *sid, char *nt_domain)
+{
+ fstring sid_str;
+ int i = 0;
+
+ sid_to_string(sid_str, sid);
+
+ if (!sid_name_map_initialized)
+ init_sid_name_map();
+
+ DEBUG(5,("map_domain_sid_to_name: %s\n", sid_str));
+
+ if (nt_domain == NULL)
+ return False;
+
+ while (sid_name_map[i].sid != NULL) {
+ sid_to_string(sid_str, sid_name_map[i].sid);
+ DEBUG(5,("map_domain_sid_to_name: compare: %s\n", sid_str));
+ if (sid_equal(sid_name_map[i].sid, sid)) {
+ fstrcpy(nt_domain, sid_name_map[i].name);
+ DEBUG(5,("map_domain_sid_to_name: found '%s'\n", nt_domain));
+ return True;
+ }
+ i++;
+ }
+
+ DEBUG(5,("map_domain_sid_to_name: mapping for %s not found\n", sid_str));
+
+ return False;
+}
+
+/**************************************************************************
+ Looks up a known username from one of the known domains.
+***************************************************************************/
+
+BOOL lookup_known_rid(DOM_SID *sid, uint32 rid, char *name, enum SID_NAME_USE *psid_name_use)
+{
+ int i = 0;
+ struct sid_name_map_info *psnm;
+
+ if (!sid_name_map_initialized)
+ init_sid_name_map();
+
+ for(i = 0; sid_name_map[i].sid != NULL; i++) {
+ psnm = &sid_name_map[i];
+ if(sid_equal(psnm->sid, sid)) {
+ int j;
+ for(j = 0; psnm->known_users && psnm->known_users[j].known_user_name != NULL; j++) {
+ if(rid == psnm->known_users[j].rid) {
+ DEBUG(5,("lookup_builtin_rid: rid = %u, domain = '%s', user = '%s'\n",
+ (unsigned int)rid, psnm->name, psnm->known_users[j].known_user_name ));
+ fstrcpy( name, psnm->known_users[j].known_user_name);
+ *psid_name_use = psnm->known_users[j].sid_name_use;
+ return True;
+ }
+ }
+ }
+ }
+
+ return False;
+}
+
+/**************************************************************************
+ Turns a domain name into a SID.
+ *** side-effect: if the domain name is NULL, it is set to our domain ***
+***************************************************************************/
+
+BOOL map_domain_name_to_sid(DOM_SID *sid, char *nt_domain)
+{
+ int i = 0;
+
+ if (nt_domain == NULL) {
+ DEBUG(5,("map_domain_name_to_sid: mapping NULL domain to our SID.\n"));
+ sid_copy(sid, &global_sam_sid);
+ return True;
+ }
+
+ if (nt_domain[0] == 0) {
+ fstrcpy(nt_domain, global_myname);
+ DEBUG(5,("map_domain_name_to_sid: overriding blank name to %s\n", nt_domain));
+ sid_copy(sid, &global_sam_sid);
+ return True;
+ }
+
+ DEBUG(5,("map_domain_name_to_sid: %s\n", nt_domain));
+
+ if (!sid_name_map_initialized)
+ init_sid_name_map();
+
+ while (sid_name_map[i].name != NULL) {
+ DEBUG(5,("map_domain_name_to_sid: compare: %s\n", sid_name_map[i].name));
+ if (strequal(sid_name_map[i].name, nt_domain)) {
+ fstring sid_str;
+ sid_copy(sid, sid_name_map[i].sid);
+ sid_to_string(sid_str, sid_name_map[i].sid);
+ DEBUG(5,("map_domain_name_to_sid: found %s\n", sid_str));
+ return True;
+ }
+ i++;
+ }
+
+ DEBUG(0,("map_domain_name_to_sid: mapping to %s not found.\n", nt_domain));
+ return False;
+}
+
+/**************************************************************************
+ Splits a name of format \DOMAIN\name or name into its two components.
+ Sets the DOMAIN name to global_myname if it has not been specified.
+***************************************************************************/
+
+void split_domain_name(const char *fullname, char *domain, char *name)
+{
+ pstring full_name;
+ char *p, *sep;
+
+ sep = lp_winbind_separator();
+
+ *domain = *name = '\0';
+
+ if (fullname[0] == sep[0] || fullname[0] == '\\')
+ fullname++;
+
+ pstrcpy(full_name, fullname);
+ p = strchr_m(full_name+1, '\\');
+ if (!p) p = strchr_m(full_name+1, sep[0]);
+
+ if (p != NULL) {
+ *p = 0;
+ fstrcpy(domain, full_name);
+ fstrcpy(name, p+1);
+ } else {
+ fstrcpy(domain, global_myname);
+ fstrcpy(name, full_name);
+ }
+
+ DEBUG(10,("split_domain_name:name '%s' split into domain :'%s' and user :'%s'\n",
+ fullname, domain, name));
+}
+
+/*****************************************************************
+ Convert a SID to an ascii string.
+*****************************************************************/
+
+char *sid_to_string(fstring sidstr_out, DOM_SID *sid)
+{
+ char subauth[16];
+ int i;
+ /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
+ uint32 ia = (sid->id_auth[5]) +
+ (sid->id_auth[4] << 8 ) +
+ (sid->id_auth[3] << 16) +
+ (sid->id_auth[2] << 24);
+
+ slprintf(sidstr_out, sizeof(fstring) - 1, "S-%u-%lu", (unsigned int)sid->sid_rev_num, (unsigned long)ia);
+
+ for (i = 0; i < sid->num_auths; i++) {
+ slprintf(subauth, sizeof(subauth)-1, "-%lu", (unsigned long)sid->sub_auths[i]);
+ fstrcat(sidstr_out, subauth);
+ }
+
+ return sidstr_out;
+}
+
+/*
+ useful function for debug lines
+*/
+const char *sid_string_static(DOM_SID *sid)
+{
+ static fstring sid_str;
+ sid_to_string(sid_str, sid);
+ return sid_str;
+}
+
+/*****************************************************************
+ Convert a string to a SID. Returns True on success, False on fail.
+*****************************************************************/
+
+BOOL string_to_sid(DOM_SID *sidout, const char *sidstr)
+{
+ pstring tok;
+ char *p, *q;
+ /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
+ uint32 ia;
+
+ if (StrnCaseCmp( sidstr, "S-", 2)) {
+ DEBUG(0,("string_to_sid: Sid %s does not start with 'S-'.\n", sidstr));
+ return False;
+ }
+
+ memset((char *)sidout, '\0', sizeof(DOM_SID));
+
+ q = p = strdup(sidstr + 2);
+ if (p == NULL) {
+ DEBUG(0, ("string_to_sid: out of memory!\n"));
+ return False;
+ }
+
+ if (!next_token(&p, tok, "-", sizeof(tok))) {
+ DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr));
+ SAFE_FREE(q);
+ return False;
+ }
+
+ /* Get the revision number. */
+ sidout->sid_rev_num = (uint8)strtoul(tok, NULL, 10);
+
+ if (!next_token(&p, tok, "-", sizeof(tok))) {
+ DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr));
+ SAFE_FREE(q);
+ return False;
+ }
+
+ /* identauth in decimal should be < 2^32 */
+ ia = (uint32)strtoul(tok, NULL, 10);
+
+ /* NOTE - the ia value is in big-endian format. */
+ sidout->id_auth[0] = 0;
+ sidout->id_auth[1] = 0;
+ sidout->id_auth[2] = (ia & 0xff000000) >> 24;
+ sidout->id_auth[3] = (ia & 0x00ff0000) >> 16;
+ sidout->id_auth[4] = (ia & 0x0000ff00) >> 8;
+ sidout->id_auth[5] = (ia & 0x000000ff);
+
+ sidout->num_auths = 0;
+
+ while(next_token(&p, tok, "-", sizeof(tok)) &&
+ sidout->num_auths < MAXSUBAUTHS) {
+ /*
+ * NOTE - the subauths are in native machine-endian format. They
+ * are converted to little-endian when linearized onto the wire.
+ */
+ sid_append_rid(sidout, (uint32)strtoul(tok, NULL, 10));
+ }
+
+ SAFE_FREE(q);
+ return True;
+}
+
+/*****************************************************************
+ Add a rid to the end of a sid
+*****************************************************************/
+
+BOOL sid_append_rid(DOM_SID *sid, uint32 rid)
+{
+ if (sid->num_auths < MAXSUBAUTHS) {
+ sid->sub_auths[sid->num_auths++] = rid;
+ return True;
+ }
+ return False;
+}
+
+/*****************************************************************
+ Removes the last rid from the end of a sid
+*****************************************************************/
+
+BOOL sid_split_rid(DOM_SID *sid, uint32 *rid)
+{
+ if (sid->num_auths > 0) {
+ sid->num_auths--;
+ *rid = sid->sub_auths[sid->num_auths];
+ return True;
+ }
+ return False;
+}
+
+/*****************************************************************
+ Return the last rid from the end of a sid
+*****************************************************************/
+
+BOOL sid_peek_rid(DOM_SID *sid, uint32 *rid)
+{
+ if (sid->num_auths > 0) {
+ *rid = sid->sub_auths[sid->num_auths - 1];
+ return True;
+ }
+ return False;
+}
+
+/*****************************************************************
+ Copies a sid
+*****************************************************************/
+
+void sid_copy(DOM_SID *dst, const DOM_SID *src)
+{
+ int i;
+
+ memset((char *)dst, '\0', sizeof(DOM_SID));
+
+ dst->sid_rev_num = src->sid_rev_num;
+ dst->num_auths = src->num_auths;
+
+ memcpy(&dst->id_auth[0], &src->id_auth[0], sizeof(src->id_auth));
+
+ for (i = 0; i < src->num_auths; i++)
+ dst->sub_auths[i] = src->sub_auths[i];
+}
+
+/*****************************************************************
+ Duplicates a sid - mallocs the target.
+*****************************************************************/
+
+DOM_SID *sid_dup(DOM_SID *src)
+{
+ DOM_SID *dst;
+
+ if(!src)
+ return NULL;
+
+ if((dst = malloc(sizeof(DOM_SID))) != NULL) {
+ memset(dst, '\0', sizeof(DOM_SID));
+ sid_copy( dst, src);
+ }
+
+ return dst;
+}
+
+/*****************************************************************
+ Write a sid out into on-the-wire format.
+*****************************************************************/
+BOOL sid_linearize(char *outbuf, size_t len, DOM_SID *sid)
+{
+ size_t i;
+
+ if (len < sid_size(sid))
+ return False;
+
+ SCVAL(outbuf,0,sid->sid_rev_num);
+ SCVAL(outbuf,1,sid->num_auths);
+ memcpy(&outbuf[2], sid->id_auth, 6);
+ for(i = 0; i < sid->num_auths; i++)
+ SIVAL(outbuf, 8 + (i*4), sid->sub_auths[i]);
+
+ return True;
+}
+
+/*****************************************************************
+ parse a on-the-wire SID to a DOM_SID
+*****************************************************************/
+BOOL sid_parse(char *inbuf, size_t len, DOM_SID *sid)
+{
+ int i;
+ if (len < 8) return False;
+ sid->sid_rev_num = CVAL(inbuf, 0);
+ sid->num_auths = CVAL(inbuf, 1);
+ memcpy(sid->id_auth, inbuf+2, 6);
+ if (len < 8 + sid->num_auths*4) return False;
+ for (i=0;i<sid->num_auths;i++) {
+ sid->sub_auths[i] = IVAL(inbuf, 8+i*4);
+ }
+ return True;
+}
+
+
+/*****************************************************************
+ Compare the auth portion of two sids.
+*****************************************************************/
+int sid_compare_auth(const DOM_SID *sid1, const DOM_SID *sid2)
+{
+ int i;
+
+ if (sid1 == sid2) return 0;
+ if (!sid1) return -1;
+ if (!sid2) return 1;
+
+ if (sid1->sid_rev_num != sid2->sid_rev_num)
+ return sid1->sid_rev_num - sid2->sid_rev_num;
+
+ for (i = 0; i < 6; i++)
+ if (sid1->id_auth[i] != sid2->id_auth[i])
+ return sid1->id_auth[i] - sid2->id_auth[i];
+
+ return 0;
+}
+
+/*****************************************************************
+ Compare two sids.
+*****************************************************************/
+int sid_compare(const DOM_SID *sid1, const DOM_SID *sid2)
+{
+ int i;
+
+ if (sid1 == sid2) return 0;
+ if (!sid1) return -1;
+ if (!sid2) return 1;
+
+ /* compare most likely different rids, first: i.e start at end */
+ if (sid1->num_auths != sid2->num_auths)
+ return sid1->num_auths - sid2->num_auths;
+
+ for (i = sid1->num_auths-1; i >= 0; --i)
+ if (sid1->sub_auths[i] != sid2->sub_auths[i])
+ return sid1->sub_auths[i] - sid2->sub_auths[i];
+
+ return sid_compare_auth(sid1, sid2);
+}
+
+/*****************************************************************
+see if 2 SIDs are in the same domain
+this just compares the leading sub-auths
+*****************************************************************/
+int sid_compare_domain(const DOM_SID *sid1, const DOM_SID *sid2)
+{
+ int n, i;
+
+ n = MIN(sid1->num_auths, sid2->num_auths);
+
+ for (i = n-1; i >= 0; --i)
+ if (sid1->sub_auths[i] != sid2->sub_auths[i])
+ return sid1->sub_auths[i] - sid2->sub_auths[i];
+
+ return sid_compare_auth(sid1, sid2);
+}
+
+/*****************************************************************
+ Compare two sids.
+*****************************************************************/
+BOOL sid_equal(const DOM_SID *sid1, const DOM_SID *sid2)
+{
+ return sid_compare(sid1, sid2) == 0;
+}
+
+
+/*****************************************************************
+ Check if the SID is our domain SID (S-1-5-21-x-y-z).
+*****************************************************************/
+BOOL sid_check_is_domain(const DOM_SID *sid)
+{
+ return sid_equal(sid, &global_sam_sid);
+}
+
+
+/*****************************************************************
+ Check if the SID is the builtin SID (S-1-5-32).
+*****************************************************************/
+BOOL sid_check_is_builtin(const DOM_SID *sid)
+{
+ return sid_equal(sid, &global_sid_Builtin);
+}
+
+
+/*****************************************************************
+ Check if the SID is our domain SID (S-1-5-21-x-y-z).
+*****************************************************************/
+BOOL sid_check_is_in_our_domain(const DOM_SID *sid)
+{
+ DOM_SID dom_sid;
+ uint32 rid;
+
+ sid_copy(&dom_sid, sid);
+ sid_split_rid(&dom_sid, &rid);
+
+ return sid_equal(&dom_sid, &global_sam_sid);
+}
+
+/*****************************************************************
+ Check if the SID is our domain SID (S-1-5-21-x-y-z).
+*****************************************************************/
+BOOL sid_check_is_in_builtin(const DOM_SID *sid)
+{
+ DOM_SID dom_sid;
+ uint32 rid;
+
+ sid_copy(&dom_sid, sid);
+ sid_split_rid(&dom_sid, &rid);
+
+ return sid_equal(&dom_sid, &global_sid_Builtin);
+}
+
+
+/*****************************************************************
+ Calculates size of a sid.
+*****************************************************************/
+
+size_t sid_size(DOM_SID *sid)
+{
+ if (sid == NULL)
+ return 0;
+
+ return sid->num_auths * sizeof(uint32) + 8;
+}
+
+/*****************************************************************
+ Returns true if SID is internal (and non-mappable).
+*****************************************************************/
+
+BOOL non_mappable_sid(DOM_SID *sid)
+{
+ DOM_SID dom;
+ uint32 rid;
+
+ sid_copy(&dom, sid);
+ sid_split_rid(&dom, &rid);
+
+ if (sid_equal(&dom, &global_sid_Builtin))
+ return True;
+
+ if (sid_equal(&dom, &global_sid_Creator_Owner_Domain))
+ return True;
+
+ if (sid_equal(&dom, &global_sid_NT_Authority))
+ return True;
+
+ return False;
+}
+
+/*
+ return the binary string representation of a DOM_SID
+ caller must free
+*/
+char *sid_binstring(DOM_SID *sid)
+{
+ char *buf, *s;
+ int len = sid_size(sid);
+ buf = malloc(len);
+ if (!buf) return NULL;
+ sid_linearize(buf, len, sid);
+ s = binary_string(buf, len);
+ free(buf);
+ return s;
+}
+
diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c
new file mode 100644
index 0000000000..af3182264d
--- /dev/null
+++ b/source3/lib/util_sock.c
@@ -0,0 +1,1340 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Tim Potter 2000-2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifdef WITH_SSL
+#include <openssl/ssl.h>
+#undef Realloc /* SSLeay defines this and samba has a function of this name */
+extern SSL *ssl;
+extern int sslFd;
+#endif /* WITH_SSL */
+
+/* the last IP received from */
+struct in_addr lastip;
+
+/* the last port received from */
+int lastport=0;
+
+int smb_read_error = 0;
+
+/****************************************************************************
+ Determine if a file descriptor is in fact a socket.
+****************************************************************************/
+
+BOOL is_a_socket(int fd)
+{
+ int v,l;
+ l = sizeof(int);
+ return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
+}
+
+enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
+
+typedef struct smb_socket_option
+{
+ char *name;
+ int level;
+ int option;
+ int value;
+ int opttype;
+} smb_socket_option;
+
+smb_socket_option socket_options[] = {
+ {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
+ {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
+ {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
+#ifdef TCP_NODELAY
+ {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
+#endif
+#ifdef IPTOS_LOWDELAY
+ {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
+#endif
+#ifdef IPTOS_THROUGHPUT
+ {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
+#endif
+#ifdef SO_REUSEPORT
+ {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
+#endif
+#ifdef SO_SNDBUF
+ {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
+#endif
+#ifdef SO_RCVBUF
+ {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
+#endif
+#ifdef SO_SNDLOWAT
+ {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
+#endif
+#ifdef SO_RCVLOWAT
+ {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
+#endif
+#ifdef SO_SNDTIMEO
+ {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
+#endif
+#ifdef SO_RCVTIMEO
+ {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
+#endif
+ {NULL,0,0,0,0}};
+
+/****************************************************************************
+ Print socket options.
+****************************************************************************/
+static void print_socket_options(int s)
+{
+ int value, vlen = 4;
+ smb_socket_option *p = &socket_options[0];
+
+ for (; p->name != NULL; p++) {
+ if (getsockopt(s, p->level, p->option, (void *)&value, &vlen) == -1) {
+ DEBUG(5,("Could not test socket option %s.\n", p->name));
+ } else {
+ DEBUG(5,("socket option %s = %d\n",p->name,value));
+ }
+ }
+ }
+
+/****************************************************************************
+ Set user socket options.
+****************************************************************************/
+
+void set_socket_options(int fd, char *options)
+{
+ fstring tok;
+
+ while (next_token(&options,tok," \t,", sizeof(tok))) {
+ int ret=0,i;
+ int value = 1;
+ char *p;
+ BOOL got_value = False;
+
+ if ((p = strchr_m(tok,'='))) {
+ *p = 0;
+ value = atoi(p+1);
+ got_value = True;
+ }
+
+ for (i=0;socket_options[i].name;i++)
+ if (strequal(socket_options[i].name,tok))
+ break;
+
+ if (!socket_options[i].name) {
+ DEBUG(0,("Unknown socket option %s\n",tok));
+ continue;
+ }
+
+ switch (socket_options[i].opttype) {
+ case OPT_BOOL:
+ case OPT_INT:
+ ret = setsockopt(fd,socket_options[i].level,
+ socket_options[i].option,(char *)&value,sizeof(int));
+ break;
+
+ case OPT_ON:
+ if (got_value)
+ DEBUG(0,("syntax error - %s does not take a value\n",tok));
+
+ {
+ int on = socket_options[i].value;
+ ret = setsockopt(fd,socket_options[i].level,
+ socket_options[i].option,(char *)&on,sizeof(int));
+ }
+ break;
+ }
+
+ if (ret != 0)
+ DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok, strerror(errno) ));
+ }
+
+ print_socket_options(fd);
+}
+
+/****************************************************************************
+ Read from a socket.
+****************************************************************************/
+
+ssize_t read_udp_socket(int fd,char *buf,size_t len)
+{
+ ssize_t ret;
+ struct sockaddr_in sock;
+ socklen_t socklen = sizeof(sock);
+
+ memset((char *)&sock,'\0',socklen);
+ memset((char *)&lastip,'\0',sizeof(lastip));
+ ret = (ssize_t)recvfrom(fd,buf,len,0,(struct sockaddr *)&sock,&socklen);
+ if (ret <= 0) {
+ DEBUG(2,("read socket failed. ERRNO=%s\n",strerror(errno)));
+ return(0);
+ }
+
+ lastip = sock.sin_addr;
+ lastport = ntohs(sock.sin_port);
+
+ DEBUG(10,("read_udp_socket: lastip %s lastport %d read: %d\n",
+ inet_ntoa(lastip), lastport, ret));
+
+ return(ret);
+}
+
+/*******************************************************************
+ checks if read data is outstanding.
+ ********************************************************************/
+int read_data_outstanding(int fd, unsigned int time_out)
+{
+ int selrtn;
+ fd_set fds;
+ struct timeval timeout;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ timeout.tv_sec = (time_t) (time_out / 1000);
+ timeout.tv_usec = (long)(1000 * (time_out % 1000));
+
+ selrtn = sys_select_intr(fd + 1, &fds, NULL, NULL, &timeout);
+
+ if (selrtn <= 0)
+ {
+ return selrtn;
+ }
+ return FD_ISSET(fd, &fds) ? 1 : 0;
+}
+
+/****************************************************************************
+ Read data from a socket with a timout in msec.
+ mincount = if timeout, minimum to read before returning
+ maxcount = number to be read.
+ time_out = timeout in milliseconds
+****************************************************************************/
+
+static ssize_t read_socket_with_timeout(int fd,char *buf,size_t mincnt,size_t maxcnt,unsigned int time_out)
+{
+ fd_set fds;
+ int selrtn;
+ ssize_t readret;
+ size_t nread = 0;
+ struct timeval timeout;
+
+ /* just checking .... */
+ if (maxcnt <= 0)
+ return(0);
+
+ smb_read_error = 0;
+
+ /* Blocking read */
+ if (time_out <= 0) {
+ if (mincnt == 0) mincnt = maxcnt;
+
+ while (nread < mincnt) {
+#ifdef WITH_SSL
+ if (fd == sslFd) {
+ readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+ } else {
+ readret = read(fd, buf + nread, maxcnt - nread);
+ }
+#else /* WITH_SSL */
+ readret = read(fd, buf + nread, maxcnt - nread);
+#endif /* WITH_SSL */
+
+ if (readret == 0) {
+ DEBUG(5,("read_socket_with_timeout: blocking read. EOF from client.\n"));
+ smb_read_error = READ_EOF;
+ return -1;
+ }
+
+ if (readret == -1) {
+ DEBUG(0,("read_socket_with_timeout: read error = %s.\n", strerror(errno) ));
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+ nread += readret;
+ }
+ return((ssize_t)nread);
+ }
+
+ /* Most difficult - timeout read */
+ /* If this is ever called on a disk file and
+ mincnt is greater then the filesize then
+ system performance will suffer severely as
+ select always returns true on disk files */
+
+ /* Set initial timeout */
+ timeout.tv_sec = (time_t)(time_out / 1000);
+ timeout.tv_usec = (long)(1000 * (time_out % 1000));
+
+ for (nread=0; nread < mincnt; ) {
+ FD_ZERO(&fds);
+ FD_SET(fd,&fds);
+
+ selrtn = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout);
+
+ /* Check if error */
+ if (selrtn == -1) {
+ /* something is wrong. Maybe the socket is dead? */
+ DEBUG(0,("read_socket_with_timeout: timeout read. select error = %s.\n", strerror(errno) ));
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+
+ /* Did we timeout ? */
+ if (selrtn == 0) {
+ DEBUG(10,("read_socket_with_timeout: timeout read. select timed out.\n"));
+ smb_read_error = READ_TIMEOUT;
+ return -1;
+ }
+
+#ifdef WITH_SSL
+ if (fd == sslFd) {
+ readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+ }else{
+ readret = read(fd, buf + nread, maxcnt - nread);
+ }
+#else /* WITH_SSL */
+ readret = read(fd, buf+nread, maxcnt-nread);
+#endif /* WITH_SSL */
+
+ if (readret == 0) {
+ /* we got EOF on the file descriptor */
+ DEBUG(5,("read_socket_with_timeout: timeout read. EOF from client.\n"));
+ smb_read_error = READ_EOF;
+ return -1;
+ }
+
+ if (readret == -1) {
+ /* the descriptor is probably dead */
+ DEBUG(0,("read_socket_with_timeout: timeout read. read error = %s.\n", strerror(errno) ));
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+
+ nread += readret;
+ }
+
+ /* Return the number we got */
+ return (ssize_t)nread;
+}
+
+/****************************************************************************
+ Read data from a fd with a timout in msec.
+ mincount = if timeout, minimum to read before returning
+ maxcount = number to be read.
+ time_out = timeout in milliseconds
+****************************************************************************/
+
+ssize_t read_with_timeout(int fd, char *buf, size_t mincnt, size_t maxcnt,
+ unsigned int time_out)
+{
+ ssize_t readret;
+ size_t nread = 0;
+
+ /* just checking .... */
+ if (maxcnt <= 0)
+ return(0);
+
+ /* Blocking read */
+ if (time_out <= 0) {
+ if (mincnt == 0) mincnt = maxcnt;
+
+ while (nread < mincnt) {
+#ifdef WITH_SSL
+ if(fd == sslFd){
+ readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+ }else{
+ readret = read(fd, buf + nread, maxcnt - nread);
+ }
+#else /* WITH_SSL */
+ readret = read(fd, buf + nread, maxcnt - nread);
+#endif /* WITH_SSL */
+
+ if (readret <= 0)
+ return readret;
+
+ nread += readret;
+ }
+ return((ssize_t)nread);
+ }
+
+ /* Most difficult - timeout read */
+ /* If this is ever called on a disk file and
+ mincnt is greater then the filesize then
+ system performance will suffer severely as
+ select always returns true on disk files */
+
+ for (nread=0; nread < mincnt; ) {
+ int selrtn = read_data_outstanding(fd, time_out);
+
+ if(selrtn <= 0)
+ return selrtn;
+
+#ifdef WITH_SSL
+ if(fd == sslFd){
+ readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+ }else{
+ readret = read(fd, buf + nread, maxcnt - nread);
+ }
+#else /* WITH_SSL */
+ readret = read(fd, buf+nread, maxcnt-nread);
+#endif /* WITH_SSL */
+
+ if (readret <= 0)
+ return readret;
+
+ nread += readret;
+ }
+
+ /* Return the number we got */
+ return((ssize_t)nread);
+}
+
+/****************************************************************************
+send a keepalive packet (rfc1002)
+****************************************************************************/
+
+BOOL send_keepalive(int client)
+{
+ unsigned char buf[4];
+
+ buf[0] = SMBkeepalive;
+ buf[1] = buf[2] = buf[3] = 0;
+
+ return(write_socket_data(client,(char *)buf,4) == 4);
+}
+
+/****************************************************************************
+ read data from the client, reading exactly N bytes.
+****************************************************************************/
+
+ssize_t read_data(int fd,char *buffer,size_t N)
+{
+ ssize_t ret;
+ size_t total=0;
+
+ smb_read_error = 0;
+
+ while (total < N)
+ {
+#ifdef WITH_SSL
+ if(fd == sslFd){
+ ret = SSL_read(ssl, buffer + total, N - total);
+ }else{
+ ret = read(fd,buffer + total,N - total);
+ }
+#else /* WITH_SSL */
+ ret = read(fd,buffer + total,N - total);
+#endif /* WITH_SSL */
+
+ if (ret == 0)
+ {
+ DEBUG(10,("read_data: read of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) ));
+ smb_read_error = READ_EOF;
+ return 0;
+ }
+ if (ret == -1)
+ {
+ DEBUG(0,("read_data: read failure for %d. Error = %s\n", (int)(N - total), strerror(errno) ));
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+ total += ret;
+ }
+ return (ssize_t)total;
+}
+
+/****************************************************************************
+ Read data from a socket, reading exactly N bytes.
+****************************************************************************/
+
+static ssize_t read_socket_data(int fd,char *buffer,size_t N)
+{
+ ssize_t ret;
+ size_t total=0;
+
+ smb_read_error = 0;
+
+ while (total < N)
+ {
+#ifdef WITH_SSL
+ if(fd == sslFd){
+ ret = SSL_read(ssl, buffer + total, N - total);
+ }else{
+ ret = read(fd,buffer + total,N - total);
+ }
+#else /* WITH_SSL */
+ ret = read(fd,buffer + total,N - total);
+#endif /* WITH_SSL */
+
+ if (ret == 0)
+ {
+ DEBUG(10,("read_socket_data: recv of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) ));
+ smb_read_error = READ_EOF;
+ return 0;
+ }
+ if (ret == -1)
+ {
+ DEBUG(0,("read_socket_data: recv failure for %d. Error = %s\n", (int)(N - total), strerror(errno) ));
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+ total += ret;
+ }
+ return (ssize_t)total;
+}
+
+/****************************************************************************
+ Write data to a fd.
+****************************************************************************/
+
+ssize_t write_data(int fd,char *buffer,size_t N)
+{
+ size_t total=0;
+ ssize_t ret;
+
+ while (total < N)
+ {
+#ifdef WITH_SSL
+ if(fd == sslFd){
+ ret = SSL_write(ssl,buffer + total,N - total);
+ }else{
+ ret = write(fd,buffer + total,N - total);
+ }
+#else /* WITH_SSL */
+ ret = write(fd,buffer + total,N - total);
+#endif /* WITH_SSL */
+
+ if (ret == -1) {
+ DEBUG(0,("write_data: write failure. Error = %s\n", strerror(errno) ));
+ return -1;
+ }
+ if (ret == 0) return total;
+
+ total += ret;
+ }
+ return (ssize_t)total;
+}
+
+/****************************************************************************
+ Write data to a socket - use send rather than write.
+****************************************************************************/
+
+ssize_t write_socket_data(int fd,char *buffer,size_t N)
+{
+ size_t total=0;
+ ssize_t ret;
+
+ while (total < N)
+ {
+#ifdef WITH_SSL
+ if(fd == sslFd){
+ ret = SSL_write(ssl,buffer + total,N - total);
+ }else{
+ ret = send(fd,buffer + total,N - total, 0);
+ }
+#else /* WITH_SSL */
+ ret = send(fd,buffer + total,N - total,0);
+#endif /* WITH_SSL */
+
+ if (ret == -1) {
+ DEBUG(0,("write_socket_data: write failure. Error = %s\n", strerror(errno) ));
+ return -1;
+ }
+ if (ret == 0) return total;
+
+ total += ret;
+ }
+ return (ssize_t)total;
+}
+
+/****************************************************************************
+write to a socket
+****************************************************************************/
+
+ssize_t write_socket(int fd,char *buf,size_t len)
+{
+ ssize_t ret=0;
+
+ DEBUG(6,("write_socket(%d,%d)\n",fd,(int)len));
+ ret = write_socket_data(fd,buf,len);
+
+ DEBUG(6,("write_socket(%d,%d) wrote %d\n",fd,(int)len,(int)ret));
+ if(ret <= 0)
+ DEBUG(0,("write_socket: Error writing %d bytes to socket %d: ERRNO = %s\n",
+ (int)len, fd, strerror(errno) ));
+
+ return(ret);
+}
+
+/****************************************************************************
+read 4 bytes of a smb packet and return the smb length of the packet
+store the result in the buffer
+This version of the function will return a length of zero on receiving
+a keepalive packet.
+timeout is in milliseconds.
+****************************************************************************/
+
+static ssize_t read_smb_length_return_keepalive(int fd,char *inbuf,unsigned int timeout)
+{
+ ssize_t len=0;
+ int msg_type;
+ BOOL ok = False;
+
+ while (!ok)
+ {
+ if (timeout > 0)
+ ok = (read_socket_with_timeout(fd,inbuf,4,4,timeout) == 4);
+ else
+ ok = (read_socket_data(fd,inbuf,4) == 4);
+
+ if (!ok)
+ return(-1);
+
+ len = smb_len(inbuf);
+ msg_type = CVAL(inbuf,0);
+
+ if (msg_type == SMBkeepalive)
+ DEBUG(5,("Got keepalive packet\n"));
+ }
+
+ DEBUG(10,("got smb length of %d\n",len));
+
+ return(len);
+}
+
+/****************************************************************************
+read 4 bytes of a smb packet and return the smb length of the packet
+store the result in the buffer. This version of the function will
+never return a session keepalive (length of zero).
+timeout is in milliseconds.
+****************************************************************************/
+
+ssize_t read_smb_length(int fd,char *inbuf,unsigned int timeout)
+{
+ ssize_t len;
+
+ for(;;)
+ {
+ len = read_smb_length_return_keepalive(fd, inbuf, timeout);
+
+ if(len < 0)
+ return len;
+
+ /* Ignore session keepalives. */
+ if(CVAL(inbuf,0) != SMBkeepalive)
+ break;
+ }
+
+ DEBUG(10,("read_smb_length: got smb length of %d\n",len));
+
+ return len;
+}
+
+/****************************************************************************
+ read an smb from a fd. Note that the buffer *MUST* be of size
+ BUFFER_SIZE+SAFETY_MARGIN.
+ The timeout is in milliseconds.
+ This function will return on a
+ receipt of a session keepalive packet.
+****************************************************************************/
+
+BOOL receive_smb(int fd,char *buffer, unsigned int timeout)
+{
+ ssize_t len,ret;
+
+ smb_read_error = 0;
+
+ memset(buffer,'\0',smb_size + 100);
+
+ len = read_smb_length_return_keepalive(fd,buffer,timeout);
+ if (len < 0) {
+ DEBUG(10,("receive_smb: length < 0!\n"));
+
+ /*
+ * Correct fix. smb_read_error may have already been
+ * set. Only set it here if not already set. Global
+ * variables still suck :-). JRA.
+ */
+
+ if (smb_read_error == 0)
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+
+ /*
+ * A WRITEX with CAP_LARGE_WRITEX can be 64k worth of data plus 65 bytes
+ * of header. Don't print the error if this fits.... JRA.
+ */
+
+ if (len > (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE)) {
+ DEBUG(0,("Invalid packet length! (%d bytes).\n",len));
+ if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) {
+
+ /*
+ * Correct fix. smb_read_error may have already been
+ * set. Only set it here if not already set. Global
+ * variables still suck :-). JRA.
+ */
+
+ if (smb_read_error == 0)
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+ }
+
+ if(len > 0) {
+ ret = read_socket_data(fd,buffer+4,len);
+ if (ret != len) {
+ if (smb_read_error == 0)
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+ }
+
+ return(True);
+}
+
+/****************************************************************************
+ read an smb from a fd ignoring all keepalive packets. Note that the buffer
+ *MUST* be of size BUFFER_SIZE+SAFETY_MARGIN.
+ The timeout is in milliseconds
+
+ This is exactly the same as receive_smb except that it never returns
+ a session keepalive packet (just as receive_smb used to do).
+ receive_smb was changed to return keepalives as the oplock processing means this call
+ should never go into a blocking read.
+****************************************************************************/
+
+BOOL client_receive_smb(int fd,char *buffer, unsigned int timeout)
+{
+ BOOL ret;
+
+ for(;;)
+ {
+ ret = receive_smb(fd, buffer, timeout);
+
+ if (!ret)
+ {
+ DEBUG(10,("client_receive_smb failed\n"));
+ show_msg(buffer);
+ return ret;
+ }
+
+ /* Ignore session keepalive packets. */
+ if(CVAL(buffer,0) != SMBkeepalive)
+ break;
+ }
+ show_msg(buffer);
+ return ret;
+}
+
+/****************************************************************************
+ send an smb to a fd
+****************************************************************************/
+
+BOOL send_smb(int fd,char *buffer)
+{
+ size_t len;
+ size_t nwritten=0;
+ ssize_t ret;
+ len = smb_len(buffer) + 4;
+
+ while (nwritten < len) {
+ ret = write_socket(fd,buffer+nwritten,len - nwritten);
+ if (ret <= 0) {
+ DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n",
+ (int)len,(int)ret, strerror(errno) ));
+ return False;
+ }
+ nwritten += ret;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+send a single packet to a port on another machine
+****************************************************************************/
+
+BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type)
+{
+ BOOL ret;
+ int out_fd;
+ struct sockaddr_in sock_out;
+
+ /* create a socket to write to */
+ out_fd = socket(AF_INET, type, 0);
+ if (out_fd == -1)
+ {
+ DEBUG(0,("socket failed"));
+ return False;
+ }
+
+ /* set the address and port */
+ memset((char *)&sock_out,'\0',sizeof(sock_out));
+ putip((char *)&sock_out.sin_addr,(char *)&ip);
+ sock_out.sin_port = htons( port );
+ sock_out.sin_family = AF_INET;
+
+ if (DEBUGLEVEL > 0)
+ DEBUG(3,("sending a packet of len %d to (%s) on port %d of type %s\n",
+ len,inet_ntoa(ip),port,type==SOCK_DGRAM?"DGRAM":"STREAM"));
+
+ /* send it */
+ ret = (sendto(out_fd,buf,len,0,(struct sockaddr *)&sock_out,sizeof(sock_out)) >= 0);
+
+ if (!ret)
+ DEBUG(0,("Packet send to %s(%d) failed ERRNO=%s\n",
+ inet_ntoa(ip),port,strerror(errno)));
+
+ close(out_fd);
+ return(ret);
+}
+
+/****************************************************************************
+ Open a socket of the specified type, port, and address for incoming data.
+****************************************************************************/
+
+int open_socket_in( int type, int port, int dlevel, uint32 socket_addr, BOOL rebind )
+{
+ struct sockaddr_in sock;
+ int res;
+
+ memset( (char *)&sock, '\0', sizeof(sock) );
+
+#ifdef HAVE_SOCK_SIN_LEN
+ sock.sin_len = sizeof(sock);
+#endif
+ sock.sin_port = htons( port );
+ sock.sin_family = AF_INET;
+ sock.sin_addr.s_addr = socket_addr;
+
+ res = socket( AF_INET, type, 0 );
+ if( res == -1 ) {
+ if( DEBUGLVL(0) ) {
+ dbgtext( "open_socket_in(): socket() call failed: " );
+ dbgtext( "%s\n", strerror( errno ) );
+ }
+ return -1;
+ }
+
+ /* This block sets/clears the SO_REUSEADDR and possibly SO_REUSEPORT. */
+ {
+ int val = rebind ? 1 : 0;
+ if( setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val)) == -1 ) {
+ if( DEBUGLVL( dlevel ) ) {
+ dbgtext( "open_socket_in(): setsockopt: " );
+ dbgtext( "SO_REUSEADDR = %s ", val?"True":"False" );
+ dbgtext( "on port %d failed ", port );
+ dbgtext( "with error = %s\n", strerror(errno) );
+ }
+ }
+#ifdef SO_REUSEPORT
+ if( setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val)) == -1 ) {
+ if( DEBUGLVL( dlevel ) ) {
+ dbgtext( "open_socket_in(): setsockopt: ");
+ dbgtext( "SO_REUSEPORT = %s ", val?"True":"False" );
+ dbgtext( "on port %d failed ", port );
+ dbgtext( "with error = %s\n", strerror(errno) );
+ }
+ }
+#endif /* SO_REUSEPORT */
+ }
+
+ /* now we've got a socket - we need to bind it */
+ if( bind( res, (struct sockaddr *)&sock, sizeof(sock) ) == -1 ) {
+ if( DEBUGLVL(dlevel) && (port == SMB_PORT || port == NMB_PORT) ) {
+ dbgtext( "bind failed on port %d ", port );
+ dbgtext( "socket_addr = %s.\n", inet_ntoa( sock.sin_addr ) );
+ dbgtext( "Error = %s\n", strerror(errno) );
+ }
+ close( res );
+ return( -1 );
+ }
+
+ DEBUG( 3, ( "bind succeeded on port %d\n", port ) );
+
+ return( res );
+ }
+
+/****************************************************************************
+ create an outgoing socket. timeout is in milliseconds.
+ **************************************************************************/
+
+int open_socket_out(int type, struct in_addr *addr, int port ,int timeout)
+{
+ struct sockaddr_in sock_out;
+ int res,ret;
+ int connect_loop = 250; /* 250 milliseconds */
+ int loops = (timeout) / connect_loop;
+
+ /* create a socket to write to */
+ res = socket(PF_INET, type, 0);
+ if (res == -1)
+ { DEBUG(0,("socket error\n")); return -1; }
+
+ if (type != SOCK_STREAM) return(res);
+
+ memset((char *)&sock_out,'\0',sizeof(sock_out));
+ putip((char *)&sock_out.sin_addr,(char *)addr);
+
+ sock_out.sin_port = htons( port );
+ sock_out.sin_family = PF_INET;
+
+ /* set it non-blocking */
+ set_blocking(res,False);
+
+ DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port));
+
+ /* and connect it to the destination */
+connect_again:
+ ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out));
+
+ /* Some systems return EAGAIN when they mean EINPROGRESS */
+ if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+ errno == EAGAIN) && loops--) {
+ msleep(connect_loop);
+ goto connect_again;
+ }
+
+ if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+ errno == EAGAIN)) {
+ DEBUG(1,("timeout connecting to %s:%d\n",inet_ntoa(*addr),port));
+ close(res);
+ return -1;
+ }
+
+#ifdef EISCONN
+ if (ret < 0 && errno == EISCONN) {
+ errno = 0;
+ ret = 0;
+ }
+#endif
+
+ if (ret < 0) {
+ DEBUG(2,("error connecting to %s:%d (%s)\n",
+ inet_ntoa(*addr),port,strerror(errno)));
+ close(res);
+ return -1;
+ }
+
+ /* set it blocking again */
+ set_blocking(res,True);
+
+ return res;
+}
+
+/*
+ open a connected UDP socket to host on port
+*/
+int open_udp_socket(const char *host, int port)
+{
+ int type = SOCK_DGRAM;
+ struct sockaddr_in sock_out;
+ int res;
+ struct in_addr *addr;
+
+ addr = interpret_addr2(host);
+
+ res = socket(PF_INET, type, 0);
+ if (res == -1) {
+ return -1;
+ }
+
+ memset((char *)&sock_out,'\0',sizeof(sock_out));
+ putip((char *)&sock_out.sin_addr,(char *)addr);
+ sock_out.sin_port = htons(port);
+ sock_out.sin_family = PF_INET;
+
+ if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))) {
+ close(res);
+ return -1;
+ }
+
+ return res;
+}
+
+
+/* the following 3 client_*() functions are nasty ways of allowing
+ some generic functions to get info that really should be hidden in
+ particular modules */
+static int client_fd = -1;
+
+void client_setfd(int fd)
+{
+ client_fd = fd;
+}
+
+char *client_name(void)
+{
+ return get_socket_name(client_fd);
+}
+
+char *client_addr(void)
+{
+ return get_socket_addr(client_fd);
+}
+
+/*******************************************************************
+ matchname - determine if host name matches IP address. Used to
+ confirm a hostname lookup to prevent spoof attacks
+ ******************************************************************/
+static BOOL matchname(char *remotehost,struct in_addr addr)
+{
+ struct hostent *hp;
+ int i;
+
+ if ((hp = sys_gethostbyname(remotehost)) == 0) {
+ DEBUG(0,("sys_gethostbyname(%s): lookup failure.\n", remotehost));
+ return False;
+ }
+
+ /*
+ * Make sure that gethostbyname() returns the "correct" host name.
+ * Unfortunately, gethostbyname("localhost") sometimes yields
+ * "localhost.domain". Since the latter host name comes from the
+ * local DNS, we just have to trust it (all bets are off if the local
+ * DNS is perverted). We always check the address list, though.
+ */
+
+ if (strcasecmp(remotehost, hp->h_name)
+ && strcasecmp(remotehost, "localhost")) {
+ DEBUG(0,("host name/name mismatch: %s != %s\n",
+ remotehost, hp->h_name));
+ return False;
+ }
+
+ /* Look up the host address in the address list we just got. */
+ for (i = 0; hp->h_addr_list[i]; i++) {
+ if (memcmp(hp->h_addr_list[i], (caddr_t) & addr, sizeof(addr)) == 0)
+ return True;
+ }
+
+ /*
+ * The host name does not map to the original host address. Perhaps
+ * someone has compromised a name server. More likely someone botched
+ * it, but that could be dangerous, too.
+ */
+
+ DEBUG(0,("host name/address mismatch: %s != %s\n",
+ inet_ntoa(addr), hp->h_name));
+ return False;
+}
+
+
+/*******************************************************************
+ return the DNS name of the remote end of a socket
+ ******************************************************************/
+char *get_socket_name(int fd)
+{
+ static pstring name_buf;
+ static fstring addr_buf;
+ struct hostent *hp;
+ struct in_addr addr;
+ char *p;
+
+ /* reverse lookups can be *very* expensive, and in many
+ situations won't work because many networks don't link dhcp
+ with dns. To avoid the delay we avoid the lookup if
+ possible */
+ if (!lp_hostname_lookups()) {
+ return get_socket_addr(fd);
+ }
+
+ p = get_socket_addr(fd);
+
+ /* it might be the same as the last one - save some DNS work */
+ if (strcmp(p, addr_buf) == 0) return name_buf;
+
+ pstrcpy(name_buf,"UNKNOWN");
+ if (fd == -1) return name_buf;
+
+ fstrcpy(addr_buf, p);
+
+ addr = *interpret_addr2(p);
+
+ /* Look up the remote host name. */
+ if ((hp = gethostbyaddr((char *)&addr.s_addr, sizeof(addr.s_addr), AF_INET)) == 0) {
+ DEBUG(1,("Gethostbyaddr failed for %s\n",p));
+ pstrcpy(name_buf, p);
+ } else {
+ pstrcpy(name_buf,(char *)hp->h_name);
+ if (!matchname(name_buf, addr)) {
+ DEBUG(0,("Matchname failed on %s %s\n",name_buf,p));
+ pstrcpy(name_buf,"UNKNOWN");
+ }
+ }
+
+ alpha_strcpy(name_buf, name_buf, "_-.", sizeof(name_buf));
+ if (strstr(name_buf,"..")) {
+ pstrcpy(name_buf, "UNKNOWN");
+ }
+
+ return name_buf;
+}
+
+/*******************************************************************
+ return the IP addr of the remote end of a socket as a string
+ ******************************************************************/
+char *get_socket_addr(int fd)
+{
+ struct sockaddr sa;
+ struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
+ int length = sizeof(sa);
+ static fstring addr_buf;
+
+ fstrcpy(addr_buf,"0.0.0.0");
+
+ if (fd == -1) {
+ return addr_buf;
+ }
+
+ if (getpeername(fd, &sa, &length) < 0) {
+ DEBUG(0,("getpeername failed. Error was %s\n", strerror(errno) ));
+ return addr_buf;
+ }
+
+ fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
+
+ return addr_buf;
+}
+
+/*******************************************************************
+ opens and connects to a unix pipe socket
+ ******************************************************************/
+int open_pipe_sock(char *path)
+{
+ int sock;
+ struct sockaddr_un sa;
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+
+ if (sock < 0)
+ {
+ DEBUG(0, ("unix socket open failed\n"));
+ return sock;
+ }
+
+ ZERO_STRUCT(sa);
+ sa.sun_family = AF_UNIX;
+ safe_strcpy(sa.sun_path, path, sizeof(sa.sun_path)-1);
+
+ DEBUG(10, ("socket open succeeded. file name: %s\n", sa.sun_path));
+
+ if (connect(sock, (struct sockaddr*) &sa, sizeof(sa)) < 0)
+ {
+ DEBUG(0,("socket connect to %s failed\n", sa.sun_path));
+ close(sock);
+ return -1;
+ }
+
+ return sock;
+}
+
+/*******************************************************************
+ Create protected unix domain socket.
+
+ some unixen cannot set permissions on a ux-dom-sock, so we
+ have to make sure that the directory contains the protection
+ permissions, instead.
+ ******************************************************************/
+int create_pipe_sock(const char *socket_dir,
+ const char *socket_name,
+ mode_t dir_perms)
+{
+ struct sockaddr_un sunaddr;
+ struct stat st;
+ int sock;
+ mode_t old_umask;
+ pstring path;
+
+ /* Create the socket directory or reuse the existing one */
+
+ if (lstat(socket_dir, &st) == -1) {
+
+ if (errno == ENOENT) {
+
+ /* Create directory */
+
+ if (mkdir(socket_dir, dir_perms) == -1) {
+ DEBUG(0, ("error creating socket directory "
+ "%s: %s\n", socket_dir,
+ strerror(errno)));
+ return -1;
+ }
+
+ } else {
+
+ DEBUG(0, ("lstat failed on socket directory %s: %s\n",
+ socket_dir, strerror(errno)));
+ return -1;
+ }
+
+ } else {
+
+ /* Check ownership and permission on existing directory */
+
+ if (!S_ISDIR(st.st_mode)) {
+ DEBUG(0, ("socket directory %s isn't a directory\n",
+ socket_dir));
+ return -1;
+ }
+
+ if ((st.st_uid != sec_initial_uid()) ||
+ ((st.st_mode & 0777) != dir_perms)) {
+ DEBUG(0, ("invalid permissions on socket directory "
+ "%s\n", socket_dir));
+ return -1;
+ }
+ }
+
+ /* Create the socket file */
+
+ old_umask = umask(0);
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+
+ if (sock == -1) {
+ perror("socket");
+ umask(old_umask);
+ return -1;
+ }
+
+ snprintf(path, sizeof(path), "%s/%s", socket_dir, socket_name);
+
+ unlink(path);
+ memset(&sunaddr, 0, sizeof(sunaddr));
+ sunaddr.sun_family = AF_UNIX;
+ safe_strcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)-1);
+
+ if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
+ DEBUG(0, ("bind failed on pipe socket %s: %s\n",
+ path,
+ strerror(errno)));
+ close(sock);
+ umask(old_umask);
+ return -1;
+ }
+
+ if (listen(sock, 5) == -1) {
+ DEBUG(0, ("listen failed on pipe socket %s: %s\n",
+ path,
+ strerror(errno)));
+ close(sock);
+ umask(old_umask);
+ return -1;
+ }
+
+ umask(old_umask);
+
+ /* Success! */
+
+ return sock;
+}
+
+/*******************************************************************
+this is like socketpair but uses tcp. It is used by the Samba
+regression test code
+The function guarantees that nobody else can attach to the socket,
+or if they do that this function fails and the socket gets closed
+returns 0 on success, -1 on failure
+the resulting file descriptors are symmetrical
+ ******************************************************************/
+static int socketpair_tcp(int fd[2])
+{
+ int listener;
+ struct sockaddr_in sock;
+ struct sockaddr_in sock2;
+ socklen_t socklen = sizeof(sock);
+ int connect_done = 0;
+
+ fd[0] = fd[1] = listener = -1;
+
+ memset(&sock, 0, sizeof(sock));
+
+ if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
+
+ memset(&sock2, 0, sizeof(sock2));
+#ifdef HAVE_SOCK_SIN_LEN
+ sock2.sin_len = sizeof(sock2);
+#endif
+ sock2.sin_family = PF_INET;
+
+ bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
+
+ if (listen(listener, 1) != 0) goto failed;
+
+ if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
+
+ if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
+
+ set_blocking(fd[1], 0);
+
+ sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
+ if (errno != EINPROGRESS) goto failed;
+ } else {
+ connect_done = 1;
+ }
+
+ if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
+
+ close(listener);
+ if (connect_done == 0) {
+ if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
+ && errno != EISCONN) goto failed;
+ }
+
+ set_blocking(fd[1], 1);
+
+ /* all OK! */
+ return 0;
+
+ failed:
+ if (fd[0] != -1) close(fd[0]);
+ if (fd[1] != -1) close(fd[1]);
+ if (listener != -1) close(listener);
+ return -1;
+}
+
+
+/*******************************************************************
+run a program on a local tcp socket, this is used to launch smbd
+when regression testing
+the return value is a socket which is attached to a subprocess
+running "prog". stdin and stdout are attached. stderr is left
+attached to the original stderr
+ ******************************************************************/
+int sock_exec(const char *prog)
+{
+ int fd[2];
+ if (socketpair_tcp(fd) != 0) {
+ DEBUG(0,("socketpair_tcp failed (%s)\n", strerror(errno)));
+ return -1;
+ }
+ if (fork() == 0) {
+ close(fd[0]);
+ close(0);
+ close(1);
+ dup(fd[1]);
+ dup(fd[1]);
+ exit(system(prog));
+ }
+ close(fd[1]);
+ return fd[0];
+}
diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c
new file mode 100644
index 0000000000..6fdca658cd
--- /dev/null
+++ b/source3/lib/util_str.c
@@ -0,0 +1,1003 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Simo Sorce 2001-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Get the next token from a string, return False if none found
+ handles double-quotes.
+Based on a routine by GJC@VILLAGE.COM.
+Extensively modified by Andrew.Tridgell@anu.edu.au
+****************************************************************************/
+BOOL next_token(char **ptr,char *buff,char *sep, size_t bufsize)
+{
+ char *s;
+ BOOL quoted;
+ size_t len=1;
+
+ if (!ptr) return(False);
+
+ s = *ptr;
+
+ /* default to simple separators */
+ if (!sep) sep = " \t\n\r";
+
+ /* find the first non sep char */
+ while (*s && strchr_m(sep,*s)) s++;
+
+ /* nothing left? */
+ if (! *s) return(False);
+
+ /* copy over the token */
+ for (quoted = False; len < bufsize && *s && (quoted || !strchr_m(sep,*s)); s++) {
+ if (*s == '\"') {
+ quoted = !quoted;
+ } else {
+ len++;
+ *buff++ = *s;
+ }
+ }
+
+ *ptr = (*s) ? s+1 : s;
+ *buff = 0;
+
+ return(True);
+}
+
+
+
+/****************************************************************************
+This is like next_token but is not re-entrant and "remembers" the first
+parameter so you can pass NULL. This is useful for user interface code
+but beware the fact that it is not re-entrant!
+****************************************************************************/
+static char *last_ptr=NULL;
+
+BOOL next_token_nr(char **ptr,char *buff,char *sep, size_t bufsize)
+{
+ BOOL ret;
+ if (!ptr) ptr = &last_ptr;
+
+ ret = next_token(ptr, buff, sep, bufsize);
+ last_ptr = *ptr;
+ return ret;
+}
+
+static uint16 tmpbuf[sizeof(pstring)];
+
+void set_first_token(char *ptr)
+{
+ last_ptr = ptr;
+}
+
+
+/****************************************************************************
+Convert list of tokens to array; dependent on above routine.
+Uses last_ptr from above - bit of a hack.
+****************************************************************************/
+char **toktocliplist(int *ctok, char *sep)
+{
+ char *s=last_ptr;
+ int ictok=0;
+ char **ret, **iret;
+
+ if (!sep) sep = " \t\n\r";
+
+ while(*s && strchr_m(sep,*s)) s++;
+
+ /* nothing left? */
+ if (!*s) return(NULL);
+
+ do {
+ ictok++;
+ while(*s && (!strchr_m(sep,*s))) s++;
+ while(*s && strchr_m(sep,*s)) *s++=0;
+ } while(*s);
+
+ *ctok=ictok;
+ s=last_ptr;
+
+ if (!(ret=iret=malloc(ictok*sizeof(char *)))) return NULL;
+
+ while(ictok--) {
+ *iret++=s;
+ while(*s++);
+ while(!*s) s++;
+ }
+
+ return ret;
+}
+
+/*******************************************************************
+ case insensitive string compararison
+********************************************************************/
+int StrCaseCmp(const char *s, const char *t)
+{
+ pstring buf1, buf2;
+ unix_strupper(s, strlen(s)+1, buf1, sizeof(buf1));
+ unix_strupper(t, strlen(t)+1, buf2, sizeof(buf2));
+ return strcmp(buf1,buf2);
+}
+
+/*******************************************************************
+ case insensitive string compararison, length limited
+********************************************************************/
+int StrnCaseCmp(const char *s, const char *t, size_t n)
+{
+ pstring buf1, buf2;
+ unix_strupper(s, strlen(s)+1, buf1, sizeof(buf1));
+ unix_strupper(t, strlen(t)+1, buf2, sizeof(buf2));
+ return strncmp(buf1,buf2,n);
+}
+
+/*******************************************************************
+ compare 2 strings
+********************************************************************/
+BOOL strequal(const char *s1, const char *s2)
+{
+ if (s1 == s2) return(True);
+ if (!s1 || !s2) return(False);
+
+ return(StrCaseCmp(s1,s2)==0);
+}
+
+/*******************************************************************
+ compare 2 strings up to and including the nth char.
+ ******************************************************************/
+BOOL strnequal(const char *s1,const char *s2,size_t n)
+{
+ if (s1 == s2) return(True);
+ if (!s1 || !s2 || !n) return(False);
+
+ return(StrnCaseCmp(s1,s2,n)==0);
+}
+
+/*******************************************************************
+ compare 2 strings (case sensitive)
+********************************************************************/
+BOOL strcsequal(const char *s1,const char *s2)
+{
+ if (s1 == s2) return(True);
+ if (!s1 || !s2) return(False);
+
+ return(strcmp(s1,s2)==0);
+}
+
+/***************************************************************************
+Do a case-insensitive, whitespace-ignoring string compare.
+***************************************************************************/
+int strwicmp(const char *psz1, const char *psz2)
+{
+ /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
+ /* appropriate value. */
+ if (psz1 == psz2)
+ return (0);
+ else if (psz1 == NULL)
+ return (-1);
+ else if (psz2 == NULL)
+ return (1);
+
+ /* sync the strings on first non-whitespace */
+ while (1)
+ {
+ while (isspace((int)*psz1))
+ psz1++;
+ while (isspace((int)*psz2))
+ psz2++;
+ if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0'
+ || *psz2 == '\0')
+ break;
+ psz1++;
+ psz2++;
+ }
+ return (*psz1 - *psz2);
+}
+
+
+/*******************************************************************
+ convert a string to "normal" form
+********************************************************************/
+void strnorm(char *s)
+{
+ extern int case_default;
+ if (case_default == CASE_UPPER)
+ strupper(s);
+ else
+ strlower(s);
+}
+
+/*******************************************************************
+check if a string is in "normal" case
+********************************************************************/
+BOOL strisnormal(char *s)
+{
+ extern int case_default;
+ if (case_default == CASE_UPPER)
+ return(!strhaslower(s));
+
+ return(!strhasupper(s));
+}
+
+
+/****************************************************************************
+ string replace
+ NOTE: oldc and newc must be 7 bit characters
+****************************************************************************/
+void string_replace(char *s,char oldc,char newc)
+{
+ push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+ string_replace_w(tmpbuf, UCS2_CHAR(oldc), UCS2_CHAR(newc));
+ pull_ucs2(NULL, s, tmpbuf, -1, sizeof(tmpbuf), STR_TERMINATE);
+}
+
+
+/*******************************************************************
+skip past some strings in a buffer
+********************************************************************/
+char *skip_string(char *buf,size_t n)
+{
+ while (n--)
+ buf += strlen(buf) + 1;
+ return(buf);
+}
+
+/*******************************************************************
+ Count the number of characters in a string. Normally this will
+ be the same as the number of bytes in a string for single byte strings,
+ but will be different for multibyte.
+********************************************************************/
+size_t str_charnum(const char *s)
+{
+ push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+ return strlen_w(tmpbuf);
+}
+
+/*******************************************************************
+trim the specified elements off the front and back of a string
+********************************************************************/
+
+BOOL trim_string(char *s,const char *front,const char *back)
+{
+ BOOL ret = False;
+ size_t front_len;
+ size_t back_len;
+ size_t len;
+
+ /* Ignore null or empty strings. */
+ if (!s || (s[0] == '\0'))
+ return False;
+
+ front_len = front? strlen(front) : 0;
+ back_len = back? strlen(back) : 0;
+
+ len = strlen(s);
+
+ if (front_len) {
+ while (len && strncmp(s, front, front_len)==0) {
+ memcpy(s, s+front_len, (len-front_len)+1);
+ len -= front_len;
+ ret=True;
+ }
+ }
+
+ if (back_len) {
+ while (strncmp(s+len-back_len,back,back_len)==0) {
+ s[len-back_len]='\0';
+ len -= back_len;
+ ret=True;
+ }
+ }
+ return ret;
+}
+
+
+/****************************************************************************
+does a string have any uppercase chars in it?
+****************************************************************************/
+BOOL strhasupper(const char *s)
+{
+ smb_ucs2_t *ptr;
+ push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+ for(ptr=tmpbuf;*ptr;ptr++)
+ if(isupper_w(*ptr)) return True;
+ return(False);
+}
+
+/****************************************************************************
+does a string have any lowercase chars in it?
+****************************************************************************/
+BOOL strhaslower(const char *s)
+{
+ smb_ucs2_t *ptr;
+ push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+ for(ptr=tmpbuf;*ptr;ptr++)
+ if(islower_w(*ptr)) return True;
+ return(False);
+}
+
+/****************************************************************************
+find the number of 'c' chars in a string
+****************************************************************************/
+size_t count_chars(const char *s,char c)
+{
+ smb_ucs2_t *ptr;
+ int count;
+ push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+ for(count=0,ptr=tmpbuf;*ptr;ptr++) if(*ptr==UCS2_CHAR(c)) count++;
+ return(count);
+}
+
+/*******************************************************************
+Return True if a string consists only of one particular character.
+********************************************************************/
+
+BOOL str_is_all(const char *s,char c)
+{
+ smb_ucs2_t *ptr;
+
+ if(s == NULL) return False;
+ if(!*s) return False;
+
+ push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+ for(ptr=tmpbuf;*ptr;ptr++) if(*ptr!=UCS2_CHAR(c)) return False;
+
+ return True;
+}
+
+/*******************************************************************
+safe string copy into a known length string. maxlength does not
+include the terminating zero.
+********************************************************************/
+
+char *safe_strcpy(char *dest,const char *src, size_t maxlength)
+{
+ size_t len;
+
+ if (!dest) {
+ DEBUG(0,("ERROR: NULL dest in safe_strcpy\n"));
+ return NULL;
+ }
+
+ if (!src) {
+ *dest = 0;
+ return dest;
+ }
+
+ len = strlen(src);
+
+ if (len > maxlength) {
+ DEBUG(0,("ERROR: string overflow by %d in safe_strcpy [%.50s]\n",
+ (int)(len-maxlength), src));
+ len = maxlength;
+ }
+
+ memmove(dest, src, len);
+ dest[len] = 0;
+ return dest;
+}
+
+/*******************************************************************
+safe string cat into a string. maxlength does not
+include the terminating zero.
+********************************************************************/
+
+char *safe_strcat(char *dest, const char *src, size_t maxlength)
+{
+ size_t src_len, dest_len;
+
+ if (!dest) {
+ DEBUG(0,("ERROR: NULL dest in safe_strcat\n"));
+ return NULL;
+ }
+
+ if (!src) {
+ return dest;
+ }
+
+ src_len = strlen(src);
+ dest_len = strlen(dest);
+
+ if (src_len + dest_len > maxlength) {
+ DEBUG(0,("ERROR: string overflow by %d in safe_strcat [%.50s]\n",
+ (int)(src_len + dest_len - maxlength), src));
+ src_len = maxlength - dest_len;
+ }
+
+ memcpy(&dest[dest_len], src, src_len);
+ dest[dest_len + src_len] = 0;
+ return dest;
+}
+
+/*******************************************************************
+ Paranoid strcpy into a buffer of given length (includes terminating
+ zero. Strips out all but 'a-Z0-9' and the character in other_safe_chars
+ and replaces with '_'. Deliberately does *NOT* check for multibyte
+ characters. Don't change it !
+********************************************************************/
+
+char *alpha_strcpy(char *dest, const char *src, const char *other_safe_chars, size_t maxlength)
+{
+ size_t len, i;
+
+ if (!dest) {
+ DEBUG(0,("ERROR: NULL dest in alpha_strcpy\n"));
+ return NULL;
+ }
+
+ if (!src) {
+ *dest = 0;
+ return dest;
+ }
+
+ len = strlen(src);
+ if (len >= maxlength)
+ len = maxlength - 1;
+
+ if (!other_safe_chars)
+ other_safe_chars = "";
+
+ for(i = 0; i < len; i++) {
+ int val = (src[i] & 0xff);
+ if(isupper(val) || islower(val) || isdigit(val) || strchr_m(other_safe_chars, val))
+ dest[i] = src[i];
+ else
+ dest[i] = '_';
+ }
+
+ dest[i] = '\0';
+
+ return dest;
+}
+
+/****************************************************************************
+ Like strncpy but always null terminates. Make sure there is room!
+ The variable n should always be one less than the available size.
+****************************************************************************/
+
+char *StrnCpy(char *dest,const char *src,size_t n)
+{
+ char *d = dest;
+ if (!dest) return(NULL);
+ if (!src) {
+ *dest = 0;
+ return(dest);
+ }
+ while (n-- && (*d++ = *src++)) ;
+ *d = 0;
+ return(dest);
+}
+
+/****************************************************************************
+like strncpy but copies up to the character marker. always null terminates.
+returns a pointer to the character marker in the source string (src).
+****************************************************************************/
+char *strncpyn(char *dest, const char *src,size_t n, char c)
+{
+ char *p;
+ size_t str_len;
+
+ p = strchr_m(src, c);
+ if (p == NULL)
+ {
+ DEBUG(5, ("strncpyn: separator character (%c) not found\n", c));
+ return NULL;
+ }
+
+ str_len = PTR_DIFF(p, src);
+ strncpy(dest, src, MIN(n, str_len));
+ dest[str_len] = '\0';
+
+ return p;
+}
+
+
+/*************************************************************
+ Routine to get hex characters and turn them into a 16 byte array.
+ the array can be variable length, and any non-hex-numeric
+ characters are skipped. "0xnn" or "0Xnn" is specially catered
+ for.
+
+ valid examples: "0A5D15"; "0x15, 0x49, 0xa2"; "59\ta9\te3\n"
+
+**************************************************************/
+size_t strhex_to_str(char *p, size_t len, const char *strhex)
+{
+ size_t i;
+ size_t num_chars = 0;
+ unsigned char lonybble, hinybble;
+ char *hexchars = "0123456789ABCDEF";
+ char *p1 = NULL, *p2 = NULL;
+
+ for (i = 0; i < len && strhex[i] != 0; i++)
+ {
+ if (strnequal(hexchars, "0x", 2))
+ {
+ i++; /* skip two chars */
+ continue;
+ }
+
+ if (!(p1 = strchr_m(hexchars, toupper(strhex[i]))))
+ {
+ break;
+ }
+
+ i++; /* next hex digit */
+
+ if (!(p2 = strchr_m(hexchars, toupper(strhex[i]))))
+ {
+ break;
+ }
+
+ /* get the two nybbles */
+ hinybble = PTR_DIFF(p1, hexchars);
+ lonybble = PTR_DIFF(p2, hexchars);
+
+ p[num_chars] = (hinybble << 4) | lonybble;
+ num_chars++;
+
+ p1 = NULL;
+ p2 = NULL;
+ }
+ return num_chars;
+}
+
+/****************************************************************************
+check if a string is part of a list
+****************************************************************************/
+BOOL in_list(char *s,char *list,BOOL casesensitive)
+{
+ pstring tok;
+ char *p=list;
+
+ if (!list) return(False);
+
+ while (next_token(&p,tok,LIST_SEP,sizeof(tok))) {
+ if (casesensitive) {
+ if (strcmp(tok,s) == 0)
+ return(True);
+ } else {
+ if (StrCaseCmp(tok,s) == 0)
+ return(True);
+ }
+ }
+ return(False);
+}
+
+/* this is used to prevent lots of mallocs of size 1 */
+static char *null_string = NULL;
+
+/****************************************************************************
+set a string value, allocing the space for the string
+****************************************************************************/
+static BOOL string_init(char **dest,const char *src)
+{
+ size_t l;
+ if (!src)
+ src = "";
+
+ l = strlen(src);
+
+ if (l == 0)
+ {
+ if (!null_string) {
+ if((null_string = (char *)malloc(1)) == NULL) {
+ DEBUG(0,("string_init: malloc fail for null_string.\n"));
+ return False;
+ }
+ *null_string = 0;
+ }
+ *dest = null_string;
+ }
+ else
+ {
+ (*dest) = (char *)malloc(l+1);
+ if ((*dest) == NULL) {
+ DEBUG(0,("Out of memory in string_init\n"));
+ return False;
+ }
+
+ pstrcpy(*dest,src);
+ }
+ return(True);
+}
+
+/****************************************************************************
+free a string value
+****************************************************************************/
+void string_free(char **s)
+{
+ if (!s || !(*s)) return;
+ if (*s == null_string)
+ *s = NULL;
+ SAFE_FREE(*s);
+}
+
+/****************************************************************************
+set a string value, allocing the space for the string, and deallocating any
+existing space
+****************************************************************************/
+BOOL string_set(char **dest,const char *src)
+{
+ string_free(dest);
+
+ return(string_init(dest,src));
+}
+
+
+/****************************************************************************
+substitute a string for a pattern in another string. Make sure there is
+enough room!
+
+This routine looks for pattern in s and replaces it with
+insert. It may do multiple replacements.
+
+any of " ; ' $ or ` in the insert string are replaced with _
+if len==0 then no length check is performed
+****************************************************************************/
+void string_sub(char *s,const char *pattern,const char *insert, size_t len)
+{
+ char *p;
+ ssize_t ls,lp,li, i;
+
+ if (!insert || !pattern || !s) return;
+
+ ls = (ssize_t)strlen(s);
+ lp = (ssize_t)strlen(pattern);
+ li = (ssize_t)strlen(insert);
+
+ if (!*pattern) return;
+
+ while (lp <= ls && (p = strstr(s,pattern))) {
+ if (len && (ls + (li-lp) >= len)) {
+ DEBUG(0,("ERROR: string overflow by %d in string_sub(%.50s, %d)\n",
+ (int)(ls + (li-lp) - len),
+ pattern, (int)len));
+ break;
+ }
+ if (li != lp) {
+ memmove(p+li,p+lp,strlen(p+lp)+1);
+ }
+ for (i=0;i<li;i++) {
+ switch (insert[i]) {
+ case '`':
+ case '"':
+ case '\'':
+ case ';':
+ case '$':
+ case '%':
+ case '\r':
+ case '\n':
+ p[i] = '_';
+ break;
+ default:
+ p[i] = insert[i];
+ }
+ }
+ s = p + li;
+ ls += (li-lp);
+ }
+}
+
+void fstring_sub(char *s,const char *pattern,const char *insert)
+{
+ string_sub(s, pattern, insert, sizeof(fstring));
+}
+
+void pstring_sub(char *s,const char *pattern,const char *insert)
+{
+ string_sub(s, pattern, insert, sizeof(pstring));
+}
+
+/****************************************************************************
+similar to string_sub() but allows for any character to be substituted.
+Use with caution!
+if len==0 then no length check is performed
+****************************************************************************/
+void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
+{
+ char *p;
+ ssize_t ls,lp,li;
+
+ if (!insert || !pattern || !s) return;
+
+ ls = (ssize_t)strlen(s);
+ lp = (ssize_t)strlen(pattern);
+ li = (ssize_t)strlen(insert);
+
+ if (!*pattern) return;
+
+ while (lp <= ls && (p = strstr(s,pattern))) {
+ if (len && (ls + (li-lp) >= len)) {
+ DEBUG(0,("ERROR: string overflow by %d in all_string_sub(%.50s, %d)\n",
+ (int)(ls + (li-lp) - len),
+ pattern, (int)len));
+ break;
+ }
+ if (li != lp) {
+ memmove(p+li,p+lp,strlen(p+lp)+1);
+ }
+ memcpy(p, insert, li);
+ s = p + li;
+ ls += (li-lp);
+ }
+}
+
+/****************************************************************************
+similar to all_string_sub but for unicode strings.
+return a new allocate unicode string.
+len is the number of bytes, not chars
+ similar to string_sub() but allows for any character to be substituted.
+ Use with caution!
+ if len==0 then no length check is performed
+****************************************************************************/
+
+smb_ucs2_t *all_string_sub_w(const smb_ucs2_t *s, const smb_ucs2_t *pattern,
+ const smb_ucs2_t *insert)
+{
+ smb_ucs2_t *r, *rp, *sp;
+ size_t lr, lp, li, lt;
+
+ if (!insert || !pattern || !*pattern || !s) return NULL;
+
+ lt = (size_t)strlen_w(s);
+ lp = (size_t)strlen_w(pattern);
+ li = (size_t)strlen_w(insert);
+
+ if (li > lp) {
+ smb_ucs2_t *st = s;
+ int ld = li - lp;
+ while ((sp = strstr_w(st, pattern))) {
+ st = sp + lp;
+ lt += ld;
+ }
+ }
+
+ r = rp = (smb_ucs2_t *)malloc((lt + 1)*(sizeof(smb_ucs2_t)));
+ if (!r) {
+ DEBUG(0, ("all_string_sub_w: out of memory!\n"));
+ return NULL;
+ }
+
+ while ((sp = strstr_w(s, pattern))) {
+ memcpy(rp, s, (sp - s));
+ rp += ((sp - s) / sizeof(smb_ucs2_t));
+ memcpy(rp, insert, (li * sizeof(smb_ucs2_t)));
+ s = sp + lp;
+ rp += li;
+ }
+ lr = ((rp - r) / sizeof(smb_ucs2_t));
+ if (lr < lt) {
+ memcpy(rp, s, ((lt - lr) * sizeof(smb_ucs2_t)));
+ rp += (lt - lr);
+ }
+ *rp = 0;
+
+ return r;
+}
+
+smb_ucs2_t *all_string_sub_wa(smb_ucs2_t *s, const char *pattern,
+ const char *insert)
+{
+ wpstring p, i;
+
+ if (!insert || !pattern || !s) return NULL;
+ push_ucs2(NULL, p, pattern, sizeof(wpstring) - 1, STR_TERMINATE);
+ push_ucs2(NULL, i, insert, sizeof(wpstring) - 1, STR_TERMINATE);
+ return all_string_sub_w(s, p, i);
+}
+
+/****************************************************************************
+ splits out the front and back at a separator.
+****************************************************************************/
+void split_at_last_component(char *path, char *front, char sep, char *back)
+{
+ char *p = strrchr_m(path, sep);
+
+ if (p != NULL)
+ {
+ *p = 0;
+ }
+ if (front != NULL)
+ {
+ pstrcpy(front, path);
+ }
+ if (p != NULL)
+ {
+ if (back != NULL)
+ {
+ pstrcpy(back, p+1);
+ }
+ *p = '\\';
+ }
+ else
+ {
+ if (back != NULL)
+ {
+ back[0] = 0;
+ }
+ }
+}
+
+
+/****************************************************************************
+write an octal as a string
+****************************************************************************/
+char *octal_string(int i)
+{
+ static char ret[64];
+ if (i == -1) {
+ return "-1";
+ }
+ slprintf(ret, sizeof(ret)-1, "0%o", i);
+ return ret;
+}
+
+
+/****************************************************************************
+truncate a string at a specified length
+****************************************************************************/
+char *string_truncate(char *s, int length)
+{
+ if (s && strlen(s) > length) {
+ s[length] = 0;
+ }
+ return s;
+}
+
+
+/****************************************************************************
+strchr and strrchr_m are very hard to do on general multi-byte strings.
+we convert via ucs2 for now
+****************************************************************************/
+char *strchr_m(const char *s, char c)
+{
+ wpstring ws;
+ pstring s2;
+ smb_ucs2_t *p;
+
+ push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE);
+ p = strchr_w(ws, UCS2_CHAR(c));
+ if (!p) return NULL;
+ *p = 0;
+ pull_ucs2_pstring(s2, ws);
+ return (char *)(s+strlen(s2));
+}
+
+char *strrchr_m(const char *s, char c)
+{
+ wpstring ws;
+ pstring s2;
+ smb_ucs2_t *p;
+
+ push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE);
+ p = strrchr_w(ws, UCS2_CHAR(c));
+ if (!p) return NULL;
+ *p = 0;
+ pull_ucs2_pstring(s2, ws);
+ return (char *)(s+strlen(s2));
+}
+
+/*******************************************************************
+ convert a string to lower case
+********************************************************************/
+void strlower_m(char *s)
+{
+ /* this is quite a common operation, so we want it to be
+ fast. We optimise for the ascii case, knowing that all our
+ supported multi-byte character sets are ascii-compatible
+ (ie. they match for the first 128 chars) */
+ while (*s && !(((unsigned char)s[0]) & 0x7F)) {
+ *s++ = tolower((unsigned char)*s);
+ }
+
+ if (!*s) return;
+
+ /* I assume that lowercased string takes the same number of bytes
+ * as source string even in UTF-8 encoding. (VIV) */
+ unix_strlower(s,strlen(s)+1,s,strlen(s)+1);
+}
+
+/*******************************************************************
+ convert a string to upper case
+********************************************************************/
+void strupper_m(char *s)
+{
+ /* this is quite a common operation, so we want it to be
+ fast. We optimise for the ascii case, knowing that all our
+ supported multi-byte character sets are ascii-compatible
+ (ie. they match for the first 128 chars) */
+ while (*s && !(((unsigned char)s[0]) & 0x7F)) {
+ *s++ = toupper((unsigned char)*s);
+ }
+
+ if (!*s) return;
+
+ /* I assume that lowercased string takes the same number of bytes
+ * as source string even in multibyte encoding. (VIV) */
+ unix_strupper(s,strlen(s)+1,s,strlen(s)+1);
+}
+
+/*
+ return a RFC2254 binary string representation of a buffer
+ used in LDAP filters
+ caller must free
+*/
+char *binary_string(char *buf, int len)
+{
+ char *s;
+ int i, j;
+ const char *hex = "0123456789ABCDEF";
+ s = malloc(len * 3 + 1);
+ if (!s) return NULL;
+ for (j=i=0;i<len;i++) {
+ s[j] = '\\';
+ s[j+1] = hex[((unsigned char)buf[i]) >> 4];
+ s[j+2] = hex[((unsigned char)buf[i]) & 0xF];
+ j += 3;
+ }
+ s[j] = 0;
+ return s;
+}
+
+
+/* Just a typesafety wrapper for snprintf into a pstring */
+int pstr_sprintf(pstring s, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(s, PSTRING_LEN, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+
+/* Just a typesafety wrapper for snprintf into a fstring */
+int fstr_sprintf(fstring s, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(s, FSTRING_LEN, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+
+#ifndef HAVE_STRNDUP
+/*******************************************************************
+some platforms don't have strndup
+********************************************************************/
+ char *strndup(const char *s, size_t n)
+{
+ char *ret;
+ int i;
+ for (i=0;s[i] && i<n;i++) ;
+
+ ret = malloc(i+1);
+ if (!ret) return NULL;
+ memcpy(ret, s, i);
+ ret[i] = 0;
+ return ret;
+}
+#endif
diff --git a/source3/lib/util_unistr.c b/source3/lib/util_unistr.c
new file mode 100644
index 0000000000..a1cff26169
--- /dev/null
+++ b/source3/lib/util_unistr.c
@@ -0,0 +1,777 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Simo Sorce 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifndef MAXUNI
+#define MAXUNI 1024
+#endif
+
+/* these 3 tables define the unicode case handling. They are loaded
+ at startup either via mmap() or read() from the lib directory */
+static smb_ucs2_t *upcase_table;
+static smb_ucs2_t *lowcase_table;
+static uint8 *valid_table;
+
+
+/*******************************************************************
+load the case handling tables
+********************************************************************/
+void load_case_tables(void)
+{
+ static int initialised;
+ int i;
+
+ if (initialised) return;
+ initialised = 1;
+
+ upcase_table = map_file(lib_path("upcase.dat"), 0x20000);
+ lowcase_table = map_file(lib_path("lowcase.dat"), 0x20000);
+
+ /* we would like Samba to limp along even if these tables are
+ not available */
+ if (!upcase_table) {
+ DEBUG(1,("creating lame upcase table\n"));
+ upcase_table = malloc(0x20000);
+ for (i=0;i<0x10000;i++) {
+ smb_ucs2_t v;
+ SSVAL(&v, 0, i);
+ upcase_table[v] = i;
+ }
+ for (i=0;i<256;i++) {
+ smb_ucs2_t v;
+ SSVAL(&v, 0, UCS2_CHAR(i));
+ upcase_table[v] = UCS2_CHAR(islower(i)?toupper(i):i);
+ }
+ }
+
+ if (!lowcase_table) {
+ DEBUG(1,("creating lame lowcase table\n"));
+ lowcase_table = malloc(0x20000);
+ for (i=0;i<0x10000;i++) {
+ smb_ucs2_t v;
+ SSVAL(&v, 0, i);
+ lowcase_table[v] = i;
+ }
+ for (i=0;i<256;i++) {
+ smb_ucs2_t v;
+ SSVAL(&v, 0, UCS2_CHAR(i));
+ lowcase_table[v] = UCS2_CHAR(isupper(i)?tolower(i):i);
+ }
+ }
+}
+
+/*
+ see if a ucs2 character can be mapped correctly to a dos character
+ and mapped back to the same character in ucs2
+*/
+static int check_dos_char(smb_ucs2_t c)
+{
+ char buf[10];
+ smb_ucs2_t c2 = 0;
+ int len1, len2;
+ len1 = convert_string(CH_UCS2, CH_DOS, &c, 2, buf, sizeof(buf));
+ if (len1 == 0) return 0;
+ len2 = convert_string(CH_DOS, CH_UCS2, buf, len1, &c2, 2);
+ if (len2 != 2) return 0;
+ return (c == c2);
+}
+
+/*******************************************************************
+load the valid character map table
+********************************************************************/
+void init_valid_table(void)
+{
+ static int initialised;
+ static int mapped_file;
+ int i;
+ const char *allowed = ".!#$%&'()_-@^`~";
+
+ if (initialised && mapped_file) return;
+ initialised = 1;
+
+ valid_table = map_file(lib_path("valid.dat"), 0x10000);
+ if (valid_table) {
+ mapped_file = 1;
+ return;
+ }
+
+ if (valid_table) free(valid_table);
+
+ DEBUG(2,("creating default valid table\n"));
+ valid_table = malloc(0x10000);
+ for (i=0;i<128;i++) valid_table[i] = isalnum(i) ||
+ strchr(allowed,i);
+ for (;i<0x10000;i++) {
+ smb_ucs2_t c;
+ SSVAL(&c, 0, i);
+ valid_table[i] = check_dos_char(c);
+ }
+}
+
+
+/*******************************************************************
+ Write a string in (little-endian) unicode format. src is in
+ the current DOS codepage. len is the length in bytes of the
+ string pointed to by dst.
+
+ if null_terminate is True then null terminate the packet (adds 2 bytes)
+
+ the return value is the length in bytes consumed by the string, including the
+ null termination if applied
+********************************************************************/
+
+size_t dos_PutUniCode(char *dst,const char *src, ssize_t len, BOOL null_terminate)
+{
+ return push_ucs2(NULL, dst, src, len,
+ STR_UNICODE|STR_NOALIGN | (null_terminate?STR_TERMINATE:0));
+}
+
+
+/*******************************************************************
+ Skip past a unicode string, but not more than len. Always move
+ past a terminating zero if found.
+********************************************************************/
+
+char *skip_unibuf(char *src, size_t len)
+{
+ char *srcend = src + len;
+
+ while (src < srcend && SVAL(src,0))
+ src += 2;
+
+ if(!SVAL(src,0))
+ src += 2;
+
+ return src;
+}
+
+/* Copy a string from little-endian or big-endian unicode source (depending
+ * on flags) to internal samba format destination
+ */
+int rpcstr_pull(char* dest, void *src, int dest_len, int src_len, int flags)
+{
+ if(dest_len==-1) dest_len=MAXUNI-3;
+ return pull_ucs2(NULL, dest, src, dest_len, src_len, flags|STR_UNICODE|STR_NOALIGN);
+}
+
+/* Copy a string from a unistr2 source to internal samba format
+ destination. Use this instead of direct calls to rpcstr_pull() to avoid
+ having to determine whether the source string is null terminated. */
+
+int rpcstr_pull_unistr2_fstring(char *dest, UNISTR2 *src)
+{
+ return pull_ucs2(NULL, dest, src->buffer, sizeof(fstring),
+ src->uni_str_len * 2, 0);
+}
+
+/* Converts a string from internal samba format to unicode
+ */
+int rpcstr_push(void* dest, const char *src, int dest_len, int flags)
+{
+ return push_ucs2(NULL, dest, src, dest_len, flags|STR_UNICODE|STR_NOALIGN);
+}
+
+/*******************************************************************
+ Return a DOS codepage version of a little-endian unicode string.
+ len is the filename length (ignoring any terminating zero) in uin16
+ units. Always null terminates.
+ Hack alert: uses fixed buffer(s).
+********************************************************************/
+char *dos_unistrn2(const uint16 *src, int len)
+{
+ static char lbufs[8][MAXUNI];
+ static int nexti;
+ char *lbuf = lbufs[nexti];
+ nexti = (nexti+1)%8;
+ pull_ucs2(NULL, lbuf, src, MAXUNI-3, len*2, STR_NOALIGN);
+ return lbuf;
+}
+
+/*******************************************************************
+ Convert a (little-endian) UNISTR2 structure to an ASCII string
+********************************************************************/
+void unistr2_to_ascii(char *dest, const UNISTR2 *str, size_t maxlen)
+{
+ if (str == NULL) {
+ *dest='\0';
+ return;
+ }
+ pull_ucs2(NULL, dest, str->buffer, maxlen, str->uni_str_len*2, STR_NOALIGN);
+}
+
+
+/*******************************************************************
+ duplicate a UNISTR2 string into a null terminated char*
+ using a talloc context
+********************************************************************/
+char *unistr2_tdup(TALLOC_CTX *ctx, const UNISTR2 *str)
+{
+ char *s;
+ int maxlen = (str->uni_str_len+1)*4;
+ if (!str->buffer) return NULL;
+ s = (char *)talloc(ctx, maxlen); /* convervative */
+ if (!s) return NULL;
+ pull_ucs2(NULL, s, str->buffer, maxlen, str->uni_str_len*2,
+ STR_NOALIGN);
+ return s;
+}
+
+
+/*******************************************************************
+Return a number stored in a buffer
+********************************************************************/
+
+uint32 buffer2_to_uint32(BUFFER2 *str)
+{
+ if (str->buf_len == 4)
+ return IVAL(str->buffer, 0);
+ else
+ return 0;
+}
+
+/*******************************************************************
+ Convert a wchar to upper case.
+********************************************************************/
+
+smb_ucs2_t toupper_w(smb_ucs2_t val)
+{
+ return upcase_table[SVAL(&val,0)];
+}
+
+/*******************************************************************
+ Convert a wchar to lower case.
+********************************************************************/
+
+smb_ucs2_t tolower_w( smb_ucs2_t val )
+{
+ return lowcase_table[SVAL(&val,0)];
+
+}
+
+/*******************************************************************
+determine if a character is lowercase
+********************************************************************/
+BOOL islower_w(smb_ucs2_t c)
+{
+ return upcase_table[SVAL(&c,0)] != c;
+}
+
+/*******************************************************************
+determine if a character is uppercase
+********************************************************************/
+BOOL isupper_w(smb_ucs2_t c)
+{
+ return lowcase_table[SVAL(&c,0)] != c;
+}
+
+
+/*******************************************************************
+determine if a character is valid in a 8.3 name
+********************************************************************/
+BOOL isvalid83_w(smb_ucs2_t c)
+{
+ return valid_table[SVAL(&c,0)] != 0;
+}
+
+/*******************************************************************
+ Count the number of characters in a smb_ucs2_t string.
+********************************************************************/
+size_t strlen_w(const smb_ucs2_t *src)
+{
+ size_t len;
+
+ for(len = 0; *src++; len++) ;
+
+ return len;
+}
+
+/*******************************************************************
+ Count up to max number of characters in a smb_ucs2_t string.
+********************************************************************/
+size_t strnlen_w(const smb_ucs2_t *src, size_t max)
+{
+ size_t len;
+
+ for(len = 0; *src++ && (len < max); len++) ;
+
+ return len;
+}
+
+/*******************************************************************
+wide strchr()
+********************************************************************/
+smb_ucs2_t *strchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
+{
+ while (*s != 0) {
+ if (c == *s) return (smb_ucs2_t *)s;
+ s++;
+ }
+ return NULL;
+}
+
+smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c)
+{
+ return strchr_w(s, UCS2_CHAR(c));
+}
+
+smb_ucs2_t *strrchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
+{
+ const smb_ucs2_t *p = s;
+ int len = strlen_w(s);
+ if (len == 0) return NULL;
+ p += (len - 1);
+ do {
+ if (c == *p) return (smb_ucs2_t *)p;
+ } while (p-- != s);
+ return NULL;
+}
+
+/*******************************************************************
+wide strstr()
+********************************************************************/
+smb_ucs2_t *strstr_w(const smb_ucs2_t *s, const smb_ucs2_t *ins)
+{
+ smb_ucs2_t *r;
+ size_t slen, inslen;
+
+ if (!s || !*s || !ins || !*ins) return NULL;
+ slen = strlen_w(s);
+ inslen = strlen_w(ins);
+ r = (smb_ucs2_t *)s;
+ while ((r = strchr_w(r, *ins))) {
+ if (strncmp_w(r, ins, inslen) == 0) return r;
+ r++;
+ }
+ return NULL;
+}
+
+/*******************************************************************
+ Convert a string to lower case.
+ return True if any char is converted
+********************************************************************/
+BOOL strlower_w(smb_ucs2_t *s)
+{
+ BOOL ret = False;
+ while (*s) {
+ smb_ucs2_t v = tolower_w(*s);
+ if (v != *s) {
+ *s = v;
+ ret = True;
+ }
+ s++;
+ }
+ return ret;
+}
+
+/*******************************************************************
+ Convert a string to upper case.
+ return True if any char is converted
+********************************************************************/
+BOOL strupper_w(smb_ucs2_t *s)
+{
+ BOOL ret = False;
+ while (*s) {
+ smb_ucs2_t v = toupper_w(*s);
+ if (v != *s) {
+ *s = v;
+ ret = True;
+ }
+ s++;
+ }
+ return ret;
+}
+
+/*******************************************************************
+ convert a string to "normal" form
+********************************************************************/
+void strnorm_w(smb_ucs2_t *s)
+{
+ extern int case_default;
+ if (case_default == CASE_UPPER)
+ strupper_w(s);
+ else
+ strlower_w(s);
+}
+
+int strcmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
+{
+ while (*b && *a == *b) { a++; b++; }
+ return (*a - *b);
+ /* warning: if *a != *b and both are not 0 we retrun a random
+ greater or lesser than 0 number not realted to which
+ string is longer */
+}
+
+int strncmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len)
+{
+ size_t n = 0;
+ while ((n < len) && *b && *a == *b) { a++; b++; n++;}
+ return (len - n)?(*a - *b):0;
+}
+
+/*******************************************************************
+case insensitive string comparison
+********************************************************************/
+int strcasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
+{
+ while (*b && toupper_w(*a) == toupper_w(*b)) { a++; b++; }
+ return (tolower_w(*a) - tolower_w(*b));
+}
+
+/*******************************************************************
+case insensitive string comparison, lenght limited
+********************************************************************/
+int strncasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len)
+{
+ size_t n = 0;
+ while ((n < len) && *b && (toupper_w(*a) == toupper_w(*b))) { a++; b++; n++; }
+ return (len - n)?(tolower_w(*a) - tolower_w(*b)):0;
+}
+
+/*******************************************************************
+ compare 2 strings
+********************************************************************/
+BOOL strequal_w(const smb_ucs2_t *s1, const smb_ucs2_t *s2)
+{
+ if (s1 == s2) return(True);
+ if (!s1 || !s2) return(False);
+
+ return(strcasecmp_w(s1,s2)==0);
+}
+
+/*******************************************************************
+ compare 2 strings up to and including the nth char.
+ ******************************************************************/
+BOOL strnequal_w(const smb_ucs2_t *s1,const smb_ucs2_t *s2,size_t n)
+{
+ if (s1 == s2) return(True);
+ if (!s1 || !s2 || !n) return(False);
+
+ return(strncasecmp_w(s1,s2,n)==0);
+}
+
+/*******************************************************************
+duplicate string
+********************************************************************/
+smb_ucs2_t *strdup_w(const smb_ucs2_t *src)
+{
+ return strndup_w(src, 0);
+}
+
+/* if len == 0 then duplicate the whole string */
+smb_ucs2_t *strndup_w(const smb_ucs2_t *src, size_t len)
+{
+ smb_ucs2_t *dest;
+
+ if (!len) len = strlen_w(src);
+ dest = (smb_ucs2_t *)malloc((len + 1) * sizeof(smb_ucs2_t));
+ if (!dest) {
+ DEBUG(0,("strdup_w: out of memory!\n"));
+ return NULL;
+ }
+
+ memcpy(dest, src, len * sizeof(smb_ucs2_t));
+ dest[len] = 0;
+
+ return dest;
+}
+
+/*******************************************************************
+copy a string with max len
+********************************************************************/
+
+smb_ucs2_t *strncpy_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
+{
+ size_t len;
+
+ if (!dest || !src) return NULL;
+
+ for (len = 0; (src[len] != 0) && (len < max); len++)
+ dest[len] = src[len];
+ while (len < max)
+ dest[len++] = 0;
+
+ return dest;
+}
+
+
+/*******************************************************************
+append a string of len bytes and add a terminator
+********************************************************************/
+
+smb_ucs2_t *strncat_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
+{
+ size_t start;
+ size_t len;
+
+ if (!dest || !src) return NULL;
+
+ start = strlen_w(dest);
+ len = strnlen_w(src, max);
+
+ memcpy(&dest[start], src, len*sizeof(smb_ucs2_t));
+ dest[start+len] = 0;
+
+ return dest;
+}
+
+smb_ucs2_t *strcat_w(smb_ucs2_t *dest, const smb_ucs2_t *src)
+{
+ size_t start;
+ size_t len;
+
+ if (!dest || !src) return NULL;
+
+ start = strlen_w(dest);
+ len = strlen_w(src);
+
+ memcpy(&dest[start], src, len*sizeof(smb_ucs2_t));
+ dest[start+len] = 0;
+
+ return dest;
+}
+
+
+/*******************************************************************
+replace any occurence of oldc with newc in unicode string
+********************************************************************/
+
+void string_replace_w(smb_ucs2_t *s, smb_ucs2_t oldc, smb_ucs2_t newc)
+{
+ for(;*s;s++) {
+ if(*s==oldc) *s=newc;
+ }
+}
+
+/*******************************************************************
+trim unicode string
+********************************************************************/
+
+BOOL trim_string_w(smb_ucs2_t *s, const smb_ucs2_t *front,
+ const smb_ucs2_t *back)
+{
+ BOOL ret = False;
+ size_t len, front_len, back_len;
+
+ if (!s || !*s) return False;
+
+ len = strlen_w(s);
+
+ if (front && *front) {
+ front_len = strlen_w(front);
+ while (len && strncmp_w(s, front, front_len) == 0) {
+ memmove(s, (s + front_len), (len - front_len + 1) * sizeof(smb_ucs2_t));
+ len -= front_len;
+ ret = True;
+ }
+ }
+
+ if (back && *back) {
+ back_len = strlen_w(back);
+ while (len && strncmp_w((s + (len - back_len)), back, back_len) == 0) {
+ s[len - back_len] = 0;
+ len -= back_len;
+ ret = True;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ The *_wa() functions take a combination of 7 bit ascii
+ and wide characters They are used so that you can use string
+ functions combining C string constants with ucs2 strings
+
+ The char* arguments must NOT be multibyte - to be completely sure
+ of this only pass string constants */
+
+
+void pstrcpy_wa(smb_ucs2_t *dest, const char *src)
+{
+ int i;
+ for (i=0;i<PSTRING_LEN;i++) {
+ dest[i] = UCS2_CHAR(src[i]);
+ if (src[i] == 0) return;
+ }
+}
+
+int strcmp_wa(const smb_ucs2_t *a, const char *b)
+{
+ while (*b && *a == UCS2_CHAR(*b)) { a++; b++; }
+ return (*a - UCS2_CHAR(*b));
+}
+
+int strncmp_wa(const smb_ucs2_t *a, const char *b, size_t len)
+{
+ size_t n = 0;
+ while ((n < len) && *b && *a == UCS2_CHAR(*b)) { a++; b++; n++;}
+ return (len - n)?(*a - UCS2_CHAR(*b)):0;
+}
+
+smb_ucs2_t *strpbrk_wa(const smb_ucs2_t *s, const char *p)
+{
+ while (*s != 0) {
+ int i;
+ for (i=0; p[i] && *s != UCS2_CHAR(p[i]); i++)
+ ;
+ if (p[i]) return (smb_ucs2_t *)s;
+ s++;
+ }
+ return NULL;
+}
+
+smb_ucs2_t *strstr_wa(const smb_ucs2_t *s, const char *ins)
+{
+ smb_ucs2_t *r;
+ size_t slen, inslen;
+
+ if (!s || !*s || !ins || !*ins) return NULL;
+ slen = strlen_w(s);
+ inslen = strlen(ins);
+ r = (smb_ucs2_t *)s;
+ while ((r = strchr_w(r, UCS2_CHAR(*ins)))) {
+ if (strncmp_wa(r, ins, inslen) == 0) return r;
+ r++;
+ }
+ return NULL;
+}
+
+/*******************************************************************
+copy a string with max len
+********************************************************************/
+
+smb_ucs2_t *strncpy_wa(smb_ucs2_t *dest, const char *src, const size_t max)
+{
+ smb_ucs2_t *ucs2_src;
+
+ if (!dest || !src) return NULL;
+ if (!(ucs2_src = acnv_uxu2(src)))
+ return NULL;
+
+ strncpy_w(dest, ucs2_src, max);
+ SAFE_FREE(ucs2_src);
+ return dest;
+}
+
+/*******************************************************************
+convert and duplicate an ascii string
+********************************************************************/
+smb_ucs2_t *strdup_wa(const char *src)
+{
+ return strndup_wa(src, 0);
+}
+
+/* if len == 0 then duplicate the whole string */
+smb_ucs2_t *strndup_wa(const char *src, size_t len)
+{
+ smb_ucs2_t *dest, *s;
+
+ s = acnv_dosu2(src);
+ if (!len) len = strlen_w(s);
+ dest = (smb_ucs2_t *)malloc((len + 1) * sizeof(smb_ucs2_t));
+ if (!dest) {
+ DEBUG(0,("strdup_w: out of memory!\n"));
+ SAFE_FREE(s);
+ return NULL;
+ }
+
+ memcpy(dest, src, len * sizeof(smb_ucs2_t));
+ dest[len] = 0;
+
+ SAFE_FREE(s);
+ return dest;
+}
+
+/*******************************************************************
+append a string of len bytes and add a terminator
+********************************************************************/
+
+smb_ucs2_t *strncat_wa(smb_ucs2_t *dest, const char *src, const size_t max)
+{
+ smb_ucs2_t *ucs2_src;
+
+ if (!dest || !src) return NULL;
+ if (!(ucs2_src = acnv_uxu2(src)))
+ return NULL;
+
+ strncat_w(dest, ucs2_src, max);
+ SAFE_FREE(ucs2_src);
+ return dest;
+}
+
+smb_ucs2_t *strcat_wa(smb_ucs2_t *dest, const char *src)
+{
+ smb_ucs2_t *ucs2_src;
+
+ if (!dest || !src) return NULL;
+ if (!(ucs2_src = acnv_uxu2(src)))
+ return NULL;
+
+ strcat_w(dest, ucs2_src);
+ SAFE_FREE(ucs2_src);
+ return dest;
+}
+
+BOOL trim_string_wa(smb_ucs2_t *s, const char *front,
+ const char *back)
+{
+ wpstring f, b;
+
+ if (front) push_ucs2(NULL, f, front, sizeof(wpstring) - 1, STR_TERMINATE);
+ else *f = 0;
+ if (back) push_ucs2(NULL, b, back, sizeof(wpstring) - 1, STR_TERMINATE);
+ else *b = 0;
+ return trim_string_w(s, f, b);
+}
+
+/*******************************************************************
+ returns the length in number of wide characters
+ ******************************************************************/
+int unistrlen(uint16 *s)
+{
+ int len;
+
+ if (!s)
+ return -1;
+
+ for (len=0; *s; s++,len++);
+
+ return len;
+}
+
+/*******************************************************************
+ Strcpy for unicode strings. returns length (in num of wide chars)
+********************************************************************/
+
+int unistrcpy(uint16 *dst, uint16 *src)
+{
+ int num_wchars = 0;
+
+ while (*src) {
+ *dst++ = *src++;
+ num_wchars++;
+ }
+ *dst = 0;
+
+ return num_wchars;
+}
diff --git a/source3/lib/wins_srv.c b/source3/lib/wins_srv.c
new file mode 100644
index 0000000000..0181ee0956
--- /dev/null
+++ b/source3/lib/wins_srv.c
@@ -0,0 +1,339 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Christopher R. Hertel 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* -------------------------------------------------------------------------- **
+ * Discussion...
+ *
+ * This module implements WINS failover.
+ *
+ * Microsoft's WINS servers provide a feature called WINS replication,
+ * which synchronises the WINS name databases between two or more servers.
+ * This means that the two servers can be used interchangably (more or
+ * less). WINS replication is particularly useful if you are trying to
+ * synchronise the WINS namespace between servers in remote locations, or
+ * if your WINS servers tend to crash a lot.
+ *
+ * WINS failover allows the client to 'switch' to a different WINS server
+ * if the current WINS server mysteriously disappears. On Windows
+ * systems, this is typically represented as 'primary' and 'secondary'
+ * WINS servers.
+ *
+ * Failover only works if the WINS servers are synced. If they are not,
+ * then
+ * a) if the primary WINS server never fails the client will never 'see'
+ * the secondary (or tertiary or...) WINS server name space.
+ * b) if the primary *does* fail, the client will be entering an
+ * unfamiliar namespace. The client itself will not be registered in
+ * that namespace and any names which match names in the previous
+ * space will likely resolve to different host IP addresses.
+ *
+ * One key thing to remember regarding WINS failover is that Samba does
+ * not (yet) implement WINS replication. For those interested, sniff port
+ * 42 (TCP? UDP? ...dunno off hand) and see what two MS WINS servers do.
+ *
+ * At this stage, only failover is implemented. The next thing is to add
+ * support for multi-WINS server registration and query (multi-membership).
+ *
+ * Multi-membership is a little wierd. The idea is that the client can
+ * register itself with multiple non-replicated WINS servers, and query
+ * all of those servers (in a prescribed sequence) to resolve a name.
+ *
+ * The implications of multi-membership are not quite clear. Worth
+ * trying, I suppose. Changes will be needed in the name query and
+ * registration code to accomodate this feature. Also, there will need to
+ * be some sort of syntax extension for the 'wins server' parameter in
+ * smb.conf. I'm thinking that a colon could be used as a separator.
+ *
+ * Of course, for each WINS namespace there might be multiple, synced WINS
+ * servers. The change to this module would likely be the addition of a
+ * linked list of linked lists.
+ *
+ * crh@samba.org
+ */
+
+/* -------------------------------------------------------------------------- **
+ * Defines...
+ *
+ * NECROMANCYCLE - The dead server retry period, in seconds. When a WINS
+ * server is declared dead, wait this many seconds before
+ * attempting to communicate with it.
+ */
+
+#define NECROMANCYCLE 600 /* 600 seconds == 10 minutes. */
+
+/* -------------------------------------------------------------------------- **
+ * Typedefs...
+ */
+
+typedef struct
+ {
+ ubi_slNode node; /* Linked list node structure. */
+ time_t mourning; /* If > current time then server is dead, Jim. */
+ char *server; /* DNS name or IP of NBNS server to query. */
+ struct in_addr ip_addr; /* Cache translated IP. */
+ } list_entry;
+
+/* -------------------------------------------------------------------------- **
+ * Private, static variables.
+ */
+
+static ubi_slNewList( wins_srv_list );
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+
+BOOL wins_srv_load_list( char *src )
+ /* ------------------------------------------------------------------------ **
+ * Create or recreate the linked list of failover WINS servers.
+ *
+ * Input: src - String of DNS names and/or IP addresses delimited by the
+ * characters listed in LIST_SEP (see include/local.h).
+ *
+ * Output: True if at least one name or IP could be parsed out of the
+ * list, else False.
+ *
+ * Notes: There is no syntax checking done on the names or IPs. We do
+ * check to see if the field is an IP, in which case we copy it
+ * to the ip_addr field of the entry. Don't bother to to a host
+ * name lookup on all names now. They're done as needed in
+ * wins_srv_ip().
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ list_entry *entry;
+ char *p = src;
+ pstring wins_id_bufr;
+ unsigned long count;
+
+ /* Empty the list. */
+ while( NULL != (entry =(list_entry *)ubi_slRemHead( wins_srv_list )) )
+ {
+ SAFE_FREE( entry->server );
+ SAFE_FREE( entry );
+ }
+ (void)ubi_slInitList( wins_srv_list ); /* shouldn't be needed */
+
+ /* Parse out the DNS names or IP addresses of the WINS servers. */
+ DEBUG( 4, ("wins_srv_load_list(): Building WINS server list:\n") );
+ while( next_token( &p, wins_id_bufr, LIST_SEP, sizeof( wins_id_bufr ) ) )
+ {
+ entry = (list_entry *)malloc( sizeof( list_entry ) );
+ if( NULL == entry )
+ {
+ DEBUG( 0, ("wins_srv_load_list(): malloc(list_entry) failed.\n") );
+ }
+ else
+ {
+ entry->mourning = 0;
+ /* Create a copy of the server name and store it in the list. */
+ if( NULL == (entry->server = strdup( wins_id_bufr )) )
+ {
+ SAFE_FREE( entry );
+ DEBUG( 0,
+ ("wins_srv_load_list(): strdup(\"%s\") failed.\n", wins_id_bufr) );
+ }
+ else
+ {
+ /* Add server to list.
+ * If the server name was actually an IP address we will store that
+ * too. It it was a DNS name, we will wait until we need to use
+ * the WINS server before doing the DNS lookup. Since this may be
+ * a list, and since we will reload the list whenever smb.conf is
+ * reloaded, there's no point in trying to look up names until we
+ * need them. ...of course, once we do the lookup we will cache
+ * the result. See wins_srv_ip().
+ */
+ if( is_ipaddress( wins_id_bufr ) )
+ entry->ip_addr = *interpret_addr2( wins_id_bufr );
+ else
+ entry->ip_addr = *interpret_addr2( "0.0.0.0" );
+ (void)ubi_slAddTail( wins_srv_list, entry );
+ DEBUGADD( 4, ("%s,\n", wins_id_bufr) );
+ }
+ }
+ }
+
+ count = ubi_slCount( wins_srv_list );
+ DEBUGADD( 4,
+ ( "%d WINS server%s listed.\n", (int)count, (1==count)?"":"s" ) );
+
+ return( (count > 0) ? True : False );
+ } /* wins_srv_load_list */
+
+
+struct in_addr wins_srv_ip( void )
+ /* ------------------------------------------------------------------------ **
+ * Return the IP address of an NBNS (WINS) server thought to be active.
+ *
+ * Input: none.
+ *
+ * Output: An IP address in struct in_addr form.
+ *
+ * Notes: This function will return the IP address of the first available
+ * NBNS (WINS) server. The order of the list is determined in
+ * smb.conf. If all of the WINS servers have been marked 'dead'
+ * then the zero IP (0.0.0.0) is returned. The zero IP is not a
+ * valid Unicast address on any system.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ time_t now = time(NULL);
+ list_entry *entry = (list_entry *)ubi_slFirst( wins_srv_list );
+
+ while( NULL != entry )
+ {
+ if( now >= entry->mourning ) /* Found a live one. */
+ {
+ /* If we don't have the IP, look it up. */
+ if( is_zero_ip( entry->ip_addr ) )
+ entry->ip_addr = *interpret_addr2( entry->server );
+
+ /* If we still don't have the IP then kill it, else return it. */
+ if( is_zero_ip( entry->ip_addr ) )
+ entry->mourning = now + NECROMANCYCLE;
+ else
+ return( entry->ip_addr );
+ }
+ entry = (list_entry *)ubi_slNext( entry );
+ }
+
+ /* If there are no live entries, return the zero IP. */
+ return( *interpret_addr2( "0.0.0.0" ) );
+ } /* wins_srv_ip */
+
+
+char *wins_srv_name( void )
+ /* ------------------------------------------------------------------------ **
+ * Return the name of first live WINS server in the list.
+ *
+ * Input: none.
+ *
+ * Output: A pointer to a string containing either the DNS name or IP
+ * address of the WINS server as given in the WINS SERVER
+ * parameter in smb.conf, or NULL if no (live) WINS servers are
+ * in the list.
+ *
+ * Notes: This function will return the name of the first available
+ * NBNS (WINS) server. The order of the list is determined in
+ * smb.conf. If all of the WINS servers have been marked 'dead'
+ * then NULL is returned.
+ *
+ * - This function does not verify that the name can be mapped to
+ * an IP address, or that the WINS server is running.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ time_t now = time(NULL);
+ list_entry *entry = (list_entry *)ubi_slFirst( wins_srv_list );
+
+ while( NULL != entry )
+ {
+ if( now >= entry->mourning )
+ return( entry->server ); /* Found a live one. */
+ entry = (list_entry *)ubi_slNext( entry );
+ }
+
+ /* If there are no live entries, return NULL. */
+ return( NULL );
+ } /* wins_srv_name */
+
+
+void wins_srv_died( struct in_addr boothill_ip )
+ /* ------------------------------------------------------------------------ **
+ * Called to indicate that a specific WINS server has died.
+ *
+ * Input: boothill_ip - IP address of an NBNS (WINS) server that has
+ * failed.
+ *
+ * Notes: This function marks the record 'dead' for NECROMANCYCLE
+ * seconds.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ list_entry *entry;
+
+ if( is_zero_ip( boothill_ip ) )
+ {
+ DEBUG( 4, ("wins_srv_died(): Invalid request to mark zero IP down.\n") );
+ return;
+ }
+
+ entry = (list_entry *)ubi_slFirst( wins_srv_list );
+ while( NULL != entry )
+ {
+ /* Match based on IP. */
+ if( ip_equal( boothill_ip, entry->ip_addr ) )
+ {
+ entry->mourning = time(NULL) + NECROMANCYCLE;
+ entry->ip_addr.s_addr = 0; /* Force a re-lookup at re-birth. */
+ DEBUG( 2, ( "wins_srv_died(): WINS server %s appears to be down.\n",
+ entry->server ) );
+ return;
+ }
+ entry = (list_entry *)ubi_slNext( entry );
+ }
+
+ if( DEBUGLVL( 1 ) )
+ {
+ dbgtext( "wins_srv_died(): Could not mark WINS server %s down.\n",
+ inet_ntoa( boothill_ip ) );
+ dbgtext( "Address not found in server list.\n" );
+ }
+ } /* wins_srv_died */
+
+
+unsigned long wins_srv_count( void )
+ /* ------------------------------------------------------------------------ **
+ * Return the total number of entries in the list, dead or alive.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ unsigned long count = ubi_slCount( wins_srv_list );
+
+ if( DEBUGLVL( 8 ) )
+ {
+ list_entry *entry = (list_entry *)ubi_slFirst( wins_srv_list );
+ time_t now = time(NULL);
+
+ dbgtext( "wins_srv_count: WINS status: %ld servers.\n", count );
+ while( NULL != entry )
+ {
+ dbgtext( " %s <%s>: ", entry->server, inet_ntoa( entry->ip_addr ) );
+ if( now >= entry->mourning )
+ dbgtext( "alive\n" );
+ else
+ dbgtext( "dead for %d more seconds\n", (int)(entry->mourning - now) );
+
+ entry = (list_entry *)ubi_slNext( entry );
+ }
+ }
+
+ return( count );
+ } /* wins_srv_count */
+
+/* ========================================================================== */
diff --git a/source3/lib/xfile.c b/source3/lib/xfile.c
new file mode 100644
index 0000000000..00ea6e5cac
--- /dev/null
+++ b/source3/lib/xfile.c
@@ -0,0 +1,339 @@
+/*
+ Unix SMB/CIFS implementation.
+ stdio replacement
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ stdio is very convenient, but on some systems the file descriptor
+ in FILE* is 8 bits, so it fails when more than 255 files are open.
+
+ XFILE replaces stdio. It is less efficient, but at least it works
+ when you have lots of files open
+
+ The main restriction on XFILE is that it doesn't support seeking,
+ and doesn't support O_RDWR. That keeps the code simple.
+*/
+
+#include "includes.h"
+
+static XFILE _x_stdin = { 0, NULL, NULL, 0, 0, O_RDONLY, X_IOFBF, 0 };
+static XFILE _x_stdout = { 1, NULL, NULL, 0, 0, O_WRONLY, X_IOLBF, 0 };
+static XFILE _x_stderr = { 2, NULL, NULL, 0, 0, O_WRONLY, X_IONBF, 0 };
+
+XFILE *x_stdin = &_x_stdin;
+XFILE *x_stdout = &_x_stdout;
+XFILE *x_stderr = &_x_stderr;
+
+#define XBUFSIZE BUFSIZ
+
+#define X_FLAG_EOF 1
+#define X_FLAG_ERROR 2
+
+/* simulate setvbuf() */
+int x_setvbuf(XFILE *f, char *buf, int mode, size_t size)
+{
+ x_fflush(f);
+ if (f->bufused) return -1;
+
+ /* on files being read full buffering is the only option */
+ if ((f->open_flags & O_ACCMODE) == O_RDONLY) {
+ mode = X_IOFBF;
+ }
+
+ /* destroy any earlier buffer */
+ SAFE_FREE(f->buf);
+ f->buf = 0;
+ f->bufsize = 0;
+ f->next = NULL;
+ f->bufused = 0;
+ f->buftype = mode;
+
+ if (f->buftype == X_IONBF) return 0;
+
+ /* if buffering then we need some size */
+ if (size == 0) size = XBUFSIZE;
+
+ f->bufsize = size;
+ f->bufused = 0;
+
+ return 0;
+}
+
+/* allocate the buffer */
+static int x_allocate_buffer(XFILE *f)
+{
+ if (f->buf) return 1;
+ if (f->bufsize == 0) return 0;
+ f->buf = malloc(f->bufsize);
+ if (!f->buf) return 0;
+ f->next = f->buf;
+ return 1;
+}
+
+
+/* this looks more like open() than fopen(), but that is quite deliberate.
+ I want programmers to *think* about O_EXCL, O_CREAT etc not just
+ get them magically added
+*/
+XFILE *x_fopen(const char *fname, int flags, mode_t mode)
+{
+ XFILE *ret;
+
+ ret = (XFILE *)malloc(sizeof(XFILE));
+ if (!ret) return NULL;
+
+ memset(ret, 0, sizeof(XFILE));
+
+ if ((flags & O_ACCMODE) == O_RDWR) {
+ /* we don't support RDWR in XFILE - use file
+ descriptors instead */
+ errno = EINVAL;
+ return NULL;
+ }
+
+ ret->open_flags = flags;
+
+ ret->fd = sys_open(fname, flags, mode);
+ if (ret->fd == -1) {
+ SAFE_FREE(ret);
+ return NULL;
+ }
+
+ x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
+
+ return ret;
+}
+
+/* simulate fclose() */
+int x_fclose(XFILE *f)
+{
+ int ret;
+
+ /* make sure we flush any buffered data */
+ x_fflush(f);
+
+ ret = close(f->fd);
+ f->fd = -1;
+ if (f->buf) {
+ /* make sure data can't leak into a later malloc */
+ memset(f->buf, 0, f->bufsize);
+ SAFE_FREE(f->buf);
+ }
+ SAFE_FREE(f);
+ return ret;
+}
+
+/* simulate fwrite() */
+int x_fwrite(const void *p, size_t size, size_t nmemb, XFILE *f)
+{
+ int ret, total=0;
+
+ /* we might be writing unbuffered */
+ if (f->buftype == X_IONBF ||
+ (!f->buf && !x_allocate_buffer(f))) {
+ ret = write(f->fd, p, size*nmemb);
+ if (ret == -1) return -1;
+ return ret/size;
+ }
+
+
+ while (total < size*nmemb) {
+ int n = f->bufsize - f->bufused;
+ n = MIN(n, (size*nmemb)-total);
+
+ if (n == 0) {
+ /* it's full, flush it */
+ x_fflush(f);
+ continue;
+ }
+
+ memcpy(f->buf + f->bufused, total+(const char *)p, n);
+ f->bufused += n;
+ total += n;
+ }
+
+ /* when line buffered we need to flush at the last linefeed. This can
+ flush a bit more than necessary, but that is harmless */
+ if (f->buftype == X_IOLBF && f->bufused) {
+ int i;
+ for (i=size-1; i>=0; i--) {
+ if (*(i+(const char *)p) == '\n') {
+ x_fflush(f);
+ break;
+ }
+ }
+ }
+
+ return total/size;
+}
+
+/* thank goodness for asprintf() */
+int x_vfprintf(XFILE *f, const char *format, va_list ap)
+{
+ char *p;
+ int len, ret;
+ len = vasprintf(&p, format, ap);
+ if (len <= 0) return len;
+ ret = x_fwrite(p, 1, len, f);
+ SAFE_FREE(p);
+ return ret;
+}
+
+int x_fprintf(XFILE *f, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = x_vfprintf(f, format, ap);
+ va_end(ap);
+ return ret;
+}
+
+/* at least fileno() is simple! */
+int x_fileno(XFILE *f)
+{
+ return f->fd;
+}
+
+/* simulate fflush() */
+int x_fflush(XFILE *f)
+{
+ int ret;
+
+ if (f->flags & X_FLAG_ERROR) return -1;
+
+ if ((f->open_flags & O_ACCMODE) != O_WRONLY) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (f->bufused == 0) return 0;
+
+ ret = write(f->fd, f->buf, f->bufused);
+ if (ret == -1) return -1;
+
+ f->bufused -= ret;
+ if (f->bufused > 0) {
+ f->flags |= X_FLAG_ERROR;
+ memmove(f->buf, ret + (char *)f->buf, f->bufused);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* simulate setbuffer() */
+void x_setbuffer(XFILE *f, char *buf, size_t size)
+{
+ x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, size);
+}
+
+/* simulate setbuf() */
+void x_setbuf(XFILE *f, char *buf)
+{
+ x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, XBUFSIZE);
+}
+
+/* simulate setlinebuf() */
+void x_setlinebuf(XFILE *f)
+{
+ x_setvbuf(f, NULL, X_IOLBF, 0);
+}
+
+
+/* simulate feof() */
+int x_feof(XFILE *f)
+{
+ if (f->flags & X_FLAG_EOF) return 1;
+ return 0;
+}
+
+/* simulate ferror() */
+int x_ferror(XFILE *f)
+{
+ if (f->flags & X_FLAG_ERROR) return 1;
+ return 0;
+}
+
+/* fill the read buffer */
+static void x_fillbuf(XFILE *f)
+{
+ int n;
+
+ if (f->bufused) return;
+
+ if (!f->buf && !x_allocate_buffer(f)) return;
+
+ n = read(f->fd, f->buf, f->bufsize);
+ if (n <= 0) return;
+ f->bufused = n;
+ f->next = f->buf;
+}
+
+/* simulate fgetc() */
+int x_fgetc(XFILE *f)
+{
+ int ret;
+
+ if (f->flags & (X_FLAG_EOF | X_FLAG_ERROR)) return EOF;
+
+ if (f->bufused == 0) x_fillbuf(f);
+
+ if (f->bufused == 0) {
+ f->flags |= X_FLAG_EOF;
+ return EOF;
+ }
+
+ ret = *(unsigned char *)(f->next);
+ f->next++;
+ f->bufused--;
+ return ret;
+}
+
+/* simulate fread */
+size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
+{
+ size_t total = 0;
+ while (total < size*nmemb) {
+ int c = x_fgetc(f);
+ if (c == EOF) break;
+ (total+(char *)p)[0] = (char)c;
+ total++;
+ }
+ return total/size;
+}
+
+/* simulate fgets() */
+char *x_fgets(char *s, int size, XFILE *stream)
+{
+ char *s0 = s;
+ int l = size;
+ while (l>1) {
+ int c = x_fgetc(stream);
+ if (c == EOF) break;
+ *s++ = (char)c;
+ l--;
+ if (c == '\n') break;
+ }
+ if (l==size || x_ferror(stream)) {
+ return 0;
+ }
+ *s = 0;
+ return s0;
+}