summaryrefslogtreecommitdiff
path: root/source3/lib
diff options
context:
space:
mode:
authorSamba Release Account <samba-bugs@samba.org>1996-05-04 07:50:46 +0000
committerSamba Release Account <samba-bugs@samba.org>1996-05-04 07:50:46 +0000
commit0e8fd3398771da2f016d72830179507f3edda51b (patch)
treeb5d07075a85050832720033f7b26c37a301ede72 /source3/lib
downloadsamba-0e8fd3398771da2f016d72830179507f3edda51b.tar.gz
samba-0e8fd3398771da2f016d72830179507f3edda51b.tar.bz2
samba-0e8fd3398771da2f016d72830179507f3edda51b.zip
Initial version imported to CVS
(This used to be commit 291551d80711daab7b7581720bcd9a08d6096517)
Diffstat (limited to 'source3/lib')
-rw-r--r--source3/lib/access.c389
-rw-r--r--source3/lib/charcnv.c126
-rw-r--r--source3/lib/charset.c111
-rw-r--r--source3/lib/fault.c86
-rw-r--r--source3/lib/getsmbpass.c166
-rw-r--r--source3/lib/kanji.c895
-rw-r--r--source3/lib/md4.c299
-rw-r--r--source3/lib/system.c222
-rw-r--r--source3/lib/ufc.c782
-rw-r--r--source3/lib/username.c246
-rw-r--r--source3/lib/util.c4510
11 files changed, 7832 insertions, 0 deletions
diff --git a/source3/lib/access.c b/source3/lib/access.c
new file mode 100644
index 0000000000..14a84b2fb4
--- /dev/null
+++ b/source3/lib/access.c
@@ -0,0 +1,389 @@
+/*
+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 has been considerably changed from the original. Bug reports
+should be sent to Andrew.Tridgell@anu.edu.au
+*/
+
+#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
+
+
+/* return true if access should be allowed to a service*/
+BOOL check_access(int snum)
+{
+ extern int Client;
+ extern struct from_host Client_info;
+ char *denyl,*allowl;
+ BOOL ret = False;
+
+ denyl = lp_hostsdeny(snum);
+ if (denyl) denyl = strdup(denyl);
+
+ allowl = lp_hostsallow(snum);
+ if (allowl) allowl = strdup(allowl);
+
+
+ fromhost(Client,&Client_info);
+
+ if ((!denyl || *denyl==0) && (!allowl || *allowl==0))
+ ret = True;
+
+ 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 (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);
+}
+
+/* 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)())
+{
+ 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.
+ */
+
+ /* jkf -- can get called recursively with NULL list */
+ listcopy = (list == 0) ? (char *)0 : strdup(list);
+
+ /*
+ * Process tokens one at a time. We have exhausted all possible matches
+ * when we reach an "EXCEPT" token or the end of the list. If we do find
+ * a match, look for an "EXCEPT" list and recurse to determine whether
+ * 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 */
+ break;
+ if ((match = (*match_fn) (tok, item))) /* YES 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);
+}
+
+
+/* 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.
+ */
+
+ 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);
+ }
+ }
+#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);
+}
+
+/* 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);
+}
+
+
+/* fromhost - find out what is at the other end of a socket */
+BOOL fromhost(int sock,struct from_host *f)
+{
+ 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);
+}
+
+/* matchname - determine if host name matches IP address */
+static int matchname(char *remotehost,struct in_addr addr)
+{
+ 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);
+ }
+
+ /* 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);
+}
+
+
diff --git a/source3/lib/charcnv.c b/source3/lib/charcnv.c
new file mode 100644
index 0000000000..049390f2a4
--- /dev/null
+++ b/source3/lib/charcnv.c
@@ -0,0 +1,126 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Character set conversion 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.
+
+*/
+#include "includes.h"
+extern int DEBUGLEVEL;
+
+static char cvtbuf[1024];
+
+static mapsinited = 0;
+
+static char unix2dos[256];
+static char dos2unix[256];
+
+static void initmaps() {
+ int k;
+
+ for (k = 0; k < 256; k++) unix2dos[k] = k;
+ for (k = 0; k < 256; k++) dos2unix[k] = k;
+
+ mapsinited = 1;
+}
+
+static void update_map(char * str) {
+ char *p;
+
+ for (p = str; *p; p++) {
+ if (p[1]) {
+ unix2dos[(unsigned char)*p] = p[1];
+ dos2unix[(unsigned char)p[1]] = *p;
+ p++;
+ }
+ }
+}
+
+static void initiso() {
+
+ if (!mapsinited) initmaps();
+
+ 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");
+}
+
+/*
+ * Convert unix to dos
+ */
+char *
+unix2dos_format(char *str,BOOL overwrite)
+{
+ char *p;
+ char *dp;
+
+ 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;
+ }
+}
+
+/*
+ * Convert dos to unix
+ */
+char *
+dos2unix_format (char *str, BOOL overwrite)
+{
+ char *p;
+ char *dp;
+
+ 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;
+ }
+}
+
+
+/*
+ * Interpret character set.
+ */
+int
+interpret_character_set (char *str, int def)
+{
+
+ if (strequal (str, "iso8859-1")) {
+ initiso();
+ return def;
+ } else {
+ DEBUG(0,("unrecognized character set\n"));
+ }
+ return def;
+}
diff --git a/source3/lib/charset.c b/source3/lib/charset.c
new file mode 100644
index 0000000000..ada3ef790a
--- /dev/null
+++ b/source3/lib/charset.c
@@ -0,0 +1,111 @@
+/*
+ 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/fault.c b/source3/lib/fault.c
new file mode 100644
index 0000000000..20c75f7876
--- /dev/null
+++ b/source3/lib/fault.c
@@ -0,0 +1,86 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Critical Fault 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.
+*/
+
+#ifdef LINUX
+#define __KERNEL__
+#endif
+
+#include "includes.h"
+extern int DEBUGLEVEL;
+
+
+static void (*cont_fn)();
+
+
+/*******************************************************************
+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"));
+
+#if AJT
+ ajt_panic();
+#endif
+
+ if (cont_fn)
+ {
+ fault_setup(cont_fn);
+ cont_fn(NULL);
+#ifdef SIGSEGV
+ signal(SIGSEGV,SIGNAL_CAST SIG_DFL);
+#endif
+#ifdef SIGBUS
+ signal(SIGBUS,SIGNAL_CAST SIG_DFL);
+#endif
+ return; /* this should cause a core dump */
+ }
+ exit(1);
+}
+
+/****************************************************************************
+catch serious errors
+****************************************************************************/
+static void sig_fault(int sig)
+{
+ fault_report(sig);
+}
+
+/*******************************************************************
+setup our fault handlers
+********************************************************************/
+void fault_setup(void (*fn)())
+{
+ cont_fn = fn;
+
+#ifdef SIGSEGV
+ signal(SIGSEGV,SIGNAL_CAST sig_fault);
+#endif
+#ifdef SIGBUS
+ signal(SIGBUS,SIGNAL_CAST sig_fault);
+#endif
+}
+
+
+
diff --git a/source3/lib/getsmbpass.c b/source3/lib/getsmbpass.c
new file mode 100644
index 0000000000..07a7dbfd9b
--- /dev/null
+++ b/source3/lib/getsmbpass.c
@@ -0,0 +1,166 @@
+/* Copyright (C) 1992, 1993, 1994 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
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/* Modified to use with samba by Jeremy Allison, 8th July 1995. */
+
+#include "includes.h"
+
+#ifdef REPLACE_GETPASS
+
+#ifdef SYSV_TERMIO
+
+/* SYSTEM V TERMIO HANDLING */
+
+static struct termio t;
+
+#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)
+
+#ifndef TCSAFLUSH
+#define TCSAFLUSH 1
+#endif
+
+#ifndef TCSANOW
+#define TCSANOW 0
+#endif
+
+int tcgetattr(int fd, struct termio *t)
+{
+ return ioctl(fd, TCGETA, t);
+}
+
+int tcsetattr(int fd, int flags, const struct termio *t)
+{
+ if(flags & TCSAFLUSH)
+ ioctl(fd, TCFLSH, TCIOFLUSH);
+ return ioctl(fd, TCSETS, t);
+}
+
+#else /* SYSV_TERMIO */
+#ifdef BSD_TERMIO
+
+/* BSD TERMIO HANDLING */
+
+static struct sgttyb t;
+
+#define ECHO_IS_ON(t) ((t).sg_flags & ECHO)
+#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)
+{
+ return ioctl(fd, TIOCGETP, (char *)t);
+}
+
+int tcsetattr(int fd, int flags, const struct sgttyb *t)
+{
+ return ioctl(fd, TIOCSETP, (char *)t);
+}
+
+#else /* BSD_TERMIO */
+
+/* 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)
+{
+ FILE *in, *out;
+ int echo_off;
+ static char buf[256];
+ static size_t bufsize = sizeof(buf);
+ size_t nread;
+
+ /* Catch problematic signals */
+ signal(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. */
+
+ in = fopen ("/dev/tty", "w+");
+ if (in == NULL)
+ {
+ in = stdin;
+ out = stderr;
+ }
+ else
+ out = in;
+
+ setvbuf(in, NULL, _IONBF, 0);
+
+ /* Turn echoing off if it is on now. */
+
+ if (tcgetattr (fileno (in), &t) == 0)
+ {
+ if (ECHO_IS_ON(t))
+ {
+ TURN_ECHO_OFF(t);
+ echo_off = tcsetattr (fileno (in), TCSAFLUSH, &t) == 0;
+ TURN_ECHO_ON(t);
+ }
+ else
+ echo_off = 0;
+ }
+ else
+ echo_off = 0;
+
+ /* Write the prompt. */
+ fputs (prompt, out);
+ fflush (out);
+
+ /* Read the password. */
+ buf[0] = 0;
+ fgets(buf, bufsize, in);
+ nread = strlen(buf);
+ if (buf[nread - 1] == '\n')
+ buf[nread - 1] = '\0';
+
+ /* Restore echoing. */
+ if (echo_off)
+ (void) tcsetattr (fileno (in), TCSANOW, &t);
+
+ if (in != stdin)
+ /* We opened the terminal; now close it. */
+ fclose (in);
+
+ /* Catch problematic signals */
+ signal(SIGINT, SIGNAL_CAST SIG_DFL);
+
+ printf("\n");
+ return buf;
+}
+
+#else
+
+void getsmbpasswd_dummy() {;}
+#endif
diff --git a/source3/lib/kanji.c b/source3/lib/kanji.c
new file mode 100644
index 0000000000..0af476eb15
--- /dev/null
+++ b/source3/lib/kanji.c
@@ -0,0 +1,895 @@
+/*
+ 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
new file mode 100644
index 0000000000..485e231a78
--- /dev/null
+++ b/source3/lib/md4.c
@@ -0,0 +1,299 @@
+#ifdef SMB_PASSWD
+/*
+ This code is from rfc1186.
+*/
+
+ /*
+ ** ********************************************************************
+ ** md4.c -- Implementation of MD4 Message Digest Algorithm **
+ ** Updated: 2/16/90 by Ronald L. Rivest **
+ ** (C) 1990 RSA Data Security, Inc. **
+ ** ********************************************************************
+ */
+
+ /*
+ ** 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)
+ */
+
+ /* 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)
+
+ /* 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);
+ }
+
+ /* 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;
+ }
+
+ /* 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 < 16; i++) {
+ t = X[i];
+ SIVAL(X,i*4,t);
+ }
+ }
+
+ /* 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;
+ }
+
+ /* 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/system.c b/source3/lib/system.c
new file mode 100644
index 0000000000..938746e9c9
--- /dev/null
+++ b/source3/lib/system.c
@@ -0,0 +1,222 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Samba system utilities
+ 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.
+*/
+
+#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:
+
+ - 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
+*/
+
+
+/*******************************************************************
+this replaces the normal select() system call
+return if some data has arrived on one of the file descriptors
+return -1 means error
+********************************************************************/
+#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)
+{
+ fd_set fds2;
+ int counter=0;
+ int found=0;
+
+ FD_ZERO(&fds2);
+
+ while (1)
+ {
+ int i;
+ for (i=0;i<255;i++) {
+ if (FD_ISSET(i,fds) && pollfd(i)>0) {
+ found++;
+ FD_SET(i,&fds2);
+ }
+ }
+
+ if (found) {
+ memcpy((void *)fds,(void *)&fds2,sizeof(fds2));
+ return(found);
+ }
+
+ if (tval && tval.tv_sec < counter) return(0);
+ sleep(1);
+ counter++;
+ }
+}
+
+#else
+int sys_select(fd_set *fds,struct timeval *tval)
+{
+ struct timeval t2;
+ int selrtn;
+
+ 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);
+
+ return(selrtn);
+}
+#endif
+
+
+/*******************************************************************
+just a unlink wrapper
+********************************************************************/
+int sys_unlink(char *fname)
+{
+ return(unlink(dos_to_unix(fname,False)));
+}
+
+
+/*******************************************************************
+a simple open() wrapper
+********************************************************************/
+int sys_open(char *fname,int flags,int mode)
+{
+ return(open(dos_to_unix(fname,False),flags,mode));
+}
+
+
+/*******************************************************************
+a simple opendir() wrapper
+********************************************************************/
+DIR *sys_opendir(char *dname)
+{
+ return(opendir(dos_to_unix(dname,False)));
+}
+
+
+/*******************************************************************
+and a stat() wrapper
+********************************************************************/
+int sys_stat(char *fname,struct stat *sbuf)
+{
+ return(stat(dos_to_unix(fname,False),sbuf));
+}
+
+/*******************************************************************
+don't forget lstat()
+********************************************************************/
+int sys_lstat(char *fname,struct stat *sbuf)
+{
+ return(lstat(dos_to_unix(fname,False),sbuf));
+}
+
+
+/*******************************************************************
+mkdir() gets a wrapper
+********************************************************************/
+int sys_mkdir(char *dname,int mode)
+{
+ return(mkdir(dos_to_unix(dname,False),mode));
+}
+
+
+/*******************************************************************
+do does rmdir()
+********************************************************************/
+int sys_rmdir(char *dname)
+{
+ return(rmdir(dos_to_unix(dname,False)));
+}
+
+
+/*******************************************************************
+I almost forgot chdir()
+********************************************************************/
+int sys_chdir(char *dname)
+{
+ return(chdir(dos_to_unix(dname,False)));
+}
+
+
+/*******************************************************************
+now for utime()
+********************************************************************/
+int sys_utime(char *fname,struct utimbuf *times)
+{
+ return(utime(dos_to_unix(fname,False),times));
+}
+
+/*******************************************************************
+for rename()
+********************************************************************/
+int sys_rename(char *from, char *to)
+{
+#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 */
+}
+
+
+/*******************************************************************
+chown isn't used much but OS/2 doesn't have it
+********************************************************************/
+int sys_chown(char *fname,int uid,int gid)
+{
+#ifdef NO_CHOWN
+ DEBUG(1,("Warning - chown(%s,%d,%d) not done\n",fname,uid,gid));
+#else
+ return(chown(fname,uid,gid));
+#endif
+}
+
+/*******************************************************************
+os/2 also doesn't have chroot
+********************************************************************/
+int sys_chroot(char *dname)
+{
+#ifdef NO_CHROOT
+ DEBUG(1,("Warning - chroot(%s) not done\n",dname));
+#else
+ return(chroot(dname));
+#endif
+}
diff --git a/source3/lib/ufc.c b/source3/lib/ufc.c
new file mode 100644
index 0000000000..8417285821
--- /dev/null
+++ b/source3/lib/ufc.c
@@ -0,0 +1,782 @@
+/*
+ This bit of code was derived from the UFC-crypt package which
+ carries the following copyright
+
+ Modified for use by Samba by Andrew Tridgell, October 1994
+
+ Note that this routine is only faster on some machines. Under Linux 1.1.51
+ libc 4.5.26 I actually found this routine to be slightly slower.
+
+ Under SunOS I found a huge speedup by using these routines
+ (a factor of 20 or so)
+
+ Warning: I've had a report from Steve Kennedy <steve@gbnet.org>
+ that this crypt routine may sometimes get the wrong answer. Only
+ use UFC_CRYT if you really need it.
+
+*/
+
+#ifdef UFC_CRYPT
+
+/*
+ * UFC-crypt: ultra fast crypt(3) implementation
+ *
+ * Copyright (C) 1991, 1992, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * @(#)crypt_util.c 2.31 02/08/92
+ *
+ * Support routines
+ *
+ */
+#include "includes.h"
+
+
+#ifndef long32
+#define long32 int32
+#endif
+
+#ifndef long64
+#define long64 int64
+#endif
+
+#ifndef ufc_long
+#define ufc_long unsigned
+#endif
+
+#ifndef _UFC_64_
+#define _UFC_32_
+#endif
+
+/*
+ * Permutation done once on the 56 bit
+ * key derived from the original 8 byte ASCII key.
+ */
+static int pc1[56] = {
+ 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
+ 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
+};
+
+/*
+ * How much to rotate each 28 bit half of the pc1 permutated
+ * 56 bit key before using pc2 to give the i' key
+ */
+static int rots[16] = {
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+};
+
+/*
+ * Permutation giving the key
+ * of the i' DES round
+ */
+static int pc2[48] = {
+ 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
+};
+
+/*
+ * The E expansion table which selects
+ * bits from the 32 bit intermediate result.
+ */
+static int esel[48] = {
+ 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9,
+ 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
+ 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
+ 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1
+};
+static int e_inverse[64];
+
+/*
+ * Permutation done on the
+ * result of sbox lookups
+ */
+static int perm32[32] = {
+ 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
+ 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
+};
+
+/*
+ * The sboxes
+ */
+static int sbox[8][4][16]= {
+ { { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 },
+ { 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 },
+ { 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0 },
+ { 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 }
+ },
+
+ { { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 },
+ { 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 },
+ { 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15 },
+ { 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 }
+ },
+
+ { { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 },
+ { 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 },
+ { 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7 },
+ { 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 }
+ },
+
+ { { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 },
+ { 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 },
+ { 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4 },
+ { 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 }
+ },
+
+ { { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 },
+ { 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 },
+ { 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14 },
+ { 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 }
+ },
+
+ { { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 },
+ { 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 },
+ { 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6 },
+ { 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 }
+ },
+
+ { { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 },
+ { 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 },
+ { 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2 },
+ { 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 }
+ },
+
+ { { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 },
+ { 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 },
+ { 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 },
+ { 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 }
+ }
+};
+
+/*
+ * This is the final
+ * permutation matrix
+ */
+static int final_perm[64] = {
+ 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
+ 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
+ 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
+ 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25
+};
+
+/*
+ * The 16 DES keys in BITMASK format
+ */
+#ifdef _UFC_32_
+long32 _ufc_keytab[16][2];
+#endif
+
+#ifdef _UFC_64_
+long64 _ufc_keytab[16];
+#endif
+
+
+#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.')
+#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
+
+/* Macro to set a bit (0..23) */
+#define BITMASK(i) ( (1<<(11-(i)%12+3)) << ((i)<12?16:0) )
+
+/*
+ * sb arrays:
+ *
+ * Workhorses of the inner loop of the DES implementation.
+ * They do sbox lookup, shifting of this value, 32 bit
+ * permutation and E permutation for the next round.
+ *
+ * Kept in 'BITMASK' format.
+ */
+
+#ifdef _UFC_32_
+long32 _ufc_sb0[8192], _ufc_sb1[8192], _ufc_sb2[8192], _ufc_sb3[8192];
+static long32 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3};
+#endif
+
+#ifdef _UFC_64_
+long64 _ufc_sb0[4096], _ufc_sb1[4096], _ufc_sb2[4096], _ufc_sb3[4096];
+static long64 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3};
+#endif
+
+/*
+ * eperm32tab: do 32 bit permutation and E selection
+ *
+ * The first index is the byte number in the 32 bit value to be permuted
+ * - second - is the value of this byte
+ * - third - selects the two 32 bit values
+ *
+ * The table is used and generated internally in init_des to speed it up
+ */
+static ufc_long eperm32tab[4][256][2];
+
+/*
+ * do_pc1: permform pc1 permutation in the key schedule generation.
+ *
+ * The first index is the byte number in the 8 byte ASCII key
+ * - second - - the two 28 bits halfs of the result
+ * - third - selects the 7 bits actually used of each byte
+ *
+ * The result is kept with 28 bit per 32 bit with the 4 most significant
+ * bits zero.
+ */
+static ufc_long do_pc1[8][2][128];
+
+/*
+ * do_pc2: permform pc2 permutation in the key schedule generation.
+ *
+ * The first index is the septet number in the two 28 bit intermediate values
+ * - second - - - septet values
+ *
+ * Knowledge of the structure of the pc2 permutation is used.
+ *
+ * The result is kept with 28 bit per 32 bit with the 4 most significant
+ * bits zero.
+ */
+static ufc_long do_pc2[8][128];
+
+/*
+ * efp: undo an extra e selection and do final
+ * permutation giving the DES result.
+ *
+ * Invoked 6 bit a time on two 48 bit values
+ * giving two 32 bit longs.
+ */
+static ufc_long efp[16][64][2];
+
+static unsigned char bytemask[8] = {
+ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
+};
+
+static ufc_long longmask[32] = {
+ 0x80000000, 0x40000000, 0x20000000, 0x10000000,
+ 0x08000000, 0x04000000, 0x02000000, 0x01000000,
+ 0x00800000, 0x00400000, 0x00200000, 0x00100000,
+ 0x00080000, 0x00040000, 0x00020000, 0x00010000,
+ 0x00008000, 0x00004000, 0x00002000, 0x00001000,
+ 0x00000800, 0x00000400, 0x00000200, 0x00000100,
+ 0x00000080, 0x00000040, 0x00000020, 0x00000010,
+ 0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+
+/*
+ * Silly rewrite of 'bzero'. I do so
+ * because some machines don't have
+ * bzero and some don't have memset.
+ */
+
+static void clearmem(start, cnt)
+ char *start;
+ int cnt;
+ { while(cnt--)
+ *start++ = '\0';
+ }
+
+static int initialized = 0;
+
+/* lookup a 6 bit value in sbox */
+
+#define s_lookup(i,s) sbox[(i)][(((s)>>4) & 0x2)|((s) & 0x1)][((s)>>1) & 0xf];
+
+/*
+ * Initialize unit - may be invoked directly
+ * by fcrypt users.
+ */
+
+static void ufc_init_des()
+ { int comes_from_bit;
+ int bit, sg;
+ ufc_long j;
+ ufc_long mask1, mask2;
+
+ /*
+ * Create the do_pc1 table used
+ * to affect pc1 permutation
+ * when generating keys
+ */
+ for(bit = 0; bit < 56; bit++) {
+ comes_from_bit = pc1[bit] - 1;
+ mask1 = bytemask[comes_from_bit % 8 + 1];
+ mask2 = longmask[bit % 28 + 4];
+ for(j = 0; j < 128; j++) {
+ if(j & mask1)
+ do_pc1[comes_from_bit / 8][bit / 28][j] |= mask2;
+ }
+ }
+
+ /*
+ * Create the do_pc2 table used
+ * to affect pc2 permutation when
+ * generating keys
+ */
+ for(bit = 0; bit < 48; bit++) {
+ comes_from_bit = pc2[bit] - 1;
+ mask1 = bytemask[comes_from_bit % 7 + 1];
+ mask2 = BITMASK(bit % 24);
+ for(j = 0; j < 128; j++) {
+ if(j & mask1)
+ do_pc2[comes_from_bit / 7][j] |= mask2;
+ }
+ }
+
+ /*
+ * Now generate the table used to do combined
+ * 32 bit permutation and e expansion
+ *
+ * We use it because we have to permute 16384 32 bit
+ * longs into 48 bit in order to initialize sb.
+ *
+ * Looping 48 rounds per permutation becomes
+ * just too slow...
+ *
+ */
+
+ clearmem((char*)eperm32tab, sizeof(eperm32tab));
+
+ for(bit = 0; bit < 48; bit++) {
+ ufc_long mask1,comes_from;
+
+ comes_from = perm32[esel[bit]-1]-1;
+ mask1 = bytemask[comes_from % 8];
+
+ for(j = 256; j--;) {
+ if(j & mask1)
+ eperm32tab[comes_from / 8][j][bit / 24] |= BITMASK(bit % 24);
+ }
+ }
+
+ /*
+ * Create the sb tables:
+ *
+ * For each 12 bit segment of an 48 bit intermediate
+ * result, the sb table precomputes the two 4 bit
+ * values of the sbox lookups done with the two 6
+ * bit halves, shifts them to their proper place,
+ * sends them through perm32 and finally E expands
+ * them so that they are ready for the next
+ * DES round.
+ *
+ */
+ for(sg = 0; sg < 4; sg++) {
+ int j1, j2;
+ int s1, s2;
+
+ for(j1 = 0; j1 < 64; j1++) {
+ s1 = s_lookup(2 * sg, j1);
+ for(j2 = 0; j2 < 64; j2++) {
+ ufc_long to_permute, inx;
+
+ s2 = s_lookup(2 * sg + 1, j2);
+ to_permute = ((s1 << 4) | s2) << (24 - 8 * sg);
+
+#ifdef _UFC_32_
+ inx = ((j1 << 6) | j2) << 1;
+ sb[sg][inx ] = eperm32tab[0][(to_permute >> 24) & 0xff][0];
+ sb[sg][inx+1] = eperm32tab[0][(to_permute >> 24) & 0xff][1];
+ sb[sg][inx ] |= eperm32tab[1][(to_permute >> 16) & 0xff][0];
+ sb[sg][inx+1] |= eperm32tab[1][(to_permute >> 16) & 0xff][1];
+ sb[sg][inx ] |= eperm32tab[2][(to_permute >> 8) & 0xff][0];
+ sb[sg][inx+1] |= eperm32tab[2][(to_permute >> 8) & 0xff][1];
+ sb[sg][inx ] |= eperm32tab[3][(to_permute) & 0xff][0];
+ sb[sg][inx+1] |= eperm32tab[3][(to_permute) & 0xff][1];
+#endif
+#ifdef _UFC_64_
+ inx = ((j1 << 6) | j2);
+ sb[sg][inx] =
+ ((long64)eperm32tab[0][(to_permute >> 24) & 0xff][0] << 32) |
+ (long64)eperm32tab[0][(to_permute >> 24) & 0xff][1];
+ sb[sg][inx] |=
+ ((long64)eperm32tab[1][(to_permute >> 16) & 0xff][0] << 32) |
+ (long64)eperm32tab[1][(to_permute >> 16) & 0xff][1];
+ sb[sg][inx] |=
+ ((long64)eperm32tab[2][(to_permute >> 8) & 0xff][0] << 32) |
+ (long64)eperm32tab[2][(to_permute >> 8) & 0xff][1];
+ sb[sg][inx] |=
+ ((long64)eperm32tab[3][(to_permute) & 0xff][0] << 32) |
+ (long64)eperm32tab[3][(to_permute) & 0xff][1];
+#endif
+ }
+ }
+ }
+
+ /*
+ * Create an inverse matrix for esel telling
+ * where to plug out bits if undoing it
+ */
+ for(bit=48; bit--;) {
+ e_inverse[esel[bit] - 1 ] = bit;
+ e_inverse[esel[bit] - 1 + 32] = bit + 48;
+ }
+
+ /*
+ * create efp: the matrix used to
+ * undo the E expansion and effect final permutation
+ */
+ clearmem((char*)efp, sizeof efp);
+ for(bit = 0; bit < 64; bit++) {
+ int o_bit, o_long;
+ ufc_long word_value, mask1, mask2;
+ int comes_from_f_bit, comes_from_e_bit;
+ int comes_from_word, bit_within_word;
+
+ /* See where bit i belongs in the two 32 bit long's */
+ o_long = bit / 32; /* 0..1 */
+ o_bit = bit % 32; /* 0..31 */
+
+ /*
+ * And find a bit in the e permutated value setting this bit.
+ *
+ * Note: the e selection may have selected the same bit several
+ * times. By the initialization of e_inverse, we only look
+ * for one specific instance.
+ */
+ comes_from_f_bit = final_perm[bit] - 1; /* 0..63 */
+ comes_from_e_bit = e_inverse[comes_from_f_bit]; /* 0..95 */
+ 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];
+
+ for(word_value = 64; word_value--;) {
+ if(word_value & mask1)
+ efp[comes_from_word][word_value][o_long] |= mask2;
+ }
+ }
+ initialized++;
+ }
+
+/*
+ * Process the elements of the sb table permuting the
+ * bits swapped in the expansion by the current salt.
+ */
+
+#ifdef _UFC_32_
+static void shuffle_sb(k, saltbits)
+ long32 *k;
+ ufc_long saltbits;
+ { ufc_long j;
+ long32 x;
+ for(j=4096; j--;) {
+ x = (k[0] ^ k[1]) & (long32)saltbits;
+ *k++ ^= x;
+ *k++ ^= x;
+ }
+ }
+#endif
+
+#ifdef _UFC_64_
+static void shuffle_sb(k, saltbits)
+ long64 *k;
+ ufc_long saltbits;
+ { ufc_long j;
+ long64 x;
+ for(j=4096; j--;) {
+ x = ((*k >> 32) ^ *k) & (long64)saltbits;
+ *k++ ^= (x << 32) | x;
+ }
+ }
+#endif
+
+/*
+ * Setup the unit for a new salt
+ * Hopefully we'll not see a new salt in each crypt call.
+ */
+
+static unsigned char current_salt[3] = "&&"; /* invalid value */
+static ufc_long current_saltbits = 0;
+static int direction = 0;
+
+static void setup_salt(char *s1)
+ { ufc_long i, j, saltbits;
+ unsigned char *s2 = (unsigned char *)s1;
+
+ if(!initialized)
+ ufc_init_des();
+
+ if(s2[0] == current_salt[0] && s2[1] == current_salt[1])
+ return;
+ current_salt[0] = s2[0]; current_salt[1] = s2[1];
+
+ /*
+ * This is the only crypt change to DES:
+ * entries are swapped in the expansion table
+ * according to the bits set in the salt.
+ */
+ saltbits = 0;
+ for(i = 0; i < 2; i++) {
+ long c=ascii_to_bin(s2[i]);
+ if(c < 0 || c > 63)
+ c = 0;
+ for(j = 0; j < 6; j++) {
+ if((c >> j) & 0x1)
+ saltbits |= BITMASK(6 * i + j);
+ }
+ }
+
+ /*
+ * Permute the sb table values
+ * to reflect the changed e
+ * selection table
+ */
+ shuffle_sb(_ufc_sb0, current_saltbits ^ saltbits);
+ shuffle_sb(_ufc_sb1, current_saltbits ^ saltbits);
+ shuffle_sb(_ufc_sb2, current_saltbits ^ saltbits);
+ shuffle_sb(_ufc_sb3, current_saltbits ^ saltbits);
+
+ current_saltbits = saltbits;
+ }
+
+static void ufc_mk_keytab(key)
+ char *key;
+ { ufc_long v1, v2, *k1;
+ int i;
+#ifdef _UFC_32_
+ long32 v, *k2 = &_ufc_keytab[0][0];
+#endif
+#ifdef _UFC_64_
+ long64 v, *k2 = &_ufc_keytab[0];
+#endif
+
+ v1 = v2 = 0; k1 = &do_pc1[0][0][0];
+ for(i = 8; i--;) {
+ v1 |= k1[*key & 0x7f]; k1 += 128;
+ v2 |= k1[*key++ & 0x7f]; k1 += 128;
+ }
+
+ for(i = 0; i < 16; i++) {
+ k1 = &do_pc2[0][0];
+
+ v1 = (v1 << rots[i]) | (v1 >> (28 - rots[i]));
+ v = k1[(v1 >> 21) & 0x7f]; k1 += 128;
+ v |= k1[(v1 >> 14) & 0x7f]; k1 += 128;
+ v |= k1[(v1 >> 7) & 0x7f]; k1 += 128;
+ v |= k1[(v1 ) & 0x7f]; k1 += 128;
+
+#ifdef _UFC_32_
+ *k2++ = v;
+ v = 0;
+#endif
+#ifdef _UFC_64_
+ v <<= 32;
+#endif
+
+ v2 = (v2 << rots[i]) | (v2 >> (28 - rots[i]));
+ v |= k1[(v2 >> 21) & 0x7f]; k1 += 128;
+ v |= k1[(v2 >> 14) & 0x7f]; k1 += 128;
+ v |= k1[(v2 >> 7) & 0x7f]; k1 += 128;
+ v |= k1[(v2 ) & 0x7f];
+
+ *k2++ = v;
+ }
+
+ direction = 0;
+ }
+
+/*
+ * 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 v1, v2, x;
+ static ufc_long ary[2];
+
+ x = (l1 ^ l2) & current_saltbits; l1 ^= x; l2 ^= x;
+ x = (r1 ^ r2) & current_saltbits; r1 ^= x; r2 ^= x;
+
+ v1=v2=0; l1 >>= 3; l2 >>= 3; r1 >>= 3; r2 >>= 3;
+
+ v1 |= efp[15][ r2 & 0x3f][0]; v2 |= efp[15][ r2 & 0x3f][1];
+ v1 |= efp[14][(r2 >>= 6) & 0x3f][0]; v2 |= efp[14][ r2 & 0x3f][1];
+ v1 |= efp[13][(r2 >>= 10) & 0x3f][0]; v2 |= efp[13][ r2 & 0x3f][1];
+ v1 |= efp[12][(r2 >>= 6) & 0x3f][0]; v2 |= efp[12][ r2 & 0x3f][1];
+
+ v1 |= efp[11][ r1 & 0x3f][0]; v2 |= efp[11][ r1 & 0x3f][1];
+ v1 |= efp[10][(r1 >>= 6) & 0x3f][0]; v2 |= efp[10][ r1 & 0x3f][1];
+ v1 |= efp[ 9][(r1 >>= 10) & 0x3f][0]; v2 |= efp[ 9][ r1 & 0x3f][1];
+ v1 |= efp[ 8][(r1 >>= 6) & 0x3f][0]; v2 |= efp[ 8][ r1 & 0x3f][1];
+
+ v1 |= efp[ 7][ l2 & 0x3f][0]; v2 |= efp[ 7][ l2 & 0x3f][1];
+ v1 |= efp[ 6][(l2 >>= 6) & 0x3f][0]; v2 |= efp[ 6][ l2 & 0x3f][1];
+ v1 |= efp[ 5][(l2 >>= 10) & 0x3f][0]; v2 |= efp[ 5][ l2 & 0x3f][1];
+ v1 |= efp[ 4][(l2 >>= 6) & 0x3f][0]; v2 |= efp[ 4][ l2 & 0x3f][1];
+
+ v1 |= efp[ 3][ l1 & 0x3f][0]; v2 |= efp[ 3][ l1 & 0x3f][1];
+ v1 |= efp[ 2][(l1 >>= 6) & 0x3f][0]; v2 |= efp[ 2][ l1 & 0x3f][1];
+ v1 |= efp[ 1][(l1 >>= 10) & 0x3f][0]; v2 |= efp[ 1][ l1 & 0x3f][1];
+ v1 |= efp[ 0][(l1 >>= 6) & 0x3f][0]; v2 |= efp[ 0][ l1 & 0x3f][1];
+
+ ary[0] = v1; ary[1] = v2;
+ return ary;
+ }
+
+/*
+ * crypt only: convert from 64 bit to 11 bit ASCII
+ * prefixing with the salt
+ */
+
+static char *output_conversion(v1, v2, salt)
+ ufc_long v1, v2;
+ char *salt;
+ { static char outbuf[14];
+ int i, s;
+
+ outbuf[0] = salt[0];
+ outbuf[1] = salt[1] ? salt[1] : salt[0];
+
+ for(i = 0; i < 5; i++)
+ outbuf[i + 2] = bin_to_ascii((v1 >> (26 - 6 * i)) & 0x3f);
+
+ s = (v2 & 0xf) << 2;
+ v2 = (v2 >> 2) | ((v1 & 0x3) << 30);
+
+ for(i = 5; i < 10; i++)
+ outbuf[i + 2] = bin_to_ascii((v2 >> (56 - 6 * i)) & 0x3f);
+
+ outbuf[12] = bin_to_ascii(s);
+ outbuf[13] = 0;
+
+ return outbuf;
+ }
+
+ufc_long *_ufc_doit();
+
+/*
+ * UNIX crypt function
+ */
+
+char *ufc_crypt(char *key,char *salt)
+ { ufc_long *s;
+ char ktab[9];
+
+ /*
+ * Hack DES tables according to salt
+ */
+ setup_salt(salt);
+
+ /*
+ * Setup key schedule
+ */
+ clearmem(ktab, sizeof ktab);
+ StrnCpy(ktab, key, 8);
+ ufc_mk_keytab(ktab);
+
+ /*
+ * Go for the 25 DES encryptions
+ */
+ s = _ufc_doit((ufc_long)0, (ufc_long)0,
+ (ufc_long)0, (ufc_long)0, (ufc_long)25);
+
+ /*
+ * And convert back to 6 bit ASCII
+ */
+ return output_conversion(s[0], s[1], salt);
+ }
+
+
+#ifdef _UFC_32_
+
+/*
+ * 32 bit version
+ */
+
+extern long32 _ufc_keytab[16][2];
+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;
+ { int i;
+ long32 s, *k;
+
+ while(itr--) {
+ k = &_ufc_keytab[0][0];
+ for(i=8; i--; ) {
+ s = *k++ ^ r1;
+ l1 ^= SBA(_ufc_sb1, s & 0xffff); l2 ^= SBA(_ufc_sb1, (s & 0xffff)+4);
+ l1 ^= SBA(_ufc_sb0, s >>= 16); l2 ^= SBA(_ufc_sb0, (s) +4);
+ s = *k++ ^ r2;
+ l1 ^= SBA(_ufc_sb3, s & 0xffff); l2 ^= SBA(_ufc_sb3, (s & 0xffff)+4);
+ l1 ^= SBA(_ufc_sb2, s >>= 16); l2 ^= SBA(_ufc_sb2, (s) +4);
+
+ s = *k++ ^ l1;
+ r1 ^= SBA(_ufc_sb1, s & 0xffff); r2 ^= SBA(_ufc_sb1, (s & 0xffff)+4);
+ r1 ^= SBA(_ufc_sb0, s >>= 16); r2 ^= SBA(_ufc_sb0, (s) +4);
+ s = *k++ ^ l2;
+ r1 ^= SBA(_ufc_sb3, s & 0xffff); r2 ^= SBA(_ufc_sb3, (s & 0xffff)+4);
+ r1 ^= SBA(_ufc_sb2, s >>= 16); r2 ^= SBA(_ufc_sb2, (s) +4);
+ }
+ s=l1; l1=r1; r1=s; s=l2; l2=r2; r2=s;
+ }
+ return _ufc_dofinalperm(l1, l2, r1, r2);
+ }
+
+#endif
+
+#ifdef _UFC_64_
+
+/*
+ * 64 bit version
+ */
+
+extern long64 _ufc_keytab[16];
+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;
+ { int i;
+ long64 l, r, s, *k;
+
+ l = (((long64)l1) << 32) | ((long64)l2);
+ r = (((long64)r1) << 32) | ((long64)r2);
+
+ while(itr--) {
+ k = &_ufc_keytab[0];
+ for(i=8; i--; ) {
+ s = *k++ ^ r;
+ l ^= SBA(_ufc_sb3, (s >> 0) & 0xffff);
+ l ^= SBA(_ufc_sb2, (s >> 16) & 0xffff);
+ l ^= SBA(_ufc_sb1, (s >> 32) & 0xffff);
+ l ^= SBA(_ufc_sb0, (s >> 48) & 0xffff);
+
+ s = *k++ ^ l;
+ r ^= SBA(_ufc_sb3, (s >> 0) & 0xffff);
+ r ^= SBA(_ufc_sb2, (s >> 16) & 0xffff);
+ r ^= SBA(_ufc_sb1, (s >> 32) & 0xffff);
+ r ^= SBA(_ufc_sb0, (s >> 48) & 0xffff);
+ }
+ s=l; l=r; r=s;
+ }
+
+ l1 = l >> 32; l2 = l & 0xffffffff;
+ r1 = r >> 32; r2 = r & 0xffffffff;
+ return _ufc_dofinalperm(l1, l2, r1, r2);
+ }
+
+#endif
+
+
+#else
+int ufc_dummy_procedure(void)
+{return 0;}
+#endif
diff --git a/source3/lib/username.c b/source3/lib/username.c
new file mode 100644
index 0000000000..3d214fbbda
--- /dev/null
+++ b/source3/lib/username.c
@@ -0,0 +1,246 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Username 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.
+*/
+
+#include "includes.h"
+#include "loadparm.h"
+extern int DEBUGLEVEL;
+
+
+/****************************************************************************
+get a users home directory. tries as-is then lower case
+****************************************************************************/
+char *get_home_dir(char *user)
+{
+ static struct passwd *pass;
+
+ pass = Get_Pwnam(user,False);
+
+ if (!pass) return(NULL);
+ return(pass->pw_dir);
+}
+
+
+/*******************************************************************
+map a username from a dos name to a unix name by looking in the username
+map
+********************************************************************/
+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;
+ }
+
+ f = fopen(mapfile,"r");
+ if (!f) {
+ DEBUG(0,("can't open username map %s\n",mapfile));
+ return;
+ }
+
+ DEBUG(4,("Scanning username map %s\n",mapfile));
+
+ depth++;
+
+ for (; (s=fgets_slash(NULL,80,f)); free(s)) {
+ char *unixname = s;
+ char *dosname = strchr(unixname,'=');
+
+ if (!dosname) continue;
+ *dosname++ = 0;
+
+ while (isspace(*unixname)) unixname++;
+ if (!*unixname || strchr("#;",*unixname)) continue;
+
+ {
+ int l = strlen(unixname);
+ while (l && isspace(unixname[l-1])) {
+ unixname[l-1] = 0;
+ l--;
+ }
+ }
+
+ 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);
+ }
+ }
+
+ fclose(f);
+
+ depth--;
+}
+
+/****************************************************************************
+internals of Get_Pwnam wrapper
+****************************************************************************/
+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;
+ }
+#endif
+
+ }
+
+ 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!
+****************************************************************************/
+struct passwd *Get_Pwnam(char *user,BOOL allow_change)
+{
+ fstring user2;
+
+ struct passwd *ret;
+
+ if (!user || !(*user))
+ return(NULL);
+
+ StrnCpy(user2,user,sizeof(user2)-1);
+
+ if (!allow_change) {
+ user = &user2[0];
+ }
+
+ map_username(user);
+
+ ret = _Get_Pwnam(user);
+ if (ret) return(ret);
+
+ strlower(user);
+ ret = _Get_Pwnam(user);
+ if (ret) return(ret);
+
+ strupper(user);
+ ret = _Get_Pwnam(user);
+ if (ret) return(ret);
+
+ /* try with first letter capitalised */
+ if (strlen(user) > 1)
+ strlower(user+1);
+ ret = _Get_Pwnam(user);
+ if (ret) return(ret);
+
+ if (allow_change)
+ strcpy(user,user2);
+
+ return(NULL);
+}
+
+
+/****************************************************************************
+check if a user is in a user list
+****************************************************************************/
+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);
+ }
+#endif
+
+
+#if HAVE_GETGRNAM
+ if (*tok == '@')
+ {
+ struct group *gptr;
+ char **member;
+ struct passwd *pass = Get_Pwnam(user,False);
+
+ if (pass) {
+ gptr = getgrgid(pass->pw_gid);
+ if (gptr && strequal(gptr->gr_name,&tok[1]))
+ return(True);
+ }
+
+ gptr = (struct group *)getgrnam(&tok[1]);
+
+ if (gptr)
+ {
+ member = gptr->gr_mem;
+ while (member && *member)
+ {
+ if (strequal(*member,user))
+ return(True);
+ member++;
+ }
+ }
+ }
+#endif
+ }
+ return(False);
+}
+
+
diff --git a/source3/lib/util.c b/source3/lib/util.c
new file mode 100644
index 0000000000..7bd6298c4c
--- /dev/null
+++ b/source3/lib/util.c
@@ -0,0 +1,4510 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Samba utility functions
+ 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.
+*/
+
+#include "includes.h"
+#include "loadparm.h"
+
+pstring scope = "";
+
+int DEBUGLEVEL = 1;
+
+BOOL passive = False;
+
+int Protocol = PROTOCOL_COREPLUS;
+
+int serverzone=0;
+
+/* a default finfo structure to ensure all fields are sensible */
+file_info def_finfo = {-1,0,0,0,0,0,0,""};
+
+/* these are some file handles where debug info will be stored */
+FILE *dbf = NULL;
+
+/* the client file descriptor */
+int Client = -1;
+
+/* info on the client */
+struct from_host Client_info=
+{"UNKNOWN","0.0.0.0",NULL};
+
+/* the last IP received from */
+struct in_addr lastip;
+
+/* the last port received from */
+int lastport=0;
+
+/* my IP, the broadcast IP and the Netmask */
+struct in_addr myip;
+struct in_addr bcast_ip;
+struct in_addr Netmask;
+
+int trans_num = 0;
+
+/*
+ case handling on filenames
+*/
+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;
+BOOL case_preserve;
+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 int debug_count=0;
+
+ 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)
+{
+#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);
+}
+
+/****************************************************************************
+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(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)
+{
+ 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
+
+
+/****************************************************************************
+prompte a dptr (to make it recently used)
+****************************************************************************/
+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 *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;
+ }
+
+ 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\n",tok));
+ }
+}
+
+
+
+/****************************************************************************
+ close the socket communication
+****************************************************************************/
+void close_sockets(void )
+{
+ close(Client);
+ Client = 0;
+}
+
+/****************************************************************************
+ 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);
+}
+
+/****************************************************************************
+determine whether we are in the specified group
+****************************************************************************/
+BOOL in_group(gid_t group, int current_gid, int ngroups, int *groups)
+{
+ int i;
+
+ if (group == current_gid) return(True);
+
+ 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 AJT
+ /* I don't want to get lazy with these ... */
+ if (!dest || !src) {
+ DEBUG(0,("ERROR: NULL StrCpy() called!\n"));
+ ajt_panic();
+ }
+#endif
+
+ if (!dest) return(NULL);
+ if (!src) {
+ *dest = 0;
+ return(dest);
+ }
+ while ((*d++ = *src++)) ;
+ return(dest);
+}
+
+/****************************************************************************
+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);
+}
+
+
+/*******************************************************************
+copy an IP address from one buffer to another
+********************************************************************/
+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)
+{
+ 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;
+
+ if (sys_stat(fname,sbuf) != 0)
+ return(False);
+
+ return(S_ISREG(sbuf->st_mode));
+}
+
+/*******************************************************************
+check a files mod time
+********************************************************************/
+time_t file_modtime(char *fname)
+{
+ struct stat st;
+
+ if (sys_stat(fname,&st) != 0)
+ return(0);
+
+ return(st.st_mtime);
+}
+
+/*******************************************************************
+ check if a directory exists
+********************************************************************/
+BOOL directory_exist(char *dname,struct stat *st)
+{
+ struct stat st2;
+ if (!st) st = &st2;
+
+ if (sys_stat(dname,st) != 0)
+ return(False);
+
+ return(S_ISDIR(st->st_mode));
+}
+
+/*******************************************************************
+returns the size in bytes of the named file
+********************************************************************/
+uint32 file_size(char *file_name)
+{
+ struct stat buf;
+ buf.st_size = 0;
+ sys_stat(file_name,&buf);
+ 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)
+{
+ static char attrstr[10];
+
+ 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");
+
+ 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
+********************************************************************/
+void strupper(char *s)
+{
+ 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++;
+ }
+#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);
+}
+
+/*******************************************************************
+check if a string is in "normal" case
+********************************************************************/
+BOOL strisnormal(char *s)
+{
+ if (case_default == CASE_UPPER)
+ return(!strhaslower(s));
+
+ return(!strhasupper(s));
+}
+
+
+/****************************************************************************
+ 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++;
+ }
+#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;
+}
+
+/*******************************************************************
+ set the length and marker of an smb packet
+********************************************************************/
+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';
+}
+
+/*******************************************************************
+ setup the word count and byte count for a smb message
+********************************************************************/
+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);
+}
+
+/*******************************************************************
+return the number of smb words
+********************************************************************/
+int smb_numwords(char *buf)
+{
+ return (CVAL(buf,smb_wct));
+}
+
+/*******************************************************************
+return the size of the smb_buf region of a message
+********************************************************************/
+int smb_buflen(char *buf)
+{
+ return(SVAL(buf,smb_vwv0 + smb_numwords(buf)*2));
+}
+
+/*******************************************************************
+ 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)
+{
+ char *p=NULL;
+
+ DEBUG(3,("dos_clean_name [%s]\n",s));
+
+ /* remove any double slashes */
+ string_sub(s, "\\\\", "\\");
+
+ while ((p = strstr(s,"\\..\\")) != NULL)
+ {
+ pstring s1;
+
+ *p = 0;
+ strcpy(s1,p+3);
+
+ if ((p=strrchr(s,'\\')) != NULL)
+ *p = 0;
+ else
+ *s = 0;
+ strcat(s,s1);
+ }
+
+ trim_string(s,NULL,"\\..");
+
+ string_sub(s, "\\.\\", "\\");
+}
+
+/*******************************************************************
+reduce a file name, removing .. elements.
+********************************************************************/
+void unix_clean_name(char *s)
+{
+ char *p=NULL;
+
+ DEBUG(3,("unix_clean_name [%s]\n",s));
+
+ /* remove any double slashes */
+ string_sub(s, "//","/");
+
+ while ((p = strstr(s,"/../")) != NULL)
+ {
+ pstring s1;
+
+ *p = 0;
+ strcpy(s1,p+3);
+
+ if ((p=strrchr(s,'/')) != NULL)
+ *p = 0;
+ else
+ *s = 0;
+ strcat(s,s1);
+ }
+
+ trim_string(s,NULL,"/..");
+}
+
+
+/*******************************************************************
+a wrapper for the normal chdir() function
+********************************************************************/
+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;
+ }
+ }
+
+ /* 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;
+ }
+ }
+ }
+ }
+
+
+ /* 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);
+ }
+
+ 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);
+}
+
+
+
+/*******************************************************************
+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)
+{
+ char *p;
+ pstring mask2;
+
+ strcpy(mask2,mask);
+
+ if ((mode & aDIR) != 0)
+ size = 0;
+
+ memset(buf+1,' ',11);
+ if ((p = strchr(mask2,'.')) != NULL)
+ {
+ *p = 0;
+ memcpy(buf+1,mask2,MIN(strlen(mask2),8));
+ memcpy(buf+9,p+1,MIN(strlen(p+1),3));
+ *p = '.';
+ }
+ else
+ memcpy(buf+1,mask2,MIN(strlen(mask2),11));
+
+ bzero(buf+21,DIR_STRUCT_SIZE-21);
+ CVAL(buf,21) = mode;
+ put_dos_date(buf,22,date);
+ SSVAL(buf,26,size & 0xFFFF);
+ SSVAL(buf,28,size >> 16);
+ StrnCpy(buf+30,fname,12);
+ if (!case_sensitive)
+ strupper(buf+30);
+ DEBUG(8,("put name [%s] into dir struct\n",buf+30));
+}
+
+
+/*******************************************************************
+close the low 3 fd's and open dev/null in their place
+********************************************************************/
+void close_low_fds(void)
+{
+ int fd;
+ int i;
+ close(0); close(1); close(2);
+ /* 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);
+ if (fd < 0) {
+ DEBUG(0,("Can't open /dev/null\n"));
+ return;
+ }
+ if (fd != i) {
+ DEBUG(0,("Didn't get file descriptor %d\n",i));
+ return;
+ }
+ }
+}
+
+
+/****************************************************************************
+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
+if SYSV use O_NDELAY
+if BSD use FNDELAY
+****************************************************************************/
+int set_blocking(int fd, BOOL set)
+{
+int val;
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+
+ if((val = fcntl(fd, F_GETFL, 0))==-1)
+ return -1;
+ if(set) /* Turn blocking on - ie. clear nonblock flag */
+ val &= ~FLAG_TO_SET;
+ else
+ val |= FLAG_TO_SET;
+ return fcntl( fd, F_SETFL, 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
+****************************************************************************/
+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;
+
+ /* just checking .... */
+ if (maxcnt <= 0) return(0);
+
+ if(time_out == -2)
+ time_out = DEFAULT_PIPE_TIMEOUT;
+
+ /* Blocking read */
+ if(time_out < 0) {
+ if (mincnt == 0) mincnt = maxcnt;
+
+ 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;
+ }
+
+ /* 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);
+ }
+
+ 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;
+ }
+
+ /* Return the number we got */
+ return(nread);
+}
+
+/****************************************************************************
+read data from the client. Maxtime is in milliseconds
+****************************************************************************/
+int read_max_udp(int fd,char *buffer,int bufsize,int maxtime)
+{
+ 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);
+}
+
+/*******************************************************************
+find the difference in milliseconds between two struct timeval
+values
+********************************************************************/
+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)
+{
+ unsigned char buf[4];
+
+ buf[0] = 0x85;
+ buf[1] = buf[2] = buf[3] = 0;
+
+ return(write_data(client,(char *)buf,4) == 4);
+}
+
+
+
+/****************************************************************************
+ read data from the client, reading exactly N bytes.
+****************************************************************************/
+int read_data(int fd,char *buffer,int N)
+{
+ int ret;
+ int total=0;
+
+ while (total < N)
+ {
+ ret = read(fd,buffer + total,N - total);
+
+ /* this is for portability */
+ if (ret < 0)
+ errno = EBADF;
+
+ if (ret <= 0)
+ return total;
+ total += ret;
+ }
+ return total;
+}
+
+
+/****************************************************************************
+ write data to a fd
+****************************************************************************/
+int write_data(int fd,char *buffer,int N)
+{
+ int total=0;
+ int ret;
+
+ while (total < N)
+ {
+ ret = write(fd,buffer + total,N - total);
+
+ if (ret <= 0)
+ return total;
+
+ total += ret;
+ }
+ return total;
+}
+
+
+/* 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
+****************************************************************************/
+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;
+
+ /* prepare the next prediction */
+ rp_predict_fd = fd;
+ rp_predict_offset = offset + num;
+ rp_predict_length = num;
+ }
+
+ if (ret < 0) ret = 0;
+
+ return(ret);
+}
+
+/****************************************************************************
+pre-read some data
+****************************************************************************/
+void do_read_prediction()
+{
+ if (predict_skip) return;
+
+ if (rp_predict_fd == -1)
+ return;
+
+ rp_fd = rp_predict_fd;
+ rp_offset = rp_predict_offset;
+ rp_length = 0;
+
+ rp_predict_fd = -1;
+
+ 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;
+
+ 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;
+ }
+ }
+
+ if (lseek(rp_fd,rp_offset,SEEK_SET) != rp_offset) {
+ rp_fd = -1;
+ rp_predict_fd = -1;
+ return;
+ }
+
+ rp_length = read(rp_fd,rp_buffer,rp_predict_length);
+ rp_time = time(NULL);
+ if (rp_length < 0)
+ rp_length = 0;
+}
+
+/****************************************************************************
+invalidate read-prediction on a fd
+****************************************************************************/
+void invalidate_read_prediction(int fd)
+{
+ if (rp_fd == fd)
+ rp_fd = -1;
+ if (rp_predict_fd == fd)
+ rp_predict_fd = -1;
+}
+
+
+/****************************************************************************
+transfer some data between two fd's
+****************************************************************************/
+int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align)
+{
+ static char *buf=NULL;
+ char *buf1,*abuf;
+ static int size = 0;
+ int total = 0;
+
+ DEBUG(4,("transfer_file %d (head=%d) called\n",n,headlen));
+
+ if ((size < ReadSize) && buf) {
+ free(buf);
+ buf = NULL;
+ }
+
+ size = MAX(ReadSize,1024);
+
+ 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);
+ }
+
+ abuf = buf + (align%8);
+
+ if (header)
+ n += headlen;
+
+ 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 (header && headlen > 0)
+ {
+ ret = MIN(headlen,size);
+ memcpy(buf1,header,ret);
+ headlen -= ret;
+ header += ret;
+ if (headlen <= 0) header = NULL;
+ }
+
+ if (s > ret)
+ ret += read(infd,buf1+ret,s-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);
+}
+
+
+/****************************************************************************
+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)
+{
+ char *buffer;
+ char buf[4];
+ int len=0, msg_type;
+ BOOL ok=False;
+
+ if (inbuf)
+ buffer = inbuf;
+ else
+ buffer = buf;
+
+ while (!ok)
+ {
+ if (timeout > 0)
+ ok = (read_with_timeout(fd,buffer,4,4,timeout,False) == 4);
+ else
+ ok = (read_data(fd,buffer,4) == 4);
+
+ 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);
+ }
+ }
+
+ len = smb_len(buffer);
+ msg_type = CVAL(buffer,0);
+
+ if (msg_type == 0x85)
+ {
+ DEBUG(5,( "Got keepalive packet\n"));
+ ok = False;
+ }
+ }
+
+ DEBUG(10,("got smb length of %d\n",len));
+
+ return(len);
+}
+
+
+
+/****************************************************************************
+ 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)
+{
+ 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)
+ {
+ DEBUG(0,("Invalid packet length! (%d bytes)\n",len));
+ if (len > BUFFER_SIZE + (SAFETY_MARGIN/2))
+ exit(1);
+ }
+
+ ok = (read_data(fd,buffer+4,len) == len);
+
+ if (!ok)
+ {
+ close_sockets();
+ exit(1);
+ }
+
+ return(True);
+}
+
+
+/****************************************************************************
+ send an smb to a fd
+****************************************************************************/
+BOOL send_smb(int fd,char *buffer)
+{
+ int len;
+ int ret,nwritten=0;
+ 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. Exiting\n",len,ret));
+ close_sockets();
+ exit(1);
+ }
+ nwritten += ret;
+ }
+
+
+ return True;
+}
+
+
+/****************************************************************************
+find a pointer to a netbios name
+****************************************************************************/
+char *name_ptr(char *buf,int ofs)
+{
+ unsigned char c = *(unsigned char *)(buf+ofs);
+
+ 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);
+}
+
+/****************************************************************************
+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
+****************************************************************************/
+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 ret;
+ int out_fd;
+ struct sockaddr_in sock_out;
+
+ 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);
+
+ if (!ret)
+ DEBUG(0,("Packet send to %s(%d) failed ERRNO=%d\n",
+ inet_ntoa(ip),port,errno));
+
+ close(out_fd);
+ return(ret);
+}
+
+/*******************************************************************
+sleep for a specified number of milliseconds
+********************************************************************/
+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);
+
+ GetTimeOfDay(&t2);
+ tdiff = TvalDiff(&t1,&t2);
+ }
+}
+
+/****************************************************************************
+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))
+ {
+ 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
+****************************************************************************/
+BOOL string_init(char **dest,char *src)
+{
+ int l;
+ if (!src)
+ src = "";
+
+ l = strlen(src);
+
+ 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);
+}
+
+/****************************************************************************
+free a string value
+****************************************************************************/
+void string_free(char **s)
+{
+ if (!s || !(*s)) return;
+ if (*s == null_string)
+ *s = NULL;
+ if (*s) free(*s);
+ *s = NULL;
+}
+
+/****************************************************************************
+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!
+
+This routine looks for pattern in s and replaces it with
+insert. It may do multiple replacements.
+
+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;
+
+ if (!insert || !pattern || !s) return(False);
+
+ ls = strlen(s);
+ lp = strlen(pattern);
+ li = strlen(insert);
+
+ if (!*pattern) return(False);
+
+ 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);
+}
+
+
+
+/*********************************************************
+* Recursive routine that is called by mask_match.
+* Does the actual matching.
+*********************************************************/
+BOOL do_match(char *str, char *regexp, int case_sig)
+{
+ 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 && (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(!*p && !*str)
+ return True;
+
+ if (!*p && str[0] == '.' && str[1] == 0)
+ return(True);
+
+ if (!*str && *p == '?')
+ {
+ while (*p == '?') p++;
+ return(!*p);
+ }
+
+ if(!*str && (*p == '*' && p[1] == '\0'))
+ return True;
+ 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)
+{
+ 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);
+
+ if (!strchr(p2,'.')) {
+ strcat(p2,".");
+ }
+
+/*
+ if (!strchr(p1,'.')) {
+ strcat(p1,".");
+ }
+*/
+
+#if 0
+ if (strchr(p1,'.'))
+ {
+ 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);
+
+ DEBUG(5,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
+
+ 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;
+ }
+
+ if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) {
+ *p = 0;
+ strcpy(sbase,p2);
+ strcpy(sext,p+1);
+ } else {
+ strcpy(sbase,p2);
+ strcpy(sext,"");
+ }
+ }
+
+ matched = do_match(sbase,ebase,case_sig) &&
+ (trans2 || do_match(sext,eext,case_sig));
+
+ DEBUG(5,("mask_match returning %d\n", matched));
+
+ return matched;
+}
+
+
+
+/****************************************************************************
+become a daemon, discarding the controlling terminal
+****************************************************************************/
+void become_daemon(void)
+{
+#ifndef NO_FORK_DEBUG
+ if (fork())
+ exit(0);
+
+ /* 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
+}
+
+/****************************************************************************
+calculate the default netmask for an address
+****************************************************************************/
+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;
+
+#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
+
+ /* get a default netmask and broadcast */
+ default_netmask(if_nmask, if_ipaddr);
+
+#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));
+
+ ifc.ifc_len = sizeof(struct ifreq) * n_interfaces;
+ ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len);
+
+ if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
+ DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno)));
+ else {
+ ifr = ifc.ifc_req;
+
+ 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;
+ }
+ }
+ }
+#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)));
+ }
+
+ /* Close up shop */
+ (void) close(sock);
+
+#endif
+
+ /* sanity check on the netmask */
+ {
+ 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);
+ }
+ }
+
+ /* 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 */
+
+
+/****************************************************************************
+put up a yes/no prompt
+****************************************************************************/
+BOOL yesno(char *p)
+{
+ pstring ans;
+ printf("%s",p);
+
+ if (!fgets(ans,sizeof(ans)-1,stdin))
+ return(False);
+
+ if (*ans == 'y' || *ans == 'Y')
+ return(True);
+
+ return(False);
+}
+
+/****************************************************************************
+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)
+{
+ 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;
+
+ while (len < maxlen-1)
+ {
+ c = 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)
+ 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)
+ {
+ maxlen *= 2;
+ s = (char *)Realloc(s,maxlen);
+ if (!s) return(NULL);
+ }
+ }
+ 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
+
+ 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)
+{
+ unsigned char *p = (unsigned char *)buf;
+ int ret = 0;
+ while (len--)
+ ret += *p++;
+ return(ret);
+}
+
+
+
+#ifdef HPUX
+/****************************************************************************
+this is a version of setbuffer() for those machines that only have setvbuf
+****************************************************************************/
+void setbuffer(FILE *f,char *buf,int bufsize)
+{
+ setvbuf(f,buf,_IOFBF,bufsize);
+}
+#endif
+
+
+/****************************************************************************
+parse out a directory name from a path name. Assumes dos style filenames.
+****************************************************************************/
+char *dirname_dos(char *path,char *buf)
+{
+ char *p = strrchr(path,'\\');
+
+ if (!p)
+ strcpy(buf,path);
+ else
+ {
+ *p = 0;
+ strcpy(buf,path);
+ *p = '\\';
+ }
+
+ return(buf);
+}
+
+
+/****************************************************************************
+parse out a filename from a path name. Assumes dos style filenames.
+****************************************************************************/
+static char *filename_dos(char *path,char *buf)
+{
+ char *p = strrchr(path,'\\');
+
+ if (!p)
+ strcpy(buf,path);
+ else
+ strcpy(buf,p+1);
+
+ return(buf);
+}
+
+
+
+/****************************************************************************
+expand a pointer to be a particular size
+****************************************************************************/
+void *Realloc(void *p,int size)
+{
+ 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);
+}
+
+/****************************************************************************
+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;
+
+ if (sys_utime(fname,&times)) {
+ DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
+ }
+
+ return(True);
+}
+
+
+#ifdef NOSTRDUP
+/****************************************************************************
+duplicate a string
+****************************************************************************/
+char *strdup(char *s)
+{
+ char *ret = NULL;
+ if (!s) return(NULL);
+ ret = (char *)malloc(strlen(s)+1);
+ if (!ret) return(NULL);
+ strcpy(ret,s);
+ return(ret);
+}
+#endif
+
+
+/****************************************************************************
+ Signal handler for SIGPIPE (write on a disconnected socket)
+****************************************************************************/
+void Abort(void )
+{
+ DEBUG(0,("Probably got SIGPIPE\nExiting\n"));
+ exit(2);
+}
+
+
+#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)
+{
+ 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));
+}
+
+
+/*******************************************************************
+ check for a sane unix date
+********************************************************************/
+BOOL sane_unix_date(time_t unixdate)
+{
+ 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);
+}
+
+
+
+#ifdef NO_FTRUNCATE
+ /*******************************************************************
+ftruncate for operating systems that don't have it
+********************************************************************/
+int ftruncate(int f,long 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
+
+
+
+/****************************************************************************
+get my own name and IP
+****************************************************************************/
+BOOL get_myname(char *myname,struct in_addr *ip)
+{
+ struct hostent *hp;
+ pstring hostname;
+
+ *hostname = 0;
+
+ /* get my host name */
+ if (gethostname(hostname, MAXHOSTNAMELEN) == -1)
+ {
+ DEBUG(0,("gethostname failed\n"));
+ return False;
+ }
+
+ /* get host info */
+ if ((hp = Get_Hostbyname(hostname)) == 0)
+ {
+ DEBUG(0,( "Get_Hostbyname: Unknown host %s.\n",hostname));
+ return False;
+ }
+
+ if (myname)
+ {
+ /* split off any parts after an initial . */
+ char *p = strchr(hostname,'.');
+ if (p) *p = 0;
+
+ strcpy(myname,hostname);
+ }
+
+ if (ip)
+ putip((char *)ip,(char *)hp->h_addr);
+
+ return(True);
+}
+
+
+/****************************************************************************
+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);
+}
+
+
+/****************************************************************************
+open a socket of the specified type, port and address for incoming data
+****************************************************************************/
+int open_socket_in(int type, int port, int dlevel)
+{
+ 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; }
+
+ /* 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));
+ }
+
+ /* 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);
+
+ if (dlevel > 0 && port < 1000)
+ port = 7999;
+
+ if (port >= 1000 && port < 9000)
+ return(open_socket_in(type,port+1,dlevel));
+ }
+
+ return(-1);
+ }
+ DEBUG(3,("bind succeeded on port %d\n",port));
+
+ return res;
+}
+
+
+/****************************************************************************
+ create an outgoing socket
+ **************************************************************************/
+int open_socket_out(int type, struct in_addr *addr, int port )
+{
+ 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;
+}
+
+
+/****************************************************************************
+interpret a protocol description string, with a default
+****************************************************************************/
+int interpret_protocol(char *str,int def)
+{
+ 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);
+}
+
+/****************************************************************************
+interpret a security level
+****************************************************************************/
+int interpret_security(char *str,int def)
+{
+ 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);
+}
+
+
+/****************************************************************************
+interpret an internet address or name into an IP address in 4 byte form
+****************************************************************************/
+unsigned long interpret_addr(char *str)
+{
+ 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);
+}
+
+/*******************************************************************
+ a convenient addition to interpret_addr()
+ ******************************************************************/
+struct in_addr *interpret_addr2(char *str)
+{
+ static struct in_addr ret;
+ unsigned long a = interpret_addr(str);
+ putip((char *)&ret,(char *)&a);
+ return(&ret);
+}
+
+/*******************************************************************
+ check if an IP is the 0.0.0.0
+ ******************************************************************/
+BOOL zero_ip(struct in_addr ip)
+{
+ unsigned long a;
+ putip((char *)&a,(char *)&ip);
+ return(a == 0);
+}
+
+#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)
+{
+ 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);
+}
+
+
+/****************************************************************************
+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)
+{
+ 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);
+
+ d += TIME_FIXUP_CONSTANT;
+
+ d *= 1.0e7;
+
+ 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);
+}
+
+/*******************************************************************
+sub strings with useful parameters
+********************************************************************/
+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);
+ }
+
+ if (!strchr(s,'%')) return;
+
+ {
+ struct passwd *pass = Get_Pwnam(sesssetup_user,False);
+ if (pass) {
+ string_sub(s,"%G",gidtoname(pass->pw_gid));
+ }
+ }
+}
+
+
+/*******************************************************************
+write a string in unicoode format
+********************************************************************/
+int PutUniCode(char *dst,char *src)
+{
+ int ret = 0;
+ while (*src) {
+ dst[ret++] = src[0];
+ dst[ret++] = 0;
+ src++;
+ }
+ dst[ret++]=0;
+ dst[ret++]=0;
+ return(ret);
+}
+
+
+pstring smbrun_path = SMBRUN;
+
+/****************************************************************************
+run a command via system() using smbrun
+****************************************************************************/
+int smbrun(char *cmd,char *outfile)
+{
+ int ret;
+ pstring syscmd;
+
+ 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");
+
+ DEBUG(5,("smbrun - running %s ",syscmd));
+ ret = system(syscmd);
+ DEBUG(5,("gave %d\n",ret));
+ return(ret);
+}
+
+
+/****************************************************************************
+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);
+ }
+
+ if (!isalnum(*name2))
+ {
+ free(name2);
+ return(NULL);
+ }
+
+ ret = gethostbyname(name2);
+ if (ret != NULL)
+ {
+ free(name2);
+ return(ret);
+ }
+
+ /* try with all lowercase */
+ strlower(name2);
+ ret = gethostbyname(name2);
+ if (ret != NULL)
+ {
+ free(name2);
+ return(ret);
+ }
+
+ /* try with all uppercase */
+ strupper(name2);
+ ret = gethostbyname(name2);
+ if (ret != NULL)
+ {
+ free(name2);
+ return(ret);
+ }
+
+ /* nothing works :-( */
+ free(name2);
+ return(NULL);
+}
+
+
+/****************************************************************************
+check if a process exists. Does this work on all unixes?
+****************************************************************************/
+BOOL process_exists(int pid)
+{
+#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);
+
+ /* otherwise use kill */
+ return(pid == getpid() || kill(pid,0) == 0);
+#endif
+}
+
+
+/*******************************************************************
+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);
+}
+
+/*******************************************************************
+turn a gid into a group name
+********************************************************************/
+char *gidtoname(int gid)
+{
+ static char name[40];
+ struct group *grp = getgrgid(gid);
+ if (grp) return(grp->gr_name);
+ sprintf(name,"%d",gid);
+ return(name);
+}
+
+/*******************************************************************
+block sigs
+********************************************************************/
+void BlockSignals(BOOL block)
+{
+#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
+}
+
+#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
+
+#ifdef USE_DIRECT
+#define DIRECT direct
+#else
+#define DIRECT dirent
+#endif
+
+/*******************************************************************
+a readdir wrapper which just returns the file name
+also return the inode number if requested
+********************************************************************/
+char *readdirname(void *p)
+{
+ 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
+
+/****************************************************************************
+ 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;
+ }
+ 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);
+}
+
+/****************************************************************************
+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);
+}
+
+/****************************************************************************
+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)
+{
+ int len = strlen(p);
+
+ while ( *s != '\0' ) {
+ if ( strncmp(s, p, len) == 0 )
+ return s;
+ s++;
+ }
+
+ 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;
+{
+ if (link (zfrom, zto) < 0)
+ {
+ if (errno != EEXIST)
+ return -1;
+ if (unlink (zto) < 0
+ || link (zfrom, zto) < 0)
+ return -1;
+ }
+ return unlink (zfrom);
+}
+#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;
+{
+ 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
+
+
+#if WRAP_MEMCPY
+#undef memcpy
+/*******************************************************************
+a wrapper around memcpy for diagnostic purposes
+********************************************************************/
+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
+
+
+