diff options
Diffstat (limited to 'source/lib')
-rw-r--r-- | source/lib/.cvsignore | 0 | ||||
-rw-r--r-- | source/lib/access.c | 486 | ||||
-rw-r--r-- | source/lib/bitmap.c | 130 | ||||
-rw-r--r-- | source/lib/charcnv.c | 190 | ||||
-rw-r--r-- | source/lib/charset.c | 361 | ||||
-rw-r--r-- | source/lib/debug.c | 588 | ||||
-rw-r--r-- | source/lib/fault.c | 52 | ||||
-rw-r--r-- | source/lib/genrand.c | 226 | ||||
-rw-r--r-- | source/lib/getsmbpass.c | 32 | ||||
-rw-r--r-- | source/lib/interface.c | 382 | ||||
-rw-r--r-- | source/lib/kanji.c | 514 | ||||
-rw-r--r-- | source/lib/md4.c | 447 | ||||
-rw-r--r-- | source/lib/membuffer.c | 358 | ||||
-rw-r--r-- | source/lib/netatalk.c | 159 | ||||
-rw-r--r-- | source/lib/netmask.c | 353 | ||||
-rw-r--r-- | source/lib/pidfile.c | 95 | ||||
-rw-r--r-- | source/lib/replace.c | 295 | ||||
-rw-r--r-- | source/lib/signal.c | 102 | ||||
-rw-r--r-- | source/lib/slprintf.c | 111 | ||||
-rw-r--r-- | source/lib/smbrun.c | 178 | ||||
-rw-r--r-- | source/lib/system.c | 534 | ||||
-rw-r--r-- | source/lib/time.c | 546 | ||||
-rw-r--r-- | source/lib/ufc.c | 17 | ||||
-rw-r--r-- | source/lib/username.c | 335 | ||||
-rw-r--r-- | source/lib/util.c | 5002 | ||||
-rw-r--r-- | source/lib/util_hnd.c | 289 |
26 files changed, 8460 insertions, 3322 deletions
diff --git a/source/lib/.cvsignore b/source/lib/.cvsignore new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/source/lib/.cvsignore diff --git a/source/lib/access.c b/source/lib/access.c index 14a84b2fb44..31f9db4e554 100644 --- a/source/lib/access.c +++ b/source/lib/access.c @@ -1,139 +1,142 @@ /* -This module is an adaption of code from the tcpd-1.4 package written -by Wietse Venema, Eindhoven University of Technology, The Netherlands. + This module is an adaption of code from the tcpd-1.4 package written + by Wietse Venema, Eindhoven University of Technology, The Netherlands. -The code is used here with permission. + The code is used here with permission. -The code has been considerably changed from the original. Bug reports -should be sent to Andrew.Tridgell@anu.edu.au + The code has been considerably changed from the original. Bug reports + should be sent to samba-bugs@samba.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"; -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) +/* masked_match - match address against netnumber/netmask */ +static int masked_match(char *tok, char *slash, char *s) { - 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))); + uint32 net; + uint32 mask; + uint32 addr; + + if ((addr = interpret_addr(s)) == INADDR_NONE) + return (False); + *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\n", tok)); + return (False); } - } + return ((addr & mask) == net); +} - if (denyl) free(denyl); - if (allowl) free(allowl); - return(ret); +/* string_match - match string against token */ +static int string_match(char *tok,char *s) +{ + int tok_len; + int str_len; + char *cut; + + /* Return True if a token has the magic value "ALL". Return + * FAIL if the token is "FAIL". If the token starts with a "." + * (domain name), return True if it matches the last fields of + * the string. If the token has the magic value "LOCAL", + * return True if the string does not contain a "." + * character. If the token ends on a "." (network number), + * return True if it matches the first fields of the + * string. If the token begins with a "@" (netgroup name), + * return True if the string is a (host) member of the + * netgroup. Return True if the token fully matches the + * string. If the token is a netnumber/netmask pair, return + * True if the address is a member of the specified subnet. */ + + if (tok[0] == '.') { /* domain: match last fields */ + if ((str_len = strlen(s)) > (tok_len = strlen(tok)) + && strcasecmp(tok, s + str_len - tok_len) == 0) + return (True); + } else if (tok[0] == '@') { /* netgroup: look it up */ +#ifdef HAVE_NETGROUP + static char *mydomain = NULL; + char *hostname = NULL; + BOOL netgroup_ok = False; + + if (!mydomain) yp_get_default_domain(&mydomain); + + if (!mydomain) { + DEBUG(0,("Unable to get default yp domain.\n")); + return False; + } + if (!(hostname = strdup(s))) { + DEBUG(1,("out of memory for strdup!\n")); + return False; + } + + netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain); + + DEBUG(5,("looking for %s of domain %s in netgroup %s gave %s\n", + hostname, + mydomain, + tok+1, + BOOLSTR(netgroup_ok))); + + free(hostname); + + if (netgroup_ok) return(True); +#else + DEBUG(0,("access: netgroup support is not configured\n")); + return (False); +#endif + } else if (strcasecmp(tok, "ALL") == 0) { /* all: match any */ + return (True); + } else if (strcasecmp(tok, "FAIL") == 0) { /* fail: match any */ + return (FAIL); + } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */ + if (strchr(s, '.') == 0 && strcasecmp(s, "unknown") != 0) + return (True); + } else if (!strcasecmp(tok, s)) { /* match host name or address */ + return (True); + } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { /* network */ + if (strncmp(tok, s, tok_len) == 0) + return (True); + } else if ((cut = strchr(tok, '/')) != 0) { /* netnumber/netmask */ + if (isdigit((int)s[0]) && masked_match(tok, cut, s)) + return (True); + } + return (False); } -/* return true if access should be allowed */ -BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client) +/* client_match - match host name and address against token */ +static int client_match(char *tok,char *item) { - /* 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); + char **client = (char **)item; + int match; - return (True); + /* + * Try to match the address first. If that fails, try to match the host + * name if available. + */ + + if ((match = string_match(tok, client[1])) == 0) + if (client[0][0] != 0) + match = string_match(tok, client[0]); + return (match); } /* list_match - match an item against a list of tokens with exceptions */ /* (All modifications are marked with the initials "jkf") */ -static int list_match(char *list,char *item, int (*match_fn)()) +static int list_match(char *list,char *item, int (*match_fn)(char *, char *)) { char *tok; char *listcopy; /* jkf */ - int match = NO; + int match = False; /* * jkf@soton.ac.uk -- 31 August 1994 -- Stop list_match() @@ -153,237 +156,88 @@ static int list_match(char *list,char *item, int (*match_fn)()) 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 */ + if ((match = (*match_fn) (tok, item))) /* True or FAIL */ break; } - /* Process exceptions to YES or FAIL matches. */ + /* Process exceptions to True or FAIL matches. */ - if (match != NO) { + if (match != False) { while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT")) /* VOID */ ; - if (tok == 0 || list_match((char *) 0, item, match_fn) == NO) { + if (tok == 0 || list_match((char *) 0, item, match_fn) == False) { if (listcopy != 0) free(listcopy); /* jkf */ return (match); } } if (listcopy != 0) free(listcopy); /* jkf */ - return (NO); + return (False); } -/* 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) +/* return true if access should be allowed */ +BOOL allow_access(char *deny_list,char *allow_list, + char *cname,char *caddr) { - int tok_len; - int str_len; - char *cut; + char *client[2]; - /* - * 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. - */ + client[0] = cname; + client[1] = caddr; - 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); + /* 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); } - } -#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); + /* 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); } - -/* fromhost - find out what is at the other end of a socket */ -BOOL fromhost(int sock,struct from_host *f) +/* return true if access should be allowed to a service for a socket */ +BOOL check_access(int sock, char *allow_list, char *deny_list) { - static struct sockaddr sa; - struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); - struct hostent *hp; - int length = sizeof(sa); - static char addr_buf[FROM_ADDRLEN]; - static char name_buf[MAXHOSTNAMELEN]; - BOOL takeAddressAsHostname = False; - - if (getpeername(sock, &sa, &length) < 0) - { - DEBUG(0,("getpeername failed\n")); - return(False); - } - - f->sin = sockin; - f->addr = strcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr)); - - /* Look up the remote host name. */ - if ((hp = gethostbyaddr((char *) &sockin->sin_addr, - sizeof(sockin->sin_addr), - AF_INET)) == 0) { - DEBUG(1,("Gethostbyaddr failed for %s\n",addr_buf)); -#ifdef ALLOW_PURE_ADDRESSES - takeAddressAsHostname = True; -#else - return(False); -#endif - } - - /* Save the host name. A later gethostbyxxx() call may clobber it. */ - f->name = StrnCpy(name_buf, - takeAddressAsHostname? f->addr : hp->h_name, - sizeof(name_buf) - 1); - - /* - * Verify that the host name does not belong to someone else. If host - * name verification fails, pretend that the host name lookup failed. - */ - if (!takeAddressAsHostname && !matchname(f->name, sockin->sin_addr)) - { - DEBUG(0,("Matchname failed\n")); - return(False); - } + BOOL ret = False; + + if (deny_list) deny_list = strdup(deny_list); + if (allow_list) allow_list = strdup(allow_list); - return(True); -} + if ((!deny_list || *deny_list==0) && (!allow_list || *allow_list==0)) { + ret = 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); - } + if (!ret) { + if (allow_access(deny_list,allow_list, + client_name(sock),client_addr(sock))) { + DEBUG(2,("Allowed connection from %s (%s)\n", + client_name(sock),client_addr(sock))); + ret = True; + } else { + DEBUG(0,("Denied connection from %s (%s)\n", + client_name(sock),client_addr(sock))); + } + } - /* - * 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); + if (deny_list) free(deny_list); + if (allow_list) free(allow_list); + return(ret); } - - diff --git a/source/lib/bitmap.c b/source/lib/bitmap.c new file mode 100644 index 00000000000..9ccdbb420b1 --- /dev/null +++ b/source/lib/bitmap.c @@ -0,0 +1,130 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + simple bitmap functions + Copyright (C) Andrew Tridgell 1992-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +extern int DEBUGLEVEL; + +/* these functions provide a simple way to allocate integers from a + pool without repitition */ + + +/**************************************************************************** +allocate a bitmap of the specified size +****************************************************************************/ +struct bitmap *bitmap_allocate(int n) +{ + struct bitmap *bm; + + bm = (struct bitmap *)malloc(sizeof(*bm)); + bm->n = n; + + if (!bm) return NULL; + + bm->b = (uint32 *)malloc(sizeof(bm->b[0])*(n+31)/32); + if (!bm->b) { + free(bm); + return NULL; + } + + memset(bm->b, 0, sizeof(bm->b[0])*(n+31)/32); + + return bm; +} + +/**************************************************************************** +set a bit in a bitmap +****************************************************************************/ +BOOL bitmap_set(struct bitmap *bm, unsigned i) +{ + if (i >= bm->n) { + DEBUG(0,("Setting invalid bitmap entry %d (of %d)\n", + i, bm->n)); + return False; + } + bm->b[i/32] |= (1<<(i%32)); + return True; +} + +/**************************************************************************** +clear a bit in a bitmap +****************************************************************************/ +BOOL bitmap_clear(struct bitmap *bm, unsigned i) +{ + if (i >= bm->n) { + DEBUG(0,("clearing invalid bitmap entry %d (of %d)\n", + i, bm->n)); + return False; + } + bm->b[i/32] &= ~(1<<(i%32)); + return True; +} + +/**************************************************************************** +query a bit in a bitmap +****************************************************************************/ +static BOOL bitmap_query(struct bitmap *bm, unsigned i) +{ + if (i >= bm->n) return False; + if (bm->b[i/32] & (1<<(i%32))) { + return True; + } + return False; +} + +/**************************************************************************** +find a zero bit in a bitmap starting at the specified offset, with +wraparound +****************************************************************************/ +int bitmap_find(struct bitmap *bm, unsigned ofs) +{ + int i, j; + + if (ofs > bm->n) ofs = 0; + + i = ofs; + while (i < bm->n) { + if (~(bm->b[i/32])) { + j = i; + do { + if (!bitmap_query(bm, j)) return j; + j++; + } while (j & 31 && j < bm->n); + } + i += 32; + i &= ~31; + } + + i = 0; + while (i < ofs) { + if (~(bm->b[i/32])) { + j = i; + do { + if (!bitmap_query(bm, j)) return j; + j++; + } while (j & 31 && j < bm->n); + } + i += 32; + i &= ~31; + } + + return -1; +} diff --git a/source/lib/charcnv.c b/source/lib/charcnv.c index 049390f2a43..b016a07fd73 100644 --- a/source/lib/charcnv.c +++ b/source/lib/charcnv.c @@ -2,7 +2,7 @@ Unix SMB/Netbios implementation. Version 1.9. Character set conversion Extensions - Copyright (C) Andrew Tridgell 1992-1994 + Copyright (C) Andrew Tridgell 1992-1998 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,22 +20,23 @@ */ #include "includes.h" +#define CTRLZ 26 extern int DEBUGLEVEL; static char cvtbuf[1024]; -static mapsinited = 0; +static BOOL mapsinited = 0; static char unix2dos[256]; static char dos2unix[256]; -static void initmaps() { +static void initmaps(void) { int k; for (k = 0; k < 256; k++) unix2dos[k] = k; for (k = 0; k < 256; k++) dos2unix[k] = k; - mapsinited = 1; + mapsinited = True; } static void update_map(char * str) { @@ -50,77 +51,180 @@ static void update_map(char * str) { } } -static void initiso() { +static void init_iso8859_1(void) { + int i; 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"); + /* Do not map undefined characters to some accidental code */ + for (i = 128; i < 256; i++) + { + unix2dos[i] = CTRLZ; + dos2unix[i] = CTRLZ; + } + +/* MSDOS Code Page 850 -> ISO-8859 */ +update_map("\240\377\241\255\242\275\243\234\244\317\245\276\246\335\247\365"); +update_map("\250\371\251\270\252\246\253\256\254\252\255\360\256\251\257\356"); +update_map("\260\370\261\361\262\375\263\374\264\357\265\346\266\364\267\372"); +update_map("\270\367\271\373\272\247\273\257\274\254\275\253\276\363\277\250"); +update_map("\300\267\301\265\302\266\303\307\304\216\305\217\306\222\307\200"); +update_map("\310\324\311\220\312\322\313\323\314\336\315\326\316\327\317\330"); +update_map("\320\321\321\245\322\343\323\340\324\342\325\345\326\231\327\236"); +update_map("\330\235\331\353\332\351\333\352\334\232\335\355\336\350\337\341"); +update_map("\340\205\341\240\342\203\343\306\344\204\345\206\346\221\347\207"); +update_map("\350\212\351\202\352\210\353\211\354\215\355\241\356\214\357\213"); +update_map("\360\320\361\244\362\225\363\242\364\223\365\344\366\224\367\366"); +update_map("\370\233\371\227\372\243\373\226\374\201\375\354\376\347\377\230"); + +} + +/* Init for eastern european languages. */ + +static void init_iso8859_2(void) { + + int i; + if (!mapsinited) initmaps(); + + /* Do not map undefined characters to some accidental code */ + for (i = 128; i < 256; i++) + { + unix2dos[i] = CTRLZ; + dos2unix[i] = CTRLZ; + } + +/* + * Tranlation table created by Petr Hubeny <psh@capitol.cz> + * Requires client code page = 852 + * and character set = ISO8859-2 in smb.conf + */ + +/* MSDOS Code Page 852 -> ISO-8859-2 */ +update_map("\241\244\242\364\243\235\244\317\245\225\246\227\247\365"); +update_map("\250\371\251\346\252\270\253\233\254\215\256\246\257\275"); +update_map("\261\245\262\362\263\210\264\357\265\226\266\230\267\363"); +update_map("\270\367\271\347\272\255\273\234\274\253\275\361\276\247\277\276"); +update_map("\300\350\301\265\302\266\303\306\304\216\305\221\306\217\307\200"); +update_map("\310\254\311\220\312\250\313\323\314\267\315\326\316\327\317\322"); +update_map("\320\321\321\343\322\325\323\340\324\342\325\212\326\231\327\236"); +update_map("\330\374\331\336\332\351\333\353\334\232\335\355\336\335\337\341"); +update_map("\340\352\341\240\342\203\343\307\344\204\345\222\346\206\347\207"); +update_map("\350\237\351\202\352\251\353\211\354\330\355\241\356\214\357\324"); +update_map("\360\320\361\344\362\345\363\242\364\223\365\213\366\224\367\366"); +update_map("\370\375\371\205\372\243\373\373\374\201\375\354\376\356\377\372"); +} + +/* Init for russian language (iso8859-5) */ + +/* Added by Max Khon <max@iclub.nsu.ru> */ + +static void init_iso8859_5(void) +{ + int i; + if (!mapsinited) initmaps(); + + /* Do not map undefined characters to some accidental code */ + for (i = 128; i < 256; i++) + { + unix2dos[i] = CTRLZ; + dos2unix[i] = CTRLZ; + } + +/* MSDOS Code Page 866 -> ISO8859-5 */ +update_map("\200\260\201\261\202\262\203\263\204\264\205\265\206\266\207\267"); +update_map("\210\270\211\271\212\272\213\273\214\274\215\275\216\276\217\277"); +update_map("\220\300\221\301\222\302\223\303\224\304\225\305\226\306\227\307"); +update_map("\230\310\231\311\232\312\233\313\234\314\235\315\236\316\237\317"); +update_map("\240\320\241\321\242\322\243\323\244\324\245\325\246\326\247\327"); +update_map("\250\330\251\331\252\332\253\333\254\334\255\335\256\336\257\337"); +update_map("\340\340\341\341\342\342\343\343\344\344\345\345\346\346\347\347"); +update_map("\350\350\351\351\352\352\353\353\354\354\355\355\356\356\357\357"); +update_map("\360\241\361\361\362\244\363\364\364\247\365\367\366\256\367\376"); +update_map("\374\360\377\240"); +} + +/* Init for russian language (koi8) */ + +static void init_koi8_r(void) +{ + if (!mapsinited) initmaps(); + + /* There aren't undefined characters between 128 and 255 */ + +/* MSDOS Code Page 866 -> KOI8-R */ +update_map("\200\304\201\263\202\332\203\277\204\300\205\331\206\303\207\264"); +update_map("\210\302\211\301\212\305\213\337\214\334\215\333\216\335\217\336"); +update_map("\220\260\221\261\222\262\223\364\224\376\225\371\226\373\227\367"); +update_map("\230\363\231\362\232\377\233\365\234\370\235\375\236\372\237\366"); +update_map("\240\315\241\272\242\325\243\361\244\326\245\311\246\270\247\267"); +update_map("\250\273\251\324\252\323\253\310\254\276\255\275\256\274\257\306"); +update_map("\260\307\261\314\262\265\263\360\264\266\265\271\266\321\267\322"); +update_map("\270\313\271\317\272\320\273\312\274\330\275\327\276\316\277\374"); +update_map("\300\356\301\240\302\241\303\346\304\244\305\245\306\344\307\243"); +update_map("\310\345\311\250\312\251\313\252\314\253\315\254\316\255\317\256"); +update_map("\320\257\321\357\322\340\323\341\324\342\325\343\326\246\327\242"); +update_map("\330\354\331\353\332\247\333\350\334\355\335\351\336\347\337\352"); +update_map("\340\236\341\200\342\201\343\226\344\204\345\205\346\224\347\203"); +update_map("\350\225\351\210\352\211\353\212\354\213\355\214\356\215\357\216"); +update_map("\360\217\361\237\362\220\363\221\364\222\365\223\366\206\367\202"); +update_map("\370\234\371\233\372\207\373\230\374\235\375\231\376\227\377\232"); } /* * Convert unix to dos */ -char * -unix2dos_format(char *str,BOOL overwrite) +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; - } + + 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 *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; - } + + 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) +void interpret_character_set(char *str) { - if (strequal (str, "iso8859-1")) { - initiso(); - return def; + init_iso8859_1(); + } else if (strequal (str, "iso8859-2")) { + init_iso8859_2(); + } else if (strequal (str, "iso8859-5")) { + init_iso8859_5(); + } else if (strequal (str, "koi8-r")) { + init_koi8_r(); } else { DEBUG(0,("unrecognized character set\n")); } - return def; } diff --git a/source/lib/charset.c b/source/lib/charset.c index ada3ef790aa..08d7726e3bf 100644 --- a/source/lib/charset.c +++ b/source/lib/charset.c @@ -2,7 +2,7 @@ Unix SMB/Netbios implementation. Version 1.9. Character set handling - Copyright (C) Andrew Tridgell 1992-1995 + Copyright (C) Andrew Tridgell 1992-1998 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,22 +24,122 @@ extern int DEBUGLEVEL; +/* + * Codepage definitions. + */ + +#if !defined(KANJI) +/* lower->upper mapping for IBM Code Page 850 - MS-DOS Latin 1 */ +unsigned char cp_850[][4] = { +/* dec col/row oct hex description */ +/* 133 08/05 205 85 a grave */ +/* 183 11/07 267 B7 A grave */ {0x85,0xB7,1,1}, +/* 160 10/00 240 A0 a acute */ +/* 181 11/05 265 B5 A acute */ {0xA0,0xB5,1,1}, +/* 131 08/03 203 83 a circumflex */ +/* 182 11/06 266 B6 A circumflex */ {0x83,0xB6,1,1}, +/* 198 12/06 306 C6 a tilde */ +/* 199 12/07 307 C7 A tilde */ {0xC6,0xC7,1,1}, +/* 132 08/04 204 84 a diaeresis */ +/* 142 08/14 216 8E A diaeresis */ {0x84,0x8E,1,1}, +/* 134 08/06 206 86 a ring */ +/* 143 08/15 217 8F A ring */ {0x86,0x8F,1,1}, +/* 145 09/01 221 91 ae diphthong */ +/* 146 09/02 222 92 AE diphthong */ {0x91,0x92,1,1}, +/* 135 08/07 207 87 c cedilla */ +/* 128 08/00 200 80 C cedilla */ {0x87,0x80,1,1}, +/* 138 08/10 212 8A e grave */ +/* 212 13/04 324 D4 E grave */ {0x8A,0xD4,1,1}, +/* 130 08/02 202 82 e acute */ +/* 144 09/00 220 90 E acute */ {0x82,0x90,1,1}, +/* 136 08/08 210 88 e circumflex */ +/* 210 13/02 322 D2 E circumflex */ {0x88,0xD2,1,1}, +/* 137 08/09 211 89 e diaeresis */ +/* 211 13/03 323 D3 E diaeresis */ {0x89,0xD3,1,1}, +/* 141 08/13 215 8D i grave */ +/* 222 13/14 336 DE I grave */ {0x8D,0xDE,1,1}, +/* 161 10/01 241 A1 i acute */ +/* 214 13/06 326 D6 I acute */ {0xA1,0xD6,1,1}, +/* 140 08/12 214 8C i circumflex */ +/* 215 13/07 327 D7 I circumflex */ {0x8C,0xD7,1,1}, +/* 139 08/11 213 8B i diaeresis */ +/* 216 13/08 330 D8 I diaeresis */ {0x8B,0xD8,1,1}, +/* 208 13/00 320 D0 Icelandic eth */ +/* 209 13/01 321 D1 Icelandic Eth */ {0xD0,0xD1,1,1}, +/* 164 10/04 244 A4 n tilde */ +/* 165 10/05 245 A5 N tilde */ {0xA4,0xA5,1,1}, +/* 149 09/05 225 95 o grave */ +/* 227 14/03 343 E3 O grave */ {0x95,0xE3,1,1}, +/* 162 10/02 242 A2 o acute */ +/* 224 14/00 340 E0 O acute */ {0xA2,0xE0,1,1}, +/* 147 09/03 223 93 o circumflex */ +/* 226 14/02 342 E2 O circumflex */ {0x93,0xE2,1,1}, +/* 228 14/04 344 E4 o tilde */ +/* 229 14/05 345 E5 O tilde */ {0xE4,0xE5,1,1}, +/* 148 09/04 224 94 o diaeresis */ +/* 153 09/09 231 99 O diaeresis */ {0x94,0x99,1,1}, +/* 155 09/11 233 9B o slash */ +/* 157 09/13 235 9D O slash */ {0x9B,0x9D,1,1}, +/* 151 09/07 227 97 u grave */ +/* 235 14/11 353 EB U grave */ {0x97,0xEB,1,1}, +/* 163 10/03 243 A3 u acute */ +/* 233 14/09 351 E9 U acute */ {0xA3,0xE9,1,1}, +/* 150 09/06 226 96 u circumflex */ +/* 234 14/10 352 EA U circumflex */ {0x96,0xEA,1,1}, +/* 129 08/01 201 81 u diaeresis */ +/* 154 09/10 232 9A U diaeresis */ {0x81,0x9A,1,1}, +/* 236 14/12 354 EC y acute */ +/* 237 14/13 355 ED Y acute */ {0xEC,0xED,1,1}, +/* 231 14/07 347 E7 Icelandic thorn */ +/* 232 14/08 350 E8 Icelandic Thorn */ {0xE7,0xE8,1,1}, + + {0x9C,0,0,0}, /* Pound */ + {0,0,0,0} +}; +#else /* KANJI */ +/* lower->upper mapping for IBM Code Page 932 - MS-DOS Japanese SJIS */ +unsigned char cp_932[][4] = { + {0,0,0,0} +}; +#endif /* KANJI */ + 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; +char *dos_char_map = xx_dos_char_map; +char *upper_char_map = xx_upper_char_map; +char *lower_char_map = xx_lower_char_map; + +/* + * This code has been extended to deal with ascynchronous mappings + * like MS-DOS Latin US (Code page 437) where things like : + * a acute are capitalized to 'A', but the reverse mapping + * must not hold true. This allows the filename case insensitive + * matching in do_match() to work, as the DOS/Win95/NT client + * uses 'A' as a mask to match against characters like a acute. + * This is the meaning behind the parameters that allow a + * mapping from lower to upper, but not upper to lower. + */ -static void add_dos_char(int lower, int upper) +static void add_dos_char(int lower, BOOL map_lower_to_upper, + int upper, BOOL map_upper_to_lower) { - 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; + lower &= 0xff; + upper &= 0xff; + DEBUGADD( 6, ( "Adding chars 0x%x 0x%x (l->u = %s) (u->l = %s)\n", + lower, upper, + map_lower_to_upper ? "True" : "False", + map_upper_to_lower ? "True" : "False" ) ); + if (lower) dos_char_map[lower] = 1; + if (upper) dos_char_map[upper] = 1; + lower_char_map[lower] = (char)lower; /* Define tolower(lower) */ + upper_char_map[upper] = (char)upper; /* Define toupper(upper) */ if (lower && upper) { - lower_char_map[(char)upper] = (char)lower; - upper_char_map[(char)lower] = (char)upper; + if(map_upper_to_lower) + lower_char_map[upper] = (char)lower; + if(map_lower_to_upper) + upper_char_map[lower] = (char)upper; } } @@ -50,41 +150,226 @@ 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]; +#ifdef LC_ALL + /* include <locale.h> in includes.h if available for OS */ + /* we take only standard 7-bit ASCII definitions from ctype */ + setlocale(LC_ALL,"C"); +#endif - for (i= -128;i<=127;i++) { - dos_char_map[(char)i] = 0; + for (i= 0;i<=255;i++) { + dos_char_map[i] = 0; } for (i=0;i<=127;i++) { - if (isalnum((char)i) || strchr("._^$~!#%&-{}()@'`",(char)i)) - add_dos_char(i,0); + if (isalnum(i) || strchr("._^$~!#%&-{}()@'`",(char)i)) + add_dos_char(i,False,0,False); } - for (i= -128;i<=127;i++) { + for (i=0; i<=255; 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)*/ + + /* Some systems have buggy isupper/islower for characters + above 127. Best not to rely on them. */ + if(i < 128) { + if (isupper((int)c)) lower_char_map[i] = tolower(c); + if (islower((int)c)) upper_char_map[i] = toupper(c); + } + } +} + +/**************************************************************************** +load the client codepage. +****************************************************************************/ + +typedef unsigned char (*codepage_p)[4]; + +static codepage_p load_client_codepage( int client_codepage ) +{ + pstring codepage_file_name; + unsigned char buf[8]; + FILE *fp = NULL; + SMB_OFF_T size; + codepage_p cp_p = NULL; + SMB_STRUCT_STAT st; + + DEBUG(5, ("load_client_codepage: loading codepage %d.\n", client_codepage)); + + if(strlen(CODEPAGEDIR) + 14 > sizeof(codepage_file_name)) + { + DEBUG(0,("load_client_codepage: filename too long to load\n")); + return NULL; + } + + pstrcpy(codepage_file_name, CODEPAGEDIR); + pstrcat(codepage_file_name, "/"); + pstrcat(codepage_file_name, "codepage."); + slprintf(&codepage_file_name[strlen(codepage_file_name)], + sizeof(pstring)-(strlen(codepage_file_name)+1), + "%03d", + client_codepage); + + if(!file_exist(codepage_file_name,&st)) + { + DEBUG(0,("load_client_codepage: filename %s does not exist.\n", + codepage_file_name)); + return NULL; + } + + /* Check if it is at least big enough to hold the required + data. Should be 2 byte version, 2 byte codepage, 4 byte length, + plus zero or more bytes of data. Note that the data cannot be more + than 4 * MAXCODEPAGELINES bytes. + */ + size = st.st_size; + + if( size < CODEPAGE_HEADER_SIZE || size > (CODEPAGE_HEADER_SIZE + 4 * MAXCODEPAGELINES)) + { + DEBUG(0,("load_client_codepage: file %s is an incorrect size for a \ +code page file.\n", codepage_file_name)); + return NULL; + } + + /* Read the first 8 bytes of the codepage file - check + the version number and code page number. All the data + is held in little endian format. + */ + + if((fp = fopen( codepage_file_name, "r")) == NULL) + { + DEBUG(0,("load_client_codepage: cannot open file %s. Error was %s\n", + codepage_file_name, strerror(errno))); + return NULL; + } + + if(fread( buf, 1, CODEPAGE_HEADER_SIZE, fp)!=CODEPAGE_HEADER_SIZE) + { + DEBUG(0,("load_client_codepage: cannot read header from file %s. Error was %s\n", + codepage_file_name, strerror(errno))); + goto clean_and_exit; + } + + /* Check the version value */ + if(SVAL(buf,CODEPAGE_VERSION_OFFSET) != CODEPAGE_FILE_VERSION_ID) + { + DEBUG(0,("load_client_codepage: filename %s has incorrect version id. \ +Needed %hu, got %hu.\n", + codepage_file_name, (uint16)CODEPAGE_FILE_VERSION_ID, + SVAL(buf,CODEPAGE_VERSION_OFFSET))); + goto clean_and_exit; + } + + /* Check the codepage matches */ + if(SVAL(buf,CODEPAGE_CLIENT_CODEPAGE_OFFSET) != (uint16)client_codepage) + { + DEBUG(0,("load_client_codepage: filename %s has incorrect codepage. \ +Needed %hu, got %hu.\n", + codepage_file_name, (uint16)client_codepage, + SVAL(buf,CODEPAGE_CLIENT_CODEPAGE_OFFSET))); + goto clean_and_exit; + } + + /* Check the length is correct. */ + if(IVAL(buf,CODEPAGE_LENGTH_OFFSET) != (size - CODEPAGE_HEADER_SIZE)) + { + DEBUG(0,("load_client_codepage: filename %s has incorrect size headers. \ +Needed %u, got %u.\n", codepage_file_name, (uint32)(size - CODEPAGE_HEADER_SIZE), + IVAL(buf,CODEPAGE_LENGTH_OFFSET))); + goto clean_and_exit; + } + + size -= CODEPAGE_HEADER_SIZE; /* Remove header */ + + /* Make sure the size is a multiple of 4. */ + if((size % 4 ) != 0) + { + DEBUG(0,("load_client_codepage: filename %s has a codepage size not a \ +multiple of 4.\n", codepage_file_name)); + goto clean_and_exit; + } + + /* Allocate space for the code page file and read it all in. */ + if((cp_p = (codepage_p)malloc( size + 4 )) == NULL) + { + DEBUG(0,("load_client_codepage: malloc fail.\n")); + goto clean_and_exit; + } + + if(fread( (char *)cp_p, 1, size, fp)!=size) + { + DEBUG(0,("load_client_codepage: read fail on file %s. Error was %s.\n", + codepage_file_name, strerror(errno))); + goto clean_and_exit; + } + + /* Ensure array is correctly terminated. */ + memset(((char *)cp_p) + size, '\0', 4); + + fclose(fp); + return cp_p; + +clean_and_exit: + + /* pseudo destructor :-) */ + + if(fp != NULL) + fclose(fp); + if(cp_p) + free((char *)cp_p); + return NULL; } +/**************************************************************************** +initialise the client codepage. +****************************************************************************/ +void codepage_initialise(int client_codepage) +{ + int i; + static codepage_p cp = NULL; + + if(cp != NULL) + { + DEBUG(6, + ("codepage_initialise: called twice - ignoring second client code page = %d\n", + client_codepage)); + return; + } + + DEBUG(6,("codepage_initialise: client code page = %d\n", client_codepage)); + + /* + * Known client codepages - these can be added to. + */ + cp = load_client_codepage( client_codepage ); + + if(cp == NULL) + { +#ifdef KANJI + DEBUG(6,("codepage_initialise: loading dynamic codepage file %s/codepage.%d \ +for code page %d failed. Using default client codepage 932\n", + CODEPAGEDIR, client_codepage, client_codepage)); + cp = cp_932; + client_codepage = KANJI_CODEPAGE; +#else /* KANJI */ + DEBUG(6,("codepage_initialise: loading dynamic codepage file %s/codepage.%d \ +for code page %d failed. Using default client codepage 850\n", + CODEPAGEDIR, client_codepage, client_codepage)); + cp = cp_850; + client_codepage = MSDOS_LATIN_1_CODEPAGE; +#endif /* KANJI */ + } + + /* + * Setup the function pointers for the loaded codepage. + */ + initialize_multibyte_vectors( client_codepage ); + + if(cp) + { + for(i = 0; !((cp[i][0] == '\0') && (cp[i][1] == '\0')); i++) + add_dos_char(cp[i][0], (BOOL)cp[i][2], cp[i][1], (BOOL)cp[i][3]); + } +} /******************************************************************* add characters depending on a string passed by the user @@ -98,12 +383,12 @@ void add_char_string(char *s) 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)=='-') { + if (isdigit((unsigned char)*t) || (*t)=='-') { sscanf(t,"%i:%i",&i1,&i2); - add_dos_char(i1,i2); + add_dos_char(i1,True,i2,True); } else { sscanf(t,"%c:%c",&c1,&c2); - add_dos_char(c1,c2); + add_dos_char((unsigned char)c1,True,(unsigned char)c2, True); } } diff --git a/source/lib/debug.c b/source/lib/debug.c new file mode 100644 index 00000000000..6b7b9341a3c --- /dev/null +++ b/source/lib/debug.c @@ -0,0 +1,588 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Samba utility functions + Copyright (C) Andrew Tridgell 1992-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* -------------------------------------------------------------------------- ** + * Defines... + * + * FORMAT_BUFR_MAX - Index of the last byte of the format buffer; + * format_bufr[FORMAT_BUFR_MAX] should always be reserved + * for a terminating nul byte. + */ + +#define FORMAT_BUFR_MAX ( sizeof( format_bufr ) - 1 ) + +/* -------------------------------------------------------------------------- ** + * This module implements Samba's debugging utility. + * + * The syntax of a debugging log file is represented as: + * + * <debugfile> :== { <debugmsg> } + * + * <debugmsg> :== <debughdr> '\n' <debugtext> + * + * <debughdr> :== '[' TIME ',' LEVEL ']' [ [FILENAME ':'] [FUNCTION '()'] ] + * + * <debugtext> :== { <debugline> } + * + * <debugline> :== TEXT '\n' + * + * TEXT is a string of characters excluding the newline character. + * LEVEL is the DEBUG level of the message (an integer in the range 0..10). + * TIME is a timestamp. + * FILENAME is the name of the file from which the debug message was generated. + * FUNCTION is the function from which the debug message was generated. + * + * Basically, what that all means is: + * + * - A debugging log file is made up of debug messages. + * + * - Each debug message is made up of a header and text. The header is + * separated from the text by a newline. + * + * - The header begins with the timestamp and debug level of the message + * enclosed in brackets. The filename and function from which the + * message was generated may follow. The filename is terminated by a + * colon, and the function name is terminated by parenthesis. + * + * - The message text is made up of zero or more lines, each terminated by + * a newline. + */ + +/* -------------------------------------------------------------------------- ** + * External variables. + * + * dbf - Global debug file handle. + * debugf - Debug file name. + * append_log - If True, then the output file will be opened in append + * mode. + * DEBUGLEVEL - System-wide debug message limit. Messages with message- + * levels higher than DEBUGLEVEL will not be processed. + */ + +FILE *dbf = NULL; +pstring debugf = ""; +BOOL append_log = False; +int DEBUGLEVEL = 1; + + +/* -------------------------------------------------------------------------- ** + * Internal variables. + * + * stdout_logging - Default False, if set to True then dbf will be set to + * stdout and debug output will go to dbf only, and not + * to syslog. Set in setup_logging() and read in Debug1(). + * + * debug_count - Number of debug messages that have been output. + * Used to check log size. + * + * syslog_level - Internal copy of the message debug level. Written by + * dbghdr() and read by Debug1(). + * + * format_bufr - Used to format debug messages. The dbgtext() function + * prints debug messages to a string, and then passes the + * string to format_debug_text(), which uses format_bufr + * to build the formatted output. + * + * format_pos - Marks the first free byte of the format_bufr. + */ + +static BOOL stdout_logging = False; +static int debug_count = 0; +#ifdef WITH_SYSLOG +static int syslog_level = 0; +#endif +static pstring format_bufr = { '\0' }; +static int format_pos = 0; + + +/* -------------------------------------------------------------------------- ** + * Functions... + */ + +#if defined(SIGUSR2) +/* ************************************************************************** ** + * catch a sigusr2 - decrease the debug log level. + * ************************************************************************** ** + */ +void sig_usr2( int sig ) + { + BlockSignals( True, SIGUSR2 ); + + DEBUGLEVEL--; + if( DEBUGLEVEL < 0 ) + DEBUGLEVEL = 0; + + DEBUG( 0, ( "Got SIGUSR2; set debug level to %d.\n", DEBUGLEVEL ) ); + + BlockSignals( False, SIGUSR2 ); + CatchSignal( SIGUSR2, SIGNAL_CAST sig_usr2 ); + + } /* sig_usr2 */ +#endif /* SIGUSR2 */ + +#if defined(SIGUSR1) +/* ************************************************************************** ** + * catch a sigusr1 - increase the debug log level. + * ************************************************************************** ** + */ +void sig_usr1( int sig ) + { + BlockSignals( True, SIGUSR1 ); + + DEBUGLEVEL++; + + if( DEBUGLEVEL > 10 ) + DEBUGLEVEL = 10; + + DEBUG( 0, ( "Got SIGUSR1; set debug level to %d.\n", DEBUGLEVEL ) ); + + BlockSignals( False, SIGUSR1 ); + CatchSignal( SIGUSR1, SIGNAL_CAST sig_usr1 ); + + } /* sig_usr1 */ +#endif /* SIGUSR1 */ + + +/* ************************************************************************** ** + * get ready for syslog stuff + * ************************************************************************** ** + */ +void setup_logging( char *pname, BOOL interactive ) + { + if( interactive ) + { + stdout_logging = True; + dbf = stdout; + } +#ifdef WITH_SYSLOG + else + { + char *p = strrchr( pname,'/' ); + + if( p ) + pname = p + 1; +#ifdef LOG_DAEMON + openlog( pname, LOG_PID, SYSLOG_FACILITY ); +#else /* for old systems that have no facility codes. */ + openlog( pname, LOG_PID ); +#endif + } +#endif + } /* setup_logging */ + +/* ************************************************************************** ** + * reopen the log files + * ************************************************************************** ** + */ +void reopen_logs( void ) + { + pstring fname; + + if( DEBUGLEVEL > 0 ) + { + pstrcpy( fname, debugf ); + if( lp_loaded() && (*lp_logfile()) ) + pstrcpy( fname, lp_logfile() ); + + if( !strcsequal( fname, debugf ) || !dbf || !file_exist( debugf, NULL ) ) + { + mode_t oldumask = umask( 022 ); + + pstrcpy( debugf, fname ); + if( dbf ) + (void)fclose( dbf ); + if( append_log ) + dbf = fopen( debugf, "a" ); + else + dbf = fopen( debugf, "w" ); + /* Fix from klausr@ITAP.Physik.Uni-Stuttgart.De + * to fix problem where smbd's that generate less + * than 100 messages keep growing the log. + */ + force_check_log_size(); + if( dbf ) + setbuf( dbf, NULL ); + (void)umask( oldumask ); + } + } + else + { + if( dbf ) + { + (void)fclose( dbf ); + dbf = NULL; + } + } + } /* reopen_logs */ + +/* ************************************************************************** ** + * Force a check of the log size. + * ************************************************************************** ** + */ +void force_check_log_size( void ) + { + debug_count = 100; + } /* force_check_log_size */ + +/* ************************************************************************** ** + * Check to see if the log has grown to be too big. + * ************************************************************************** ** + */ +static void check_log_size( void ) + { + int maxlog; + SMB_STRUCT_STAT st; + + if( debug_count++ < 100 || getuid() != 0 ) + return; + + maxlog = lp_max_log_size() * 1024; + if( !dbf || maxlog <= 0 ) + return; + + if( sys_fstat( fileno( dbf ), &st ) == 0 && st.st_size > maxlog ) + { + (void)fclose( dbf ); + dbf = NULL; + reopen_logs(); + if( dbf && file_size( debugf ) > maxlog ) + { + pstring name; + + (void)fclose( dbf ); + dbf = NULL; + slprintf( name, sizeof(name)-1, "%s.old", debugf ); + (void)rename( debugf, name ); + reopen_logs(); + } + } + debug_count = 0; + } /* check_log_size */ + +/* ************************************************************************** ** + * Write an debug message on the debugfile. + * This is called by dbghdr() and format_debug_text(). + * ************************************************************************** ** + */ +#ifdef HAVE_STDARG_H + int Debug1( char *format_str, ... ) +{ +#else + int Debug1(va_alist) +va_dcl +{ + char *format_str; +#endif + va_list ap; + int old_errno = errno; + + if( stdout_logging ) + { +#ifdef HAVE_STDARG_H + va_start( ap, format_str ); +#else + va_start( ap ); + format_str = va_arg( ap, char * ); +#endif + (void)vfprintf( dbf, format_str, ap ); + va_end( ap ); + errno = old_errno; + return( 0 ); + } + +#ifdef WITH_SYSLOG + if( !lp_syslog_only() ) +#endif + { + if( !dbf ) + { + mode_t oldumask = umask( 022 ); + + if( append_log ) + dbf = fopen( debugf, "a" ); + else + dbf = fopen( debugf, "w" ); + (void)umask( oldumask ); + if( dbf ) + { + setbuf( dbf, NULL ); + } + else + { + errno = old_errno; + return(0); + } + } + } + +#ifdef WITH_SYSLOG + if( syslog_level < lp_syslog() ) + { + /* map debug levels to syslog() priorities + * note that not all DEBUG(0, ...) calls are + * necessarily errors + */ + static int priority_map[] = { + LOG_ERR, /* 0 */ + LOG_WARNING, /* 1 */ + LOG_NOTICE, /* 2 */ + LOG_INFO, /* 3 */ + }; + int priority; + pstring msgbuf; + + if( syslog_level >= ( sizeof(priority_map) / sizeof(priority_map[0]) ) + || syslog_level < 0) + priority = LOG_DEBUG; + else + priority = priority_map[syslog_level]; + +#ifdef HAVE_STDARG_H + va_start( ap, format_str ); +#else + va_start( ap ); + format_str = va_arg( ap, char * ); +#endif + vslprintf( msgbuf, sizeof(msgbuf)-1, format_str, ap ); + va_end( ap ); + + msgbuf[255] = '\0'; + syslog( priority, "%s", msgbuf ); + } +#endif + +#ifdef WITH_SYSLOG + if( !lp_syslog_only() ) +#endif + { +#ifdef HAVE_STDARG_H + va_start( ap, format_str ); +#else + va_start( ap ); + format_str = va_arg( ap, char * ); +#endif + (void)vfprintf( dbf, format_str, ap ); + va_end( ap ); + (void)fflush( dbf ); + } + + check_log_size(); + + errno = old_errno; + + return( 0 ); + } /* Debug1 */ + + +/* ************************************************************************** ** + * Print the buffer content via Debug1(), then reset the buffer. + * + * Input: none + * Output: none + * + * ************************************************************************** ** + */ +static void bufr_print( void ) + { + format_bufr[format_pos] = '\0'; + (void)Debug1( "%s", format_bufr ); + format_pos = 0; + } /* bufr_print */ + +/* ************************************************************************** ** + * Format the debug message text. + * + * Input: msg - Text to be added to the "current" debug message text. + * + * Output: none. + * + * Notes: The purpose of this is two-fold. First, each call to syslog() + * (used by Debug1(), see above) generates a new line of syslog + * output. This is fixed by storing the partial lines until the + * newline character is encountered. Second, printing the debug + * message lines when a newline is encountered allows us to add + * spaces, thus indenting the body of the message and making it + * more readable. + * + * ************************************************************************** ** + */ +static void format_debug_text( char *msg ) + { + int i; + BOOL timestamp = (!stdout_logging && (lp_timestamp_logs() || + !(lp_loaded()))); + + for( i = 0; msg[i]; i++ ) + { + /* Indent two spaces at each new line. */ + if(timestamp && 0 == format_pos) + { + format_bufr[0] = format_bufr[1] = ' '; + format_pos = 2; + } + + /* If there's room, copy the character to the format buffer. */ + if( format_pos < FORMAT_BUFR_MAX ) + format_bufr[format_pos++] = msg[i]; + + /* If a newline is encountered, print & restart. */ + if( '\n' == msg[i] ) + bufr_print(); + + /* If the buffer is full dump it out, reset it, and put out a line + * continuation indicator. + */ + if( format_pos >= FORMAT_BUFR_MAX ) + { + bufr_print(); + (void)Debug1( " +>\n" ); + } + } + + /* Just to be safe... */ + format_bufr[format_pos] = '\0'; + } /* format_debug_text */ + +/* ************************************************************************** ** + * Flush debug output, including the format buffer content. + * + * Input: none + * Output: none + * + * ************************************************************************** ** + */ +void dbgflush( void ) + { + bufr_print(); + (void)fflush( dbf ); + } /* dbgflush */ + +/* ************************************************************************** ** + * Print a Debug Header. + * + * Input: level - Debug level of the message (not the system-wide debug + * level. + * file - Pointer to a string containing the name of the file + * from which this function was called, or an empty string + * if the __FILE__ macro is not implemented. + * func - Pointer to a string containing the name of the function + * from which this function was called, or an empty string + * if the __FUNCTION__ macro is not implemented. + * line - line number of the call to dbghdr, assuming __LINE__ + * works. + * + * Output: Always True. This makes it easy to fudge a call to dbghdr() + * in a macro, since the function can be called as part of a test. + * Eg: ( (level <= DEBUGLEVEL) && (dbghdr(level,"",line)) ) + * + * Notes: This function takes care of setting syslog_level. + * + * ************************************************************************** ** + */ +BOOL dbghdr( int level, char *file, char *func, int line ) + { + if( format_pos ) + { + /* This is a fudge. If there is stuff sitting in the format_bufr, then + * the *right* thing to do is to call + * format_debug_text( "\n" ); + * to write the remainder, and then proceed with the new header. + * Unfortunately, there are several places in the code at which + * the DEBUG() macro is used to build partial lines. That in mind, + * we'll work under the assumption that an incomplete line indicates + * that a new header is *not* desired. + */ + return( True ); + } + +#ifdef WITH_SYSLOG + /* Set syslog_level. */ + syslog_level = level; +#endif + + /* Don't print a header if we're logging to stdout. */ + if( stdout_logging ) + return( True ); + + /* Print the header if timestamps are turned on. If parameters are + * not yet loaded, then default to timestamps on. + */ + if( lp_timestamp_logs() || !(lp_loaded()) ) + { + /* Print it all out at once to prevent split syslog output. */ + (void)Debug1( "[%s, %d] %s:%s(%d)\n", + timestring(), level, file, func, line ); + } + + return( True ); + } /* dbghdr */ + +/* ************************************************************************** ** + * Add text to the body of the "current" debug message via the format buffer. + * + * Input: format_str - Format string, as used in printf(), et. al. + * ... - Variable argument list. + * + * ..or.. va_alist - Old style variable parameter list starting point. + * + * Output: Always True. See dbghdr() for more info, though this is not + * likely to be used in the same way. + * + * ************************************************************************** ** + */ +#ifdef HAVE_STDARG_H + BOOL dbgtext( char *format_str, ... ) + { + va_list ap; + pstring msgbuf; + + va_start( ap, format_str ); + vslprintf( msgbuf, sizeof(msgbuf)-1, format_str, ap ); + va_end( ap ); + + format_debug_text( msgbuf ); + + return( True ); + } /* dbgtext */ + +#else + BOOL dbgtext( va_alist ) + va_dcl + { + char *format_str; + va_list ap; + pstring msgbuf; + + va_start( ap ); + format_str = va_arg( ap, char * ); + vslprintf( msgbuf, sizeof(msgbuf)-1, format_str, ap ); + va_end( ap ); + + format_debug_text( msgbuf ); + + return( True ); + } /* dbgtext */ + +#endif + +/* ************************************************************************** */ diff --git a/source/lib/fault.c b/source/lib/fault.c index 20c75f7876c..6effaf7d7c6 100644 --- a/source/lib/fault.c +++ b/source/lib/fault.c @@ -2,7 +2,7 @@ Unix SMB/Netbios implementation. Version 1.9. Critical Fault handling - Copyright (C) Andrew Tridgell 1992-1995 + Copyright (C) Andrew Tridgell 1992-1998 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,15 +19,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifdef LINUX -#define __KERNEL__ -#endif - #include "includes.h" extern int DEBUGLEVEL; -static void (*cont_fn)(); +static void (*cont_fn)(void *); /******************************************************************* @@ -35,28 +31,30 @@ report a fault ********************************************************************/ static void fault_report(int sig) { - DEBUG(0,("===============================================================\n")); - DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)getpid(),VERSION)); - DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n")); - DEBUG(0,("===============================================================\n")); + static int counter; + + if (counter) _exit(1); + + counter++; + + DEBUG(0,("===============================================================\n")); + DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)getpid(),VERSION)); + DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n")); + DEBUG(0,("===============================================================\n")); -#if AJT - ajt_panic(); -#endif + smb_panic("internal error"); - if (cont_fn) - { - fault_setup(cont_fn); - cont_fn(NULL); + if (cont_fn) { + cont_fn(NULL); #ifdef SIGSEGV - signal(SIGSEGV,SIGNAL_CAST SIG_DFL); + CatchSignal(SIGSEGV,SIGNAL_CAST SIG_DFL); #endif #ifdef SIGBUS - signal(SIGBUS,SIGNAL_CAST SIG_DFL); + CatchSignal(SIGBUS,SIGNAL_CAST SIG_DFL); #endif - return; /* this should cause a core dump */ - } - exit(1); + return; /* this should cause a core dump */ + } + exit(1); } /**************************************************************************** @@ -64,21 +62,21 @@ catch serious errors ****************************************************************************/ static void sig_fault(int sig) { - fault_report(sig); + fault_report(sig); } /******************************************************************* setup our fault handlers ********************************************************************/ -void fault_setup(void (*fn)()) +void fault_setup(void (*fn)(void *)) { - cont_fn = fn; + cont_fn = fn; #ifdef SIGSEGV - signal(SIGSEGV,SIGNAL_CAST sig_fault); + CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault); #endif #ifdef SIGBUS - signal(SIGBUS,SIGNAL_CAST sig_fault); + CatchSignal(SIGBUS,SIGNAL_CAST sig_fault); #endif } diff --git a/source/lib/genrand.c b/source/lib/genrand.c new file mode 100644 index 00000000000..bb1922e4f5c --- /dev/null +++ b/source/lib/genrand.c @@ -0,0 +1,226 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + + Functions to create reasonable random numbers for crypto use. + + Copyright (C) Jeremy Allison 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +extern int DEBUGLEVEL; +static uint32 counter = 0; + +/**************************************************************** +get a 16 byte hash from the contents of a file +Note that the hash is not initialised. +*****************************************************************/ +static void do_filehash(char *fname, unsigned char *hash) +{ + unsigned char buf[1011]; /* deliberate weird size */ + unsigned char tmp_md4[16]; + int fd, n; + + fd = open(fname,O_RDONLY); + if (fd == -1) return; + + while ((n = read(fd, (char *)buf, sizeof(buf))) > 0) { + mdfour(tmp_md4, buf, n); + for (n=0;n<16;n++) + hash[n] ^= tmp_md4[n]; + } + close(fd); +} + + + +/**************************************************************** + Try and get a seed by looking at the atimes of files in a given + directory. XOR them into the buf array. +*****************************************************************/ + +static void do_dirrand(char *name, unsigned char *buf, int buf_len) +{ + void *dp = dos_opendir(name); + pstring fullname; + int len_left; + int fullname_len; + char *pos; + + pstrcpy(fullname, name); + fullname_len = strlen(fullname); + + if(fullname_len + 2 > sizeof(pstring)) + return; + + if(fullname[fullname_len] != '/') { + fullname[fullname_len] = '/'; + fullname[fullname_len+1] = '\0'; + fullname_len = strlen(fullname); + } + + len_left = sizeof(pstring) - fullname_len - 1; + pos = &fullname[fullname_len]; + + if(dp != NULL) { + char *p; + + while ((p = readdirname(dp))) { + SMB_STRUCT_STAT st; + + if(strlen(p) <= len_left) + pstrcpy(pos, p); + + if(dos_stat(fullname,&st) == 0) { + SIVAL(buf, ((counter * 4)%(buf_len-4)), + IVAL(buf,((counter * 4)%(buf_len-4))) ^ st.st_atime); + counter++; + DEBUG(10,("do_dirrand: value from file %s.\n", fullname)); + } + } + closedir(dp); + } +} + +/************************************************************** + Try and get a good random number seed. Try a number of + different factors. Firstly, try /dev/random and try and + read from this. If this fails iterate through /tmp and + /dev and XOR all the file timestamps. Next add in + a hash of the contents of /etc/shadow and the smb passwd + file and a combination of pid and time of day (yes I know this + sucks :-). Finally md4 the result. + + The result goes in a 16 byte buffer passed from the caller +**************************************************************/ + +static uint32 do_reseed(unsigned char *md4_outbuf) +{ + unsigned char md4_inbuf[40]; + BOOL got_random = False; + uint32 v1, v2, ret; + int fd; + struct timeval tval; + pid_t mypid; + struct passwd *pw; + + memset(md4_inbuf, '\0', sizeof(md4_inbuf)); + + fd = open( "/dev/random", O_RDONLY); + if(fd >= 0) { + /* + * We can use /dev/random ! + */ + if(read(fd, md4_inbuf, 40) == 40) { + got_random = True; + DEBUG(10,("do_reseed: got 40 bytes from /dev/random.\n")); + } + close(fd); + } + + if(!got_random) { + /* + * /dev/random failed - try /tmp and /dev for timestamps. + */ + do_dirrand("/tmp", md4_inbuf, sizeof(md4_inbuf)); + do_dirrand("/dev", md4_inbuf, sizeof(md4_inbuf)); + } + + /* possibly add in some secret file contents */ + do_filehash("/etc/shadow", &md4_inbuf[0]); + do_filehash(lp_smb_passwd_file(), &md4_inbuf[16]); + + /* add in the root encrypted password. On any system where security is taken + seriously this will be secret */ + pw = getpwnam("root"); + if (pw && pw->pw_passwd) { + int i; + unsigned char md4_tmp[16]; + mdfour(md4_tmp, (unsigned char *)pw->pw_passwd, strlen(pw->pw_passwd)); + for (i=0;i<16;i++) + md4_inbuf[8+i] ^= md4_tmp[i]; + } + + /* + * Finally add the counter, time of day, and pid. + */ + GetTimeOfDay(&tval); + mypid = getpid(); + v1 = (counter++) + mypid + tval.tv_sec; + v2 = (counter++) * mypid + tval.tv_usec; + + SIVAL(md4_inbuf, 32, v1 ^ IVAL(md4_inbuf, 32)); + SIVAL(md4_inbuf, 36, v2 ^ IVAL(md4_inbuf, 36)); + + mdfour(md4_outbuf, md4_inbuf, sizeof(md4_inbuf)); + + /* + * Return a 32 bit int created from XORing the + * 16 bit return buffer. + */ + + ret = IVAL(md4_outbuf, 0); + ret ^= IVAL(md4_outbuf, 4); + ret ^= IVAL(md4_outbuf, 8); + return (ret ^ IVAL(md4_outbuf, 12)); +} + +/******************************************************************* + Interface to the (hopefully) good crypto random number generator. +********************************************************************/ + +void generate_random_buffer( unsigned char *out, int len, BOOL re_seed) +{ + static BOOL done_reseed = False; + static unsigned char md4_buf[16]; + unsigned char tmp_buf[16]; + unsigned char *p; + + if(!done_reseed || re_seed) { + sys_srandom(do_reseed(md4_buf)); + done_reseed = True; + } + + /* + * Generate random numbers in chunks of 64 bytes, + * then md4 them & copy to the output buffer. + * Added XOR with output from random, seeded + * by the original md4_buf. This is to stop the + * output from this function being the previous + * md4_buf md4'ed. The output from this function + * is often output onto the wire, and so it should + * not be possible to guess the next output from + * this function based on the previous output. + * XORing in the output from random(), seeded by + * the original md4 hash should stop this. JRA. + */ + + p = out; + while(len > 0) { + int i; + int copy_len = len > 16 ? 16 : len; + mdfour(tmp_buf, md4_buf, sizeof(md4_buf)); + memcpy(md4_buf, tmp_buf, sizeof(md4_buf)); + /* XOR in output from random(). */ + for(i = 0; i < 4; i++) + SIVAL(tmp_buf, i*4, (IVAL(tmp_buf, i*4) ^ (uint32)sys_random())); + memcpy(p, tmp_buf, copy_len); + p += copy_len; + len -= copy_len; + } +} diff --git a/source/lib/getsmbpass.c b/source/lib/getsmbpass.c index 07a7dbfd9b5..7e544fa8d07 100644 --- a/source/lib/getsmbpass.c +++ b/source/lib/getsmbpass.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. +/* Copyright (C) 1992-1998 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -40,20 +40,19 @@ static struct termio t; #define TCSANOW 0 #endif -int tcgetattr(int fd, struct termio *t) +static int tcgetattr(int fd, struct termio *t) { return ioctl(fd, TCGETA, t); } -int tcsetattr(int fd, int flags, const struct termio *t) +static int tcsetattr(int fd, int flags, struct termio *t) { if(flags & TCSAFLUSH) ioctl(fd, TCFLSH, TCIOFLUSH); return ioctl(fd, TCSETS, t); } -#else /* SYSV_TERMIO */ -#ifdef BSD_TERMIO +#elif !defined(TCSAFLUSH) /* BSD TERMIO HANDLING */ @@ -63,37 +62,28 @@ static struct sgttyb t; #define TURN_ECHO_OFF(t) ((t).sg_flags &= ~ECHO) #define TURN_ECHO_ON(t) ((t).sg_flags |= ECHO) -#ifndef TCSAFLUSH #define TCSAFLUSH 1 -#endif - -#ifndef TCSANOW #define TCSANOW 0 -#endif -int tcgetattr(int fd, struct sgttyb *t) +static int tcgetattr(int fd, struct sgttyb *t) { return ioctl(fd, TIOCGETP, (char *)t); } -int tcsetattr(int fd, int flags, const struct sgttyb *t) +static int tcsetattr(int fd, int flags, struct sgttyb *t) { return ioctl(fd, TIOCSETP, (char *)t); } -#else /* BSD_TERMIO */ - -/* POSIX TERMIO HANDLING */ +#else /* POSIX TERMIO HANDLING */ #define ECHO_IS_ON(t) ((t).c_lflag & ECHO) #define TURN_ECHO_OFF(t) ((t).c_lflag &= ~ECHO) #define TURN_ECHO_ON(t) ((t).c_lflag |= ECHO) static struct termios t; -#endif /* BSD_TERMIO */ #endif /* SYSV_TERMIO */ -char * -getsmbpass(char *prompt) +char *getsmbpass(char *prompt) { FILE *in, *out; int echo_off; @@ -102,7 +92,7 @@ getsmbpass(char *prompt) size_t nread; /* Catch problematic signals */ - signal(SIGINT, SIGNAL_CAST SIG_IGN); + CatchSignal(SIGINT, SIGNAL_CAST SIG_IGN); /* Try to write to and read from the terminal if we can. If we can't open the terminal, use stderr and stdin. */ @@ -154,7 +144,7 @@ getsmbpass(char *prompt) fclose (in); /* Catch problematic signals */ - signal(SIGINT, SIGNAL_CAST SIG_DFL); + CatchSignal(SIGINT, SIGNAL_CAST SIG_DFL); printf("\n"); return buf; @@ -162,5 +152,5 @@ getsmbpass(char *prompt) #else -void getsmbpasswd_dummy() {;} + void getsmbpasswd_dummy(void) {;} #endif diff --git a/source/lib/interface.c b/source/lib/interface.c new file mode 100644 index 00000000000..65d276021ce --- /dev/null +++ b/source/lib/interface.c @@ -0,0 +1,382 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + multiple interface handling + Copyright (C) Andrew Tridgell 1992-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +extern int DEBUGLEVEL; + +struct in_addr ipzero; +struct in_addr allones_ip; +struct in_addr loopback_ip; +static struct in_addr default_ip; +static struct in_addr default_bcast; +static struct in_addr default_nmask; +static BOOL got_ip=False; +static BOOL got_bcast=False; +static BOOL got_nmask=False; + +static struct interface *local_interfaces = NULL; + +struct interface *last_iface; + +#define ALLONES ((uint32)0xFFFFFFFF) +#define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES)) +/**************************************************************************** +calculate the default netmask for an address +****************************************************************************/ +static void default_netmask(struct in_addr *inm, struct in_addr *iad) +{ + /* + ** Guess a netmask based on the class of the IP address given. + */ + switch((ntohl(iad->s_addr) & 0xE0000000)) { + case 0x00000000: /* Class A addr */ + case 0x20000000: + case 0x40000000: + case 0x60000000: + inm->s_addr = htonl(0xFF000000); + break; + + case 0x80000000: /* Class B addr */ + case 0xA0000000: + inm->s_addr = htonl(0xFFFF0000); + break; + + case 0xC0000000: /* Class C addr */ + inm->s_addr = htonl(0xFFFFFF00); + break; + + default: /* ??? */ + inm->s_addr = htonl(0xFFFFFFF0); + } +} + + +/**************************************************************************** + get the broadcast address for our address +(troyer@saifr00.ateng.az.honeywell.com) +****************************************************************************/ +static void get_broadcast(struct in_addr *if_ipaddr, + struct in_addr *if_bcast, + struct in_addr *if_nmask) +{ + uint32 nm; + short onbc; + short offbc; + + /* get a default netmask and broadcast */ + default_netmask(if_nmask, if_ipaddr); + + get_netmask(if_ipaddr, if_nmask); + + /* sanity check on the netmask */ + nm = ntohl(if_nmask->s_addr); + onbc = 0; + offbc = 0; + while((onbc + offbc) < 32) { + if(nm & 0x80000000) { + onbc++; + if(offbc) { + /* already found an off bit, so mask + is wrong */ + onbc = 34; + } + } else { + offbc++; + } + nm <<= 1; + } + if ((onbc < 8)||(onbc == 34)) { + 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 */ + if_bcast->s_addr = MKBCADDR(if_ipaddr->s_addr, if_nmask->s_addr); + + DEBUG(4,("Derived broadcast address %s\n", inet_ntoa(*if_bcast))); +} + + + +/**************************************************************************** +load a list of network interfaces +****************************************************************************/ +static void interpret_interfaces(char *s, struct interface **interfaces, + char *description) +{ + char *ptr; + fstring token; + struct interface *iface; + struct in_addr ip; + + ptr = s; + ipzero = *interpret_addr2("0.0.0.0"); + allones_ip = *interpret_addr2("255.255.255.255"); + loopback_ip = *interpret_addr2("127.0.0.1"); + + while (next_token(&ptr,token,NULL,sizeof(token))) { + /* parse it into an IP address/netmasklength pair */ + char *p = strchr(token,'/'); + if (p) *p++ = 0; + + ip = *interpret_addr2(token); + + /* maybe we already have it listed */ + { + struct interface *i; + for (i=(*interfaces);i;i=i->next) + if (ip_equal(ip,i->ip)) break; + if (i) continue; + } + + iface = (struct interface *)malloc(sizeof(*iface)); + if (!iface) return; + + iface->ip = ip; + + if (p) { + if (strlen(p) > 2) + iface->nmask = *interpret_addr2(p); + else + iface->nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES)); + } else { + default_netmask(&iface->nmask,&iface->ip); + } + iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr); + iface->next = NULL; + + if (!(*interfaces)) { + (*interfaces) = iface; + } else { + last_iface->next = iface; + } + last_iface = iface; + DEBUG(2,("Added %s ip=%s ",description,inet_ntoa(iface->ip))); + DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast))); + DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask))); + } + + if (*interfaces) return; + + /* setup a default interface */ + iface = (struct interface *)malloc(sizeof(*iface)); + if (!iface) return; + + iface->next = NULL; + + if (got_ip) { + iface->ip = default_ip; + } else { + get_myname(NULL,&iface->ip); + } + + if (got_bcast) { + iface->bcast = default_bcast; + } else { + get_broadcast(&iface->ip,&iface->bcast,&iface->nmask); + } + + if (got_nmask) { + iface->nmask = default_nmask; + iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr); + } + + if (iface->bcast.s_addr != MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr)) { + DEBUG(2,("Warning: inconsistant interface %s\n",inet_ntoa(iface->ip))); + } + + iface->next = NULL; + (*interfaces) = last_iface = iface; + + DEBUG(2,("Added interface ip=%s ",inet_ntoa(iface->ip))); + DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast))); + DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask))); +} + + +/**************************************************************************** +load the remote and local interfaces +****************************************************************************/ +void load_interfaces(void) +{ + /* add the machine's interfaces to local interface structure*/ + interpret_interfaces(lp_interfaces(), &local_interfaces,"interface"); +} + + +/**************************************************************************** + override the defaults + **************************************************************************/ +void iface_set_default(char *ip,char *bcast,char *nmask) +{ + if (ip) { + got_ip = True; + default_ip = *interpret_addr2(ip); + } + + if (bcast) { + got_bcast = True; + default_bcast = *interpret_addr2(bcast); + } + + if (nmask) { + got_nmask = True; + default_nmask = *interpret_addr2(nmask); + } +} + + +/**************************************************************************** + check if an IP is one of mine + **************************************************************************/ +BOOL ismyip(struct in_addr ip) +{ + struct interface *i; + for (i=local_interfaces;i;i=i->next) + if (ip_equal(i->ip,ip)) return True; + return False; +} + +/**************************************************************************** + check if a packet is from a local (known) net + **************************************************************************/ +BOOL is_local_net(struct in_addr from) +{ + struct interface *i; + for (i=local_interfaces;i;i=i->next) + if((from.s_addr & i->nmask.s_addr) == (i->ip.s_addr & i->nmask.s_addr)) + return True; + return False; +} + +/**************************************************************************** + how many interfaces do we have + **************************************************************************/ +int iface_count(void) +{ + int ret = 0; + struct interface *i; + + for (i=local_interfaces;i;i=i->next) + ret++; + return ret; +} + +/**************************************************************************** + True if we have two or more interfaces. + **************************************************************************/ +BOOL we_are_multihomed(void) +{ + static int multi = -1; + + if(multi == -1) + multi = (iface_count() > 1 ? True : False); + + return multi; +} + +/**************************************************************************** + return the Nth interface + **************************************************************************/ +struct interface *get_interface(int n) +{ + struct interface *i; + + for (i=local_interfaces;i && n;i=i->next) + n--; + + if (i) return i; + return NULL; +} + +/**************************************************************************** + return IP of the Nth interface + **************************************************************************/ +struct in_addr *iface_n_ip(int n) +{ + struct interface *i; + + for (i=local_interfaces;i && n;i=i->next) + n--; + + if (i) return &i->ip; + return NULL; +} + +/**************************************************************************** +Try and find an interface that matches an ip. If we cannot, return NULL + **************************************************************************/ +static struct interface *iface_find(struct in_addr ip) +{ + struct interface *i; + if (zero_ip(ip)) return local_interfaces; + + for (i=local_interfaces;i;i=i->next) + if (same_net(i->ip,ip,i->nmask)) return i; + + return NULL; +} + + +/**************************************************************************** +this function provides a simple hash of the configured interfaces. It is +used to detect a change in interfaces to tell us whether to discard +the current wins.dat file. +Note that the result is independent of the order of the interfaces + **************************************************************************/ +unsigned iface_hash(void) +{ + unsigned ret = 0; + struct interface *i; + + for (i=local_interfaces;i;i=i->next) { + unsigned x1 = (unsigned)str_checksum(inet_ntoa(i->ip)); + unsigned x2 = (unsigned)str_checksum(inet_ntoa(i->nmask)); + ret ^= (x1 ^ x2); + } + + return ret; +} + + +/* these 3 functions return the ip/bcast/nmask for the interface + most appropriate for the given ip address. If they can't find + an appropriate interface they return the requested field of the + first known interface. */ + +struct in_addr *iface_bcast(struct in_addr ip) +{ + struct interface *i = iface_find(ip); + return(i ? &i->bcast : &local_interfaces->bcast); +} + +struct in_addr *iface_ip(struct in_addr ip) +{ + struct interface *i = iface_find(ip); + return(i ? &i->ip : &local_interfaces->ip); +} + + + diff --git a/source/lib/kanji.c b/source/lib/kanji.c index 0af476eb157..04eecb54375 100644 --- a/source/lib/kanji.c +++ b/source/lib/kanji.c @@ -2,7 +2,7 @@ Unix SMB/Netbios implementation. Version 1.9. Kanji Extensions - Copyright (C) Andrew Tridgell 1992-1994 + Copyright (C) Andrew Tridgell 1992-1998 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,28 +23,76 @@ 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; +/* + * Function pointers that get overridden when multi-byte code pages + * are loaded. + */ + +char *(*multibyte_strchr)(char *, int ) = (char *(*)(char *, int )) strchr; +char *(*multibyte_strrchr)(char *, int ) = (char *(*)(char *, int )) strrchr; +char *(*multibyte_strstr)(char *, char *) = (char *(*)(char *, char *)) strstr; +char *(*multibyte_strtok)(char *, char *) = (char *(*)(char *, char *)) strtok; + +/* + * Kanji is treated differently here due to historical accident of + * it being the first non-English codepage added to Samba. + * The define 'KANJI' is being overloaded to mean 'use kanji codepage + * by default' and also 'this is the filename-to-disk conversion + * method to use'. This really should be removed and all control + * over this left in the smb.conf parameters 'client codepage' + * and 'coding system'. + */ + +#ifndef KANJI + +/* + * Set the default conversion to be the functions in + * charcnv.c. + */ + +static int skip_non_multibyte_char(char); +static BOOL not_multibyte_char_1(char); + +char *(*_dos_to_unix)(char *, BOOL) = dos2unix_format; +char *(*_unix_to_dos)(char *, BOOL) = unix2dos_format; +int (*_skip_multibyte_char)(char) = skip_non_multibyte_char; +BOOL (*is_multibyte_char_1)(char) = not_multibyte_char_1; + +#else /* KANJI */ + +/* + * Set the default conversion to be the function + * sj_to_sj in this file. + */ + +static char *sj_to_sj(char *from, BOOL overwrite); +static int skip_kanji_multibyte_char(char); +static BOOL is_kanji_multibyte_char_1(char); + +char *(*_dos_to_unix)(char *, BOOL) = sj_to_sj; +char *(*_unix_to_dos)(char *, BOOL) = sj_to_sj; +int (*_skip_multibyte_char)(char) = skip_kanji_multibyte_char; +int (*is_multibyte_char_1)(char) = is_kanji_multibyte_char_1; + +#endif /* KANJI */ /* jis si/so sequence */ -char jis_kso = JIS_KSO; -char jis_ksi = JIS_KSI; -char hex_tag = HEXTAG; +static char jis_kso = JIS_KSO; +static char jis_ksi = JIS_KSI; +static char hex_tag = HEXTAG; /******************************************************************* SHIFT JIS functions ********************************************************************/ /******************************************************************* search token from S1 separated any char of S2 - S1 contain SHIFT JIS chars. + S1 contains SHIFT JIS chars. ********************************************************************/ -char * -sj_strtok (char *s1, const char *s2) +static char *sj_strtok(char *s1, char *s2) { static char *s = NULL; char *q; @@ -81,12 +129,11 @@ sj_strtok (char *s1, const char *s2) /******************************************************************* search string S2 from S1 - S1 contain SHIFT JIS chars. + S1 contains SHIFT JIS chars. ********************************************************************/ -char * -sj_strstr (const char *s1, const char *s2) +static char *sj_strstr(char *s1, char *s2) { - register int len = strlen ((char *) s2); + int len = strlen ((char *) s2); if (!*s2) return (char *) s1; for (;*s1;) { @@ -105,10 +152,9 @@ sj_strstr (const char *s1, const char *s2) /******************************************************************* Search char C from beginning of S. - S contain SHIFT JIS chars. + S contains SHIFT JIS chars. ********************************************************************/ -char * -sj_strchr (const char *s, int c) +static char *sj_strchr (char *s, int c) { for (; *s; ) { if (*s == c) @@ -124,12 +170,11 @@ sj_strchr (const char *s, int c) /******************************************************************* Search char C end of S. - S contain SHIFT JIS chars. + S contains SHIFT JIS chars. ********************************************************************/ -char * -sj_strrchr (const char *s, int c) +static char *sj_strrchr(char *s, int c) { - register char *q; + char *q; for (q = 0; *s; ) { if (*s == c) { @@ -145,6 +190,184 @@ sj_strrchr (const char *s, int c) } /******************************************************************* + Kanji multibyte char skip function. +*******************************************************************/ + +static int skip_kanji_multibyte_char(char c) +{ + if(is_shift_jis(c)) { + return 2; + } else if (is_kana(c)) { + return 1; + } + return 0; +} + +/******************************************************************* + Kanji multibyte char identification. +*******************************************************************/ + +static BOOL is_kanji_multibyte_char_1(char c) +{ + return is_shift_jis(c); +} + +/******************************************************************* + The following functions are the only ones needed to do multibyte + support for Hangul, Big5 and Simplified Chinese. Most of the + real work for these codepages is done in the generic multibyte + functions. The only reason these functions are needed at all + is that the is_xxx(c) calls are really preprocessor macros. +********************************************************************/ + +/******************************************************************* + Hangul (Korean - code page 949) function. +********************************************************************/ + +static BOOL hangul_is_multibyte_char_1(char c) +{ + return is_hangul(c); +} + +/******************************************************************* + Big5 Traditional Chinese (code page 950) function. +********************************************************************/ + +static BOOL big5_is_multibyte_char_1(char c) +{ + return is_big5_c1(c); +} + +/******************************************************************* + Simplified Chinese (code page 936) function. +********************************************************************/ + +static BOOL simpch_is_multibyte_char_1(char c) +{ + return is_simpch_c1(c); +} + +/******************************************************************* + Generic multibyte functions - used by Hangul, Big5 and Simplified + Chinese codepages. +********************************************************************/ + +/******************************************************************* + search token from S1 separated any char of S2 + S1 contains generic multibyte chars. +********************************************************************/ + +static char *generic_multibyte_strtok(char *s1, char *s2) +{ + static char *s = NULL; + char *q; + if (!s1) { + if (!s) { + return NULL; + } + s1 = s; + } + for (q = s1; *s1; ) { + if ((*is_multibyte_char_1)(*s1)) { + s1 += 2; + } 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 contains generic multibyte chars. +********************************************************************/ + +static char *generic_multibyte_strstr(char *s1, char *s2) +{ + 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_multibyte_char_1)(*s1)) { + s1 += 2; + } else { + s1++; + } + } + return 0; +} + +/******************************************************************* + Search char C from beginning of S. + S contains generic multibyte chars. +********************************************************************/ + +static char *generic_multibyte_strchr(char *s, int c) +{ + for (; *s; ) { + if (*s == c) + return (char *) s; + if ((*is_multibyte_char_1)(*s)) { + s += 2; + } else { + s++; + } + } + return 0; +} + +/******************************************************************* + Search char C end of S. + S contains generic multibyte chars. +********************************************************************/ + +static char *generic_multibyte_strrchr(char *s, int c) +{ + char *q; + + for (q = 0; *s; ) { + if (*s == c) { + q = (char *) s; + } + if ((*is_multibyte_char_1)(*s)) { + s += 2; + } else { + s++; + } + } + return q; +} + +/******************************************************************* + Generic multibyte char skip function. +*******************************************************************/ + +static int skip_generic_multibyte_char(char c) +{ + if( (*is_multibyte_char_1)(c)) { + return 2; + } + return 0; +} + +/******************************************************************* Code conversion ********************************************************************/ /* convesion buffer */ @@ -153,8 +376,7 @@ static char cvtbuf[1024]; /******************************************************************* EUC <-> SJIS ********************************************************************/ -static int -euc2sjis (register int hi, register int lo) +static int euc2sjis (int hi, int lo) { if (hi & 1) return ((hi / 2 + (hi < 0xdf ? 0x31 : 0x71)) << 8) | @@ -163,8 +385,7 @@ euc2sjis (register int hi, register int lo) return ((hi / 2 + (hi < 0xdf ? 0x30 : 0x70)) << 8) | (lo - 2); } -static int -sjis2euc (register int hi, register int lo) +static int sjis2euc (int hi, int lo) { if (lo >= 0x9f) return ((hi * 2 - (hi >= 0xe0 ? 0xe0 : 0x60)) << 8) | (lo + 2); @@ -177,10 +398,9 @@ sjis2euc (register int hi, register int lo) Convert FROM contain SHIFT JIS codes to EUC codes return converted buffer ********************************************************************/ -static char * -sj_to_euc (const char *from, BOOL overwrite) +static char *sj_to_euc(char *from, BOOL overwrite) { - register char *out; + char *out; char *save; save = (char *) from; @@ -191,7 +411,7 @@ sj_to_euc (const char *from, BOOL overwrite) *out++ = code; from += 2; } else if (is_kana (*from)) { - *out++ = euc_kana; + *out++ = (char)euc_kana; *out++ = *from++; } else { *out++ = *from++; @@ -199,7 +419,7 @@ sj_to_euc (const char *from, BOOL overwrite) } *out = 0; if (overwrite) { - strcpy((char *) save, (char *) cvtbuf); + pstrcpy((char *) save, (char *) cvtbuf); return (char *) save; } else { return cvtbuf; @@ -210,10 +430,9 @@ sj_to_euc (const char *from, BOOL overwrite) Convert FROM contain EUC codes to SHIFT JIS codes return converted buffer ********************************************************************/ -static char * -euc_to_sj (const char *from, BOOL overwrite) +static char *euc_to_sj(char *from, BOOL overwrite) { - register char *out; + char *out; char *save; save = (char *) from; @@ -232,7 +451,7 @@ euc_to_sj (const char *from, BOOL overwrite) } *out = 0; if (overwrite) { - strcpy(save, (char *) cvtbuf); + pstrcpy(save, (char *) cvtbuf); return save; } else { return cvtbuf; @@ -242,8 +461,7 @@ euc_to_sj (const char *from, BOOL overwrite) /******************************************************************* JIS7,JIS8,JUNET <-> SJIS ********************************************************************/ -static int -sjis2jis (register int hi, register int lo) +static int sjis2jis(int hi, int lo) { if (lo >= 0x9f) return ((hi * 2 - (hi >= 0xe0 ? 0x160 : 0xe0)) << 8) | (lo - 0x7e); @@ -252,8 +470,7 @@ sjis2jis (register int hi, register int lo) (lo - (lo >= 0x7f ? 0x20 : 0x1f)); } -static int -jis2sjis (register int hi, register int lo) +static int jis2sjis(int hi, int lo) { if (hi & 1) return ((hi / 2 + (hi < 0x5f ? 0x71 : 0xb1)) << 8) | @@ -266,11 +483,10 @@ jis2sjis (register int hi, register int lo) Convert FROM contain JIS codes to SHIFT JIS codes return converted buffer ********************************************************************/ -static char * -jis8_to_sj (const char *from, BOOL overwrite) +static char *jis8_to_sj(char *from, BOOL overwrite) { - register char *out; - register int shifted; + char *out; + int shifted; char *save; shifted = _KJ_ROMAN; @@ -306,7 +522,7 @@ jis8_to_sj (const char *from, BOOL overwrite) } *out = 0; if (overwrite) { - strcpy (save, (char *) cvtbuf); + pstrcpy (save, (char *) cvtbuf); return save; } else { return cvtbuf; @@ -317,11 +533,10 @@ jis8_to_sj (const char *from, BOOL overwrite) Convert FROM contain SHIFT JIS codes to JIS codes return converted buffer ********************************************************************/ -static char * -sj_to_jis8 (const char *from, BOOL overwrite) +static char *sj_to_jis8(char *from, BOOL overwrite) { - register char *out; - register int shifted; + char *out; + int shifted; char *save; shifted = _KJ_ROMAN; @@ -363,7 +578,7 @@ sj_to_jis8 (const char *from, BOOL overwrite) } *out = 0; if (overwrite) { - strcpy (save, (char *) cvtbuf); + pstrcpy (save, (char *) cvtbuf); return save; } else { return cvtbuf; @@ -374,11 +589,10 @@ sj_to_jis8 (const char *from, BOOL overwrite) Convert FROM contain 7 bits JIS codes to SHIFT JIS codes return converted buffer ********************************************************************/ -static char * -jis7_to_sj (const char *from, BOOL overwrite) +static char *jis7_to_sj(char *from, BOOL overwrite) { - register char *out; - register int shifted; + char *out; + int shifted; char *save; shifted = _KJ_ROMAN; @@ -423,7 +637,7 @@ jis7_to_sj (const char *from, BOOL overwrite) } *out = 0; if (overwrite) { - strcpy (save, (char *) cvtbuf); + pstrcpy (save, (char *) cvtbuf); return save; } else { return cvtbuf; @@ -434,11 +648,10 @@ jis7_to_sj (const char *from, BOOL overwrite) Convert FROM contain SHIFT JIS codes to 7 bits JIS codes return converted buffer ********************************************************************/ -static char * -sj_to_jis7 (const char *from, BOOL overwrite) +static char *sj_to_jis7(char *from, BOOL overwrite) { - register char *out; - register int shifted; + char *out; + int shifted; char *save; shifted = _KJ_ROMAN; @@ -500,7 +713,7 @@ sj_to_jis7 (const char *from, BOOL overwrite) } *out = 0; if (overwrite) { - strcpy (save, (char *) cvtbuf); + pstrcpy (save, (char *) cvtbuf); return save; } else { return cvtbuf; @@ -511,11 +724,10 @@ sj_to_jis7 (const char *from, BOOL overwrite) 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) +static char *junet_to_sj(char *from, BOOL overwrite) { - register char *out; - register int shifted; + char *out; + int shifted; char *save; shifted = _KJ_ROMAN; @@ -557,7 +769,7 @@ junet_to_sj (const char *from, BOOL overwrite) } *out = 0; if (overwrite) { - strcpy (save, (char *) cvtbuf); + pstrcpy (save, (char *) cvtbuf); return save; } else { return cvtbuf; @@ -568,11 +780,10 @@ junet_to_sj (const char *from, BOOL overwrite) 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) +static char *sj_to_junet(char *from, BOOL overwrite) { - register char *out; - register int shifted; + char *out; + int shifted; char *save; shifted = _KJ_ROMAN; @@ -627,7 +838,7 @@ sj_to_junet (const char *from, BOOL overwrite) } *out = 0; if (overwrite) { - strcpy (save, (char *) cvtbuf); + pstrcpy (save, (char *) cvtbuf); return save; } else { return cvtbuf; @@ -638,15 +849,14 @@ sj_to_junet (const char *from, BOOL overwrite) HEX <-> SJIS ********************************************************************/ /* ":xx" -> a byte */ -static char * -hex_to_sj (const char *from, BOOL overwrite) +static char *hex_to_sj(char *from, BOOL overwrite) { char *sp, *dp; sp = (char *) from; dp = cvtbuf; while (*sp) { - if (*sp == hex_tag && isxdigit (sp[1]) && isxdigit (sp[2])) { + if (*sp == hex_tag && isxdigit((int)sp[1]) && isxdigit((int)sp[2])) { *dp++ = (hex2bin (sp[1])<<4) | (hex2bin (sp[2])); sp += 3; } else @@ -654,7 +864,7 @@ hex_to_sj (const char *from, BOOL overwrite) } *dp = '\0'; if (overwrite) { - strcpy ((char *) from, (char *) cvtbuf); + pstrcpy ((char *) from, (char *) cvtbuf); return (char *) from; } else { return cvtbuf; @@ -664,8 +874,7 @@ hex_to_sj (const char *from, BOOL overwrite) /******************************************************************* kanji/kana -> ":xx" ********************************************************************/ -static char * -sj_to_hex (const char *from, BOOL overwrite) +static char *sj_to_hex(char *from, BOOL overwrite) { unsigned char *sp, *dp; @@ -691,7 +900,7 @@ sj_to_hex (const char *from, BOOL overwrite) } *dp = '\0'; if (overwrite) { - strcpy ((char *) from, (char *) cvtbuf); + pstrcpy ((char *) from, (char *) cvtbuf); return (char *) from; } else { return cvtbuf; @@ -699,10 +908,41 @@ sj_to_hex (const char *from, BOOL overwrite) } /******************************************************************* - kanji/kana -> ":xx" + CAP <-> SJIS ********************************************************************/ -static char * -sj_to_cap (const char *from, BOOL overwrite) +/* ":xx" CAP -> a byte */ +static char *cap_to_sj(char *from, BOOL overwrite) +{ + char *sp, *dp; + + sp = (char *) from; + dp = cvtbuf; + while (*sp) { + /* + * The only change between this and hex_to_sj is here. sj_to_cap only + * translates characters greater or equal to 0x80 - make sure that here + * we only do the reverse (that's why the strchr is used rather than + * isxdigit. Based on fix from ado@elsie.nci.nih.gov (Arthur David Olson). + */ + if (*sp == hex_tag && (strchr ("89abcdefABCDEF", sp[1]) != NULL) && isxdigit((int)sp[2])) { + *dp++ = (hex2bin (sp[1])<<4) | (hex2bin (sp[2])); + sp += 3; + } else + *dp++ = *sp++; + } + *dp = '\0'; + if (overwrite) { + pstrcpy ((char *) from, (char *) cvtbuf); + return (char *) from; + } else { + return cvtbuf; + } +} + +/******************************************************************* + kanji/kana -> ":xx" - CAP format. +********************************************************************/ +static char *sj_to_cap(char *from, BOOL overwrite) { unsigned char *sp, *dp; @@ -720,7 +960,7 @@ sj_to_cap (const char *from, BOOL overwrite) } *dp = '\0'; if (overwrite) { - strcpy ((char *) from, (char *) cvtbuf); + pstrcpy ((char *) from, (char *) cvtbuf); return (char *) from; } else { return cvtbuf; @@ -730,11 +970,10 @@ sj_to_cap (const char *from, BOOL overwrite) /******************************************************************* sj to sj ********************************************************************/ -static char * -sj_to_sj (const char *from, BOOL overwrite) +static char *sj_to_sj(char *from, BOOL overwrite) { if (!overwrite) { - strcpy (cvtbuf, (char *) from); + pstrcpy (cvtbuf, (char *) from); return cvtbuf; } else { return (char *) from; @@ -746,18 +985,17 @@ sj_to_sj (const char *from, BOOL overwrite) _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) +static void setup_string_function(int codes) { switch (codes) { default: + _dos_to_unix = dos2unix_format; + _unix_to_dos = unix2dos_format; + break; + case SJIS_CODE: _dos_to_unix = sj_to_sj; _unix_to_dos = sj_to_sj; - break; case EUC_CODE: @@ -787,19 +1025,18 @@ setup_string_function (int codes) case CAP_CODE: _dos_to_unix = sj_to_cap; - _unix_to_dos = hex_to_sj; + _unix_to_dos = cap_to_sj; break; } - return codes; } -/* - * Interpret coding system. - */ -int -interpret_coding_system (char *str, int def) +/************************************************************************ + Interpret coding system. +************************************************************************/ + +void interpret_coding_system(char *str) { - int codes = def; + int codes = UNKNOWN_CODE; if (strequal (str, "sjis")) { codes = SJIS_CODE; @@ -811,7 +1048,7 @@ interpret_coding_system (char *str, int def) } else if (strequal (str, "hex")) { codes = HEX_CODE; hex_tag = HEXTAG; - } else if (strncasecmp (str, "hex", 3)) { + } else if (!strncasecmp (str, "hex", 3)) { codes = HEX_CODE; hex_tag = (str[3] ? str[3] : HEXTAG); } else if (strequal (str, "j8bb")) { @@ -887,9 +1124,82 @@ interpret_coding_system (char *str, int def) jis_kso = '@'; jis_ksi = 'H'; } - return setup_string_function (codes); + setup_string_function (codes); +} + +/******************************************************************* + Non multibyte char function. +*******************************************************************/ + +static int skip_non_multibyte_char(char c) +{ + return 0; +} + +/******************************************************************* + Function that always says a character isn't multibyte. +*******************************************************************/ + +static BOOL not_multibyte_char_1(char c) +{ + return False; +} + +/******************************************************************* + Setup the function pointers for the functions that are replaced + when multi-byte codepages are used. + + The dos_to_unix and unix_to_dos function pointers are only + replaced by setup_string_function called by interpret_coding_system + above. +*******************************************************************/ + +void initialize_multibyte_vectors( int client_codepage) +{ + switch( client_codepage ) + { + case KANJI_CODEPAGE: + multibyte_strchr = (char *(*)(char *, int )) sj_strchr; + multibyte_strrchr = (char *(*)(char *, int )) sj_strrchr; + multibyte_strstr = (char *(*)(char *, char *)) sj_strstr; + multibyte_strtok = (char *(*)(char *, char *)) sj_strtok; + _skip_multibyte_char = skip_kanji_multibyte_char; + is_multibyte_char_1 = is_kanji_multibyte_char_1; + break; + case HANGUL_CODEPAGE: + multibyte_strchr = (char *(*)(char *, int )) generic_multibyte_strchr; + multibyte_strrchr = (char *(*)(char *, int )) generic_multibyte_strrchr; + multibyte_strstr = (char *(*)(char *, char *)) generic_multibyte_strstr; + multibyte_strtok = (char *(*)(char *, char *)) generic_multibyte_strtok; + _skip_multibyte_char = skip_generic_multibyte_char; + is_multibyte_char_1 = hangul_is_multibyte_char_1; + break; + case BIG5_CODEPAGE: + multibyte_strchr = (char *(*)(char *, int )) generic_multibyte_strchr; + multibyte_strrchr = (char *(*)(char *, int )) generic_multibyte_strrchr; + multibyte_strstr = (char *(*)(char *, char *)) generic_multibyte_strstr; + multibyte_strtok = (char *(*)(char *, char *)) generic_multibyte_strtok; + _skip_multibyte_char = skip_generic_multibyte_char; + is_multibyte_char_1 = big5_is_multibyte_char_1; + break; + case SIMPLIFIED_CHINESE_CODEPAGE: + multibyte_strchr = (char *(*)(char *, int )) generic_multibyte_strchr; + multibyte_strrchr = (char *(*)(char *, int )) generic_multibyte_strrchr; + multibyte_strstr = (char *(*)(char *, char *)) generic_multibyte_strstr; + multibyte_strtok = (char *(*)(char *, char *)) generic_multibyte_strtok; + _skip_multibyte_char = skip_generic_multibyte_char; + is_multibyte_char_1 = simpch_is_multibyte_char_1; + break; + /* + * Single char size code page. + */ + default: + multibyte_strchr = (char *(*)(char *, int )) strchr; + multibyte_strrchr = (char *(*)(char *, int )) strrchr; + multibyte_strstr = (char *(*)(char *, char *)) strstr; + multibyte_strtok = (char *(*)(char *, char *)) strtok; + _skip_multibyte_char = skip_non_multibyte_char; + is_multibyte_char_1 = not_multibyte_char_1; + break; + } } -#else -int kanji_dummy_procedure(void) -{return 0;} -#endif /* KANJI */ diff --git a/source/lib/md4.c b/source/lib/md4.c index 485e231a784..30f2b6b8c6b 100644 --- a/source/lib/md4.c +++ b/source/lib/md4.c @@ -1,299 +1,170 @@ -#ifdef SMB_PASSWD -/* - This code is from rfc1186. +/* + Unix SMB/Netbios implementation. + Version 1.9. + a implementation of MD4 designed for use in the SMB authentication protocol + Copyright (C) Andrew Tridgell 1997-1998. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - /* - ** ******************************************************************** - ** md4.c -- Implementation of MD4 Message Digest Algorithm ** - ** Updated: 2/16/90 by Ronald L. Rivest ** - ** (C) 1990 RSA Data Security, Inc. ** - ** ******************************************************************** - */ +#include "includes.h" - /* - ** To use MD4: - ** -- Include md4.h in your program - ** -- Declare an MDstruct MD to hold the state of the digest - ** computation. - ** -- Initialize MD using MDbegin(&MD) - ** -- For each full block (64 bytes) X you wish to process, call - ** MDupdate(&MD,X,512) - ** (512 is the number of bits in a full block.) - ** -- For the last block (less than 64 bytes) you wish to process, - ** MDupdate(&MD,X,n) - ** where n is the number of bits in the partial block. A partial - ** block terminates the computation, so every MD computation - ** should terminate by processing a partial block, even if it - ** has n = 0. - ** -- The message digest is available in MD.buffer[0] ... - ** MD.buffer[3]. (Least-significant byte of each word - ** should be output first.) - ** -- You can print out the digest using MDprint(&MD) - */ +/* NOTE: This code makes no attempt to be fast! - /* Implementation notes: - ** This implementation assumes that ints are 32-bit quantities. - ** If the machine stores the least-significant byte of an int in the - ** least-addressed byte (e.g., VAX and 8086), then LOWBYTEFIRST - ** should be set to TRUE. Otherwise (e.g., SUNS), LOWBYTEFIRST - ** should be set to FALSE. Note that on machines with LOWBYTEFIRST - ** FALSE the routine MDupdate modifies has a side-effect on its input - ** array (the order of bytes in each word are reversed). If this is - ** undesired a call to MDreverse(X) can reverse the bytes of X back - ** into order after each call to MDupdate. - */ - -#define TRUE 1 -#define FALSE 0 - - /* Compile-time includes - */ - -#include <stdio.h> -#include "md4.h" - -#define uchar unsigned char -#define int16 unsigned short -#define uint32 unsigned int - -#include "byteorder.h" - - /* Compile-time declarations of MD4 "magic constants". - */ -#define I0 0x67452301 /* Initial values for MD buffer */ -#define I1 0xefcdab89 -#define I2 0x98badcfe -#define I3 0x10325476 -#define C2 013240474631 /* round 2 constant = sqrt(2) in octal */ -#define C3 015666365641 /* round 3 constant = sqrt(3) in octal */ - /* C2 and C3 are from Knuth, The Art of Programming, Volume 2 - ** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley. - ** Table 2, page 660. - */ - -#define fs1 3 /* round 1 shift amounts */ -#define fs2 7 -#define fs3 11 -#define fs4 19 -#define gs1 3 /* round 2 shift amounts */ -#define gs2 5 -#define gs3 9 -#define gs4 13 -#define hs1 3 /* round 3 shift amounts */ -#define hs2 9 -#define hs3 11 -#define hs4 15 - - /* Compile-time macro declarations for MD4. - ** Note: The "rot" operator uses the variable "tmp". - ** It assumes tmp is declared as unsigned int, so that the >> - ** operator will shift in zeros rather than extending the sign bit. - */ -#define f(X,Y,Z) ((X&Y) | ((~X)&Z)) -#define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z)) -#define h(X,Y,Z) (X^Y^Z) -#define rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S))) -#define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s) -#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s) -#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s) + It assumes that a int is at least 32 bits long +*/ - /* MDprint(MDp) - ** Print message digest buffer MDp as 32 hexadecimal digits. - ** Order is from low-order byte of buffer[0] to high-order byte of - ** buffer[3]. - ** Each byte is printed with high-order hexadecimal digit first. - ** This is a user-callable routine. - */ - void - MDprint(MDp) - MDptr MDp; - { int i,j; - for (i=0;i<4;i++) - for (j=0;j<32;j=j+8) - printf("%02x",(MDp->buffer[i]>>j) & 0xFF); - } +static uint32 A, B, C, D; + +static uint32 F(uint32 X, uint32 Y, uint32 Z) +{ + return (X&Y) | ((~X)&Z); +} + +static uint32 G(uint32 X, uint32 Y, uint32 Z) +{ + return (X&Y) | (X&Z) | (Y&Z); +} + +static uint32 H(uint32 X, uint32 Y, uint32 Z) +{ + return X^Y^Z; +} + +static uint32 lshift(uint32 x, int s) +{ + x &= 0xFFFFFFFF; + return ((x<<s)&0xFFFFFFFF) | (x>>(32-s)); +} + +#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s) +#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + (uint32)0x5A827999,s) +#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + (uint32)0x6ED9EBA1,s) + +/* this applies md4 to 64 byte chunks */ +static void mdfour64(uint32 *M) +{ + int j; + uint32 AA, BB, CC, DD; + uint32 X[16]; + + for (j=0;j<16;j++) + X[j] = M[j]; + + AA = A; BB = B; CC = C; DD = D; + + ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7); + ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19); + ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7); + ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19); + ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7); + ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19); + ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7); + ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19); + + ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5); + ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13); + ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5); + ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13); + ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5); + ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13); + ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5); + ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13); + + ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9); + ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15); + ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9); + ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15); + ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9); + ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15); + ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9); + ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15); + + A += AA; B += BB; C += CC; D += DD; + + A &= 0xFFFFFFFF; B &= 0xFFFFFFFF; + C &= 0xFFFFFFFF; D &= 0xFFFFFFFF; + + for (j=0;j<16;j++) + X[j] = 0; +} + +static void copy64(uint32 *M, unsigned char *in) +{ + int i; + + for (i=0;i<16;i++) + M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) | + (in[i*4+1]<<8) | (in[i*4+0]<<0); +} + +static void copy4(unsigned char *out,uint32 x) +{ + out[0] = x&0xFF; + out[1] = (x>>8)&0xFF; + out[2] = (x>>16)&0xFF; + out[3] = (x>>24)&0xFF; +} + +/* produce a md4 message digest from data of length n bytes */ +void mdfour(unsigned char *out, unsigned char *in, int n) +{ + unsigned char buf[128]; + uint32 M[16]; + uint32 b = n * 8; + int i; + + A = 0x67452301; + B = 0xefcdab89; + C = 0x98badcfe; + D = 0x10325476; + + while (n > 64) { + copy64(M, in); + mdfour64(M); + in += 64; + n -= 64; + } - /* MDbegin(MDp) - ** Initialize message digest buffer MDp. - ** This is a user-callable routine. - */ - void - MDbegin(MDp) - MDptr MDp; - { int i; - MDp->buffer[0] = I0; - MDp->buffer[1] = I1; - MDp->buffer[2] = I2; - MDp->buffer[3] = I3; - for (i=0;i<8;i++) MDp->count[i] = 0; - MDp->done = 0; - } + for (i=0;i<128;i++) + buf[i] = 0; + memcpy(buf, in, n); + buf[n] = 0x80; + + if (n <= 55) { + copy4(buf+56, b); + copy64(M, buf); + mdfour64(M); + } else { + copy4(buf+120, b); + copy64(M, buf); + mdfour64(M); + copy64(M, buf+64); + mdfour64(M); + } - /* MDreverse(X) - ** Reverse the byte-ordering of every int in X. - ** Assumes X is an array of 16 ints. - ** The macro revx reverses the byte-ordering of the next word of X. - */ - void MDreverse(X) - unsigned int *X; - { register unsigned int t; - register unsigned int i; + for (i=0;i<128;i++) + buf[i] = 0; + copy64(M, buf); - for(i = 0; i < 16; i++) { - t = X[i]; - SIVAL(X,i*4,t); - } - } + copy4(out, A); + copy4(out+4, B); + copy4(out+8, C); + copy4(out+12, D); - /* MDblock(MDp,X) - ** Update message digest buffer MDp->buffer using 16-word data block X. - ** Assumes all 16 words of X are full of data. - ** Does not update MDp->count. - ** This routine is not user-callable. - */ - static void - MDblock(MDp,X) - MDptr MDp; - unsigned int *X; - { - register unsigned int tmp, A, B, C, D; - MDreverse(X); - A = MDp->buffer[0]; - B = MDp->buffer[1]; - C = MDp->buffer[2]; - D = MDp->buffer[3]; - /* Update the message digest buffer */ - ff(A , B , C , D , 0 , fs1); /* Round 1 */ - ff(D , A , B , C , 1 , fs2); - ff(C , D , A , B , 2 , fs3); - ff(B , C , D , A , 3 , fs4); - ff(A , B , C , D , 4 , fs1); - ff(D , A , B , C , 5 , fs2); - ff(C , D , A , B , 6 , fs3); - ff(B , C , D , A , 7 , fs4); - ff(A , B , C , D , 8 , fs1); - ff(D , A , B , C , 9 , fs2); - ff(C , D , A , B , 10 , fs3); - ff(B , C , D , A , 11 , fs4); - ff(A , B , C , D , 12 , fs1); - ff(D , A , B , C , 13 , fs2); - ff(C , D , A , B , 14 , fs3); - ff(B , C , D , A , 15 , fs4); - gg(A , B , C , D , 0 , gs1); /* Round 2 */ - gg(D , A , B , C , 4 , gs2); - gg(C , D , A , B , 8 , gs3); - gg(B , C , D , A , 12 , gs4); - gg(A , B , C , D , 1 , gs1); - gg(D , A , B , C , 5 , gs2); - gg(C , D , A , B , 9 , gs3); - gg(B , C , D , A , 13 , gs4); - gg(A , B , C , D , 2 , gs1); - gg(D , A , B , C , 6 , gs2); - gg(C , D , A , B , 10 , gs3); - gg(B , C , D , A , 14 , gs4); - gg(A , B , C , D , 3 , gs1); - gg(D , A , B , C , 7 , gs2); - gg(C , D , A , B , 11 , gs3); - gg(B , C , D , A , 15 , gs4); - hh(A , B , C , D , 0 , hs1); /* Round 3 */ - hh(D , A , B , C , 8 , hs2); - hh(C , D , A , B , 4 , hs3); - hh(B , C , D , A , 12 , hs4); - hh(A , B , C , D , 2 , hs1); - hh(D , A , B , C , 10 , hs2); - hh(C , D , A , B , 6 , hs3); - hh(B , C , D , A , 14 , hs4); - hh(A , B , C , D , 1 , hs1); - hh(D , A , B , C , 9 , hs2); - hh(C , D , A , B , 5 , hs3); - hh(B , C , D , A , 13 , hs4); - hh(A , B , C , D , 3 , hs1); - hh(D , A , B , C , 11 , hs2); - hh(C , D , A , B , 7 , hs3); - hh(B , C , D , A , 15 , hs4); - MDp->buffer[0] += A; - MDp->buffer[1] += B; - MDp->buffer[2] += C; - MDp->buffer[3] += D; - } + A = B = C = D = 0; +} - /* MDupdate(MDp,X,count) - ** Input: MDp -- an MDptr - ** X -- a pointer to an array of unsigned characters. - ** count -- the number of bits of X to use. - ** (if not a multiple of 8, uses high bits of last byte.) - ** Update MDp using the number of bits of X given by count. - ** This is the basic input routine for an MD4 user. - ** The routine completes the MD computation when count < 512, so - ** every MD computation should end with one call to MDupdate with a - ** count less than 512. A call with count 0 will be ignored if the - ** MD has already been terminated (done != 0), so an extra call with - ** count 0 can be given as a "courtesy close" to force termination - ** if desired. - */ - void - MDupdate(MDp,X,count) - MDptr MDp; - unsigned char *X; - unsigned int count; - { unsigned int i, tmp, bit, byte, mask; - unsigned char XX[64]; - unsigned char *p; - /* return with no error if this is a courtesy close with count - ** zero and MDp->done is true. - */ - if (count == 0 && MDp->done) return; - /* check to see if MD is already done and report error */ - if (MDp->done) - { printf("\nError: MDupdate MD already done."); return; } - /* Add count to MDp->count */ - tmp = count; - p = MDp->count; - while (tmp) - { tmp += *p; - *p++ = tmp; - tmp = tmp >> 8; - } - /* Process data */ - if (count == 512) - { /* Full block of data to handle */ - MDblock(MDp,(unsigned int *)X); - } - else if (count > 512) /* Check for count too large */ - { printf("\nError: MDupdate called with illegal count value %d." - ,count); - return; - } - else /* partial block -- must be last block so finish up */ - { /* Find out how many bytes and residual bits there are */ - byte = count >> 3; - bit = count & 7; - /* Copy X into XX since we need to modify it */ - for (i=0;i<=byte;i++) XX[i] = X[i]; - for (i=byte+1;i<64;i++) XX[i] = 0; - /* Add padding '1' bit and low-order zeros in last byte */ - mask = 1 << (7 - bit); - XX[byte] = (XX[byte] | mask) & ~( mask - 1); - /* If room for bit count, finish up with this block */ - if (byte <= 55) - { for (i=0;i<8;i++) XX[56+i] = MDp->count[i]; - MDblock(MDp,(unsigned int *)XX); - } - else /* need to do two blocks to finish up */ - { MDblock(MDp,(unsigned int *)XX); - for (i=0;i<56;i++) XX[i] = 0; - for (i=0;i<8;i++) XX[56+i] = MDp->count[i]; - MDblock(MDp,(unsigned int *)XX); - } - /* Set flag saying we're done with MD computation */ - MDp->done = 1; - } - } - /* - ** End of md4.c - */ -#else -void md4_dummy() {;} -#endif diff --git a/source/lib/membuffer.c b/source/lib/membuffer.c new file mode 100644 index 00000000000..85f63e8c065 --- /dev/null +++ b/source/lib/membuffer.c @@ -0,0 +1,358 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Samba memory buffer functions + Copyright (C) Andrew Tridgell 1992-1997 + Copyright (C) Luke Kenneth Casson Leighton 1996-1997 + + 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. +*/ + +/******************************************************************* + * + * Description: memory buffer / stream management. + * Author : Luke K C Leighton + * Created : Dec 1997 + * + + * this module is intended for use in streaming data in and out of + * buffers. it is intended that a single data stream be subdivided + * into manageable sections. + + * for example, an rpc header contains a length field, but until the + * data has been created, the length is unknown. using this module, + * the header section can be tacked onto the front of the data memory + * list once the size of the data section preceding it is known. + + * the "margin" can be used to over-run and retrospectively lengthen + * the buffer. this is to save time in some of the loops, where it is + * not particularly desirable to realloc data by 1, 2 or 4 bytes + * repetitively... + + * each memory buffer contains a start and end offset. the end of + * one buffer should equal to the start of the next in the chain. + * (end - start = len, instead of end - start + 1 = len) + + * the debug log levels are very high in some of the routines: you + * have no idea how boring it gets staring at debug output from these + + ********************************************************************/ + + +#include "includes.h" + +extern int DEBUGLEVEL; + +/******************************************************************* + initialise a memory buffer. + ********************************************************************/ +void mem_init(struct mem_buf *buf, int margin) +{ + buf->dynamic = True; + buf->data = NULL; + buf->data_size = 0; + buf->data_used = 0; + + buf->margin = margin; + + buf->next = NULL; + + buf->offset.start = 0; + buf->offset.end = 0; +} + +/******************************************************************* + initialise a memory buffer. + + dynamic indicates memory has been dynamically allocated. + if mem_free is called, the memory will be freed. + ********************************************************************/ +void mem_create(struct mem_buf *buf, char *data, int size, int margin, BOOL dynamic) +{ + buf->dynamic = dynamic; + buf->data = data; + buf->data_size = size; + buf->data_used = size; + + buf->margin = margin; + + buf->next = NULL; + + buf->offset.start = 0; + buf->offset.end = size; +} + +/******************************************************************* + allocate a memory buffer. assume it's empty + ********************************************************************/ +BOOL mem_alloc_data(struct mem_buf *buf, int size) +{ + if (!buf->dynamic) + { + DEBUG(3,("mem_alloc_data: warning - memory buffer type is set to static\n")); + } + + buf->data_size = size + buf->margin; + buf->data_used = size; + + buf->data = malloc(buf->data_size); + + if (buf->data == NULL) + { + DEBUG(3,("mem_alloc: could not malloc size %d\n", + buf->data_size)); + mem_init(buf, buf->margin); + + return False; + } + + bzero(buf->data, buf->data_size); + + return True; +} + +/******************************************************************* + allocates a memory buffer structure + ********************************************************************/ +BOOL mem_buf_copy(char *copy_into, struct mem_buf *buf, + uint32 offset, uint32 len) +{ + uint32 end = offset + len; + char *q = NULL; + uint32 data_len = mem_buf_len(buf); + uint32 start_offset = offset; + struct mem_buf **bcp = &buf; + + if (buf == NULL || copy_into == NULL) return False; + + DEBUG(200,("mem_buf_copy: data[%d..%d] offset %d len %d\n", + buf->offset.start, data_len, offset, len)); + + /* there's probably an off-by-one bug, here, and i haven't even tested the code :-) */ + while (offset < end && ((q = mem_data(bcp, offset)) != NULL)) + { + uint32 copy_len = (*bcp)->offset.end - offset; + + DEBUG(200,("\tdata[%d..%d] - offset %d len %d\n", + (*bcp)->offset.start, (*bcp)->offset.end, + offset, copy_len)); + + memcpy(copy_into, q, copy_len); + + offset += copy_len; + copy_into += copy_len; + } + + if ((*bcp) != NULL) + { + DEBUG(200,("mem_buf_copy: copied %d bytes\n", offset - start_offset)); + } + else + { + DEBUG(200,("mem_buf_copy: failed\n")); + } + + return buf != NULL; +} + +/******************************************************************* + allocates a memory buffer structure + ********************************************************************/ +BOOL mem_buf_init(struct mem_buf **buf, uint32 margin) +{ + if (buf == NULL) return False; + + if ((*buf) == NULL) + { + (*buf) = malloc(sizeof(**buf)); + if ((*buf) != NULL) + { + mem_init((*buf), margin); + return True; + } + } + else + { + (*buf)->margin = margin; + return True; + } + return False; +} + +/******************************************************************* + frees up a memory buffer. + ********************************************************************/ +void mem_buf_free(struct mem_buf **buf) +{ + if (buf == NULL) return; + if ((*buf) == NULL) return; + + mem_free_data(*buf); /* delete memory data */ + free(*buf); /* delete item */ + (*buf) = NULL; +} + +/******************************************************************* + frees a memory buffer chain. assumes that all items are malloced. + ********************************************************************/ +static void mem_free_chain(struct mem_buf **buf) +{ + if (buf == NULL) return; + if ((*buf) == NULL) return; + + if ((*buf)->next != NULL) + { + mem_free_chain(&((*buf)->next)); /* delete all other items in chain */ + } + mem_buf_free(buf); +} + +/******************************************************************* + frees a memory buffer. + ********************************************************************/ +void mem_free_data(struct mem_buf *buf) +{ + if (buf == NULL) return; + + if (buf->data != NULL && buf->dynamic) + { + free(buf->data); /* delete data in this structure */ + } + mem_init(buf, buf->margin); +} + +/******************************************************************* + reallocate a memory buffer, including a safety margin + ********************************************************************/ +BOOL mem_realloc_data(struct mem_buf *buf, int new_size) +{ + char *new_data; + + if (!buf->dynamic) + { + DEBUG(3,("mem_realloc_data: memory buffer has not been dynamically allocated!\n")); + return False; + } + + if (new_size == 0) + { + mem_free_data(buf); + return True; + } + + new_data = Realloc(buf->data, new_size + buf->margin); + + if (new_data != NULL) + { + buf->data = new_data; + buf->data_size = new_size + buf->margin; + buf->data_used = new_size; + } + else if (buf->data_size <= new_size) + { + DEBUG(3,("mem_realloc: warning - could not realloc to %d(+%d)\n", + new_size, buf->margin)); + + buf->data_used = new_size; + } + else + { + DEBUG(3,("mem_realloc: error - could not realloc to %d\n", + new_size)); + + mem_free_data(buf); + return False; + } + + return True; +} + +/******************************************************************* + reallocate a memory buffer, retrospectively :-) + ********************************************************************/ +BOOL mem_grow_data(struct mem_buf **buf, BOOL io, int new_size, BOOL force_grow) +{ + if (new_size + (*buf)->margin >= (*buf)->data_size) + { + if (io && !force_grow) + { + DEBUG(3,("mem_grow_data: cannot resize when reading from a data stream\n")); + } + else + { + return mem_realloc_data((*buf), new_size); + } + } + return True; +} + +/******************************************************************* + search for a memory buffer that falls within the specified offset + ********************************************************************/ +static BOOL mem_find(struct mem_buf **buf, uint32 offset) +{ + struct mem_buf *f; + if (buf == NULL) return False; + + f = *buf; + + DEBUG(200,("mem_find: data[%d..%d] offset: %d\n", + f->offset.start, f->offset.end, offset)); + + while (f != NULL && offset >= f->offset.end) + { + f = f->next; + + DEBUG(200,("mem_find: next[%d..%d]\n", + f->offset.start, f->offset.end)); + } + + (*buf) = f; + + DEBUG(200,("mem_find: found data[%d..%d]\n", + (*buf)->offset.start,(*buf)->offset.end)); + + return f != NULL; +} + + +/******************************************************************* + add up the lengths of all sections. + ********************************************************************/ +uint32 mem_buf_len(struct mem_buf *buf) +{ + int len = 0; + while (buf != NULL) + { + len += buf->offset.end - buf->offset.start; + buf = buf->next; + } + return len; +} + + +/******************************************************************* + return the memory location specified by offset. may return NULL. + ********************************************************************/ +char *mem_data(struct mem_buf **buf, uint32 offset) +{ + if (mem_find(buf, offset)) + { + return &((*buf)->data[offset - (*buf)->offset.start]); + } + return NULL; +} + + diff --git a/source/lib/netatalk.c b/source/lib/netatalk.c new file mode 100644 index 00000000000..ae0a57154e1 --- /dev/null +++ b/source/lib/netatalk.c @@ -0,0 +1,159 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Copyright (C) Andrew Tridgell 1992-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + netatalk.c : routines for improving interaction between Samba and netatalk. + Copyright (C) John D. Blair <jdblair@cobaltnet.com> 1998 + Cobalt Networks, Inc. +*/ + +#include "includes.h" + +#ifdef WITH_NETATALK + +extern int DEBUGLEVEL; + +/***************** + ntalk_resourcepath: creates the path to the netatalk resource fork for + a given file + + fname: normal filename + doublename: buffer that will contain the location of the resource fork + length: length of this buffer (to prevent overflows) + + NOTE: doesn't currently gracefully deal with buffer overflows- it just + doesn't allow them to occur. +******************/ +void ntalk_resourcepath(const char *fname, char *doublename, const int length) +{ + int i; + int charnum; + int lastslash; + char appledouble[] = APPLEDOUBLE; + + /* copy fname to doublename and find last slash */ + for (i = 0; (fname[i] != 0) && (i <= length); i++) { + if (fname[i] == '/') { + lastslash = i; + } + doublename[i] = fname[i]; + } + lastslash++; /* location just after last slash */ + + /* insert .AppleDouble */ + charnum = lastslash; + for (i = 0; (appledouble[i] != 0) && (i <= length); i++) { + doublename[charnum] = appledouble[i]; + charnum++; + } + + /* append last part of file name */ + for (i = lastslash; (fname[i] != 0) && (i <= length); i++) { + doublename[charnum] = fname[i]; + charnum++; + } + + doublename[charnum] = 0; +} + +/********************** + ntalk_mkresdir: creates a new .AppleDouble directory (if necessary) + for the resource fork of a specified file +**********************/ +int ntalk_mkresdir(const char *fname) +{ + char fdir[255]; + int i; + int lastslash; + SMB_STRUCT_STAT dirstats; + char appledouble[] = APPLEDOUBLE; + + /* find directory containing fname */ + for (i = 0; (fname[i] != 0) && (i <= 254); i++) { + fdir[i] = fname[i]; + if (fdir[i] == '/') { + lastslash = i; + } + } + lastslash++; + fdir[lastslash] = 0; + sys_lstat(fdir, &dirstats); + + /* append .AppleDouble */ + for (i = 0; (appledouble[i] != 0) && (lastslash <= 254); i++) { + fdir[lastslash] = appledouble[i]; + lastslash++; + } + fdir[lastslash] = 0; + + /* create this directory */ + /* silently ignore EEXIST error */ + if ((mkdir(fdir, dirstats.st_mode) < 0) && (errno != EEXIST)) { + return errno; + } + + /* set ownership of this dir to the same as its parent */ + /* holy race condition, batman! */ + /* warning: this doesn't check for errors */ + chown(fdir, dirstats.st_uid, dirstats.st_gid); + + printf("%s\n", fdir); + + return 1; +} + +/********************** + ntalk_unlink: unlink a file and its resource fork +**********************/ +int ntalk_unlink(const char *fname) +{ + char buf[255]; + + ntalk_resourcepath(fname, buf, 255); + unlink(buf); + return unlink(fname); +} + +/********************** + ntalk_chown: chown a file and its resource fork +**********************/ +int ntalk_chown(const char *fname, const uid_t uid, const gid_t gid) +{ + char buf[255]; + + ntalk_resourcepath(fname, buf, 255); + chown(buf, uid, gid); + return chown(fname, uid, gid); +} + +/********************** + ntalk_chmod: chmod a file and its resource fork +**********************/ +int ntalk_chmod(const char *fname, mode_t perms) +{ + char buf[255]; + + ntalk_resourcepath(fname, buf, 255); + chmod(buf, perms); + return chmod(fname, perms); +} + + +#endif /* WITH_NETATALK */ diff --git a/source/lib/netmask.c b/source/lib/netmask.c new file mode 100644 index 00000000000..d9bc06c47a9 --- /dev/null +++ b/source/lib/netmask.c @@ -0,0 +1,353 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + code to query kernel netmask + Copyright (C) Andrew Tridgell 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +/* working out the netmask for an interface is an incredibly non-portable + thing. We have several possible implementations below, and autoconf + tries each of them to see what works + + Note that this file does _not_ include includes.h. That is so this code + can be called directly from the autoconf tests. That also means + this code cannot use any of the normal Samba debug stuff or defines. + This is standalone code. + +*/ + +#ifndef AUTOCONF +#include "config.h" +#endif + +#ifdef HAVE_NETMASK_IFCONF + +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <sys/ioctl.h> +#include <net/if.h> + +#ifndef SIOCGIFCONF +#include <sys/sockio.h> +#endif + + +/**************************************************************************** + get the netmask address for a local interface +****************************************************************************/ +int get_netmask(struct in_addr *ipaddr, struct in_addr *nmask) +{ + struct ifconf ifc; + char buff[2048]; + int fd, i, n; + struct ifreq *ifr=NULL; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { +#ifdef DEBUG + fprintf(stderr,"socket failed\n"); +#endif + return -1; + } + + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { +#ifdef DEBUG + fprintf(stderr,"SIOCGIFCONF failed\n"); +#endif + close(fd); + return -1; + } + + ifr = ifc.ifc_req; + + n = ifc.ifc_len / sizeof(struct ifreq); + +#ifdef DEBUG + fprintf(stderr,"%d interfaces - looking for %s\n", + n, inet_ntoa(*ipaddr)); +#endif + + /* Loop through interfaces, looking for given IP address */ + for (i=n-1;i>=0;i--) { + if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) { +#ifdef DEBUG + fprintf(stderr,"SIOCGIFADDR failed\n"); +#endif + continue; + } + +#ifdef DEBUG + fprintf(stderr,"interface %s\n", + inet_ntoa((*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr)); +#endif + if (ipaddr->s_addr != + (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr.s_addr) { + continue; + } + + if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) { +#ifdef DEBUG + fprintf(stderr,"SIOCGIFNETMASK failed\n"); +#endif + close(fd); + return -1; + } + close(fd); + (*nmask) = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr; +#ifdef DEBUG + fprintf(stderr,"netmask %s\n", inet_ntoa(*nmask)); +#endif + return 0; + } + +#ifdef DEBUG + fprintf(stderr,"interface not found\n"); +#endif + + close(fd); + return -1; +} + +#elif defined(HAVE_NETMASK_IFREQ) + +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <sys/ioctl.h> +#include <net/if.h> + +#ifndef SIOCGIFCONF +#include <sys/sockio.h> +#endif + +#ifndef I_STR +#include <sys/stropts.h> +#endif + + +/**************************************************************************** +this should cover most of the rest of systems +****************************************************************************/ + int get_netmask(struct in_addr *ipaddr, struct in_addr *nmask) +{ + struct ifreq ifreq; + struct strioctl strioctl; + struct ifconf *ifc; + char buff[2048]; + int fd, i, n; + struct ifreq *ifr=NULL; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { +#ifdef DEBUG + fprintf(stderr,"socket failed\n"); +#endif + return -1; + } + + 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(fd, I_STR, &strioctl) < 0) { +#ifdef DEBUG + fprintf(stderr,"SIOCGIFCONF failed\n"); +#endif + close(fd); + return -1; + } + + ifr = (struct ifreq *)ifc->ifc_req; + + /* Loop through interfaces, looking for given IP address */ + n = ifc->ifc_len / sizeof(struct ifreq); + + for (i = 0; i<n; i++, ifr++) { +#ifdef DEBUG + fprintf(stderr,"interface %s\n", + inet_ntoa((*(struct sockaddr_in *)&ifr->ifr_addr).sin_addr.s_addr)); +#endif + if (ipaddr->s_addr == + (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) { + break; + } + } + +#ifdef DEBUG + if (i == n) { + fprintf(stderr,"interface not found\n"); + close(fd); + return -1; + } +#endif + + ifreq = *ifr; + + strioctl.ic_cmd = SIOCGIFNETMASK; + strioctl.ic_dp = (char *)&ifreq; + strioctl.ic_len = sizeof(struct ifreq); + if (ioctl(fd, I_STR, &strioctl) != 0) { +#ifdef DEBUG + fprintf(stderr,"Failed SIOCGIFNETMASK\n"); +#endif + close(fd); + return -1; + } + + close(fd); + *nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr; +#ifdef DEBUG + fprintf(stderr,"netmask %s\n", inet_ntoa(*nmask)); +#endif + return 0; +} + +#elif defined(HAVE_NETMASK_AIX) + +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <sys/ioctl.h> +#include <net/if.h> + +#ifndef SIOCGIFCONF +#include <sys/sockio.h> +#endif + +/**************************************************************************** +this one is for AIX +****************************************************************************/ + int get_netmask(struct in_addr *ipaddr, struct in_addr *nmask) +{ + char buff[2048]; + int fd, i, n; + struct ifconf ifc; + struct ifreq *ifr=NULL; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { +#ifdef DEBUG + fprintf(stderr,"socket failed\n"); +#endif + return -1; + } + + + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + + if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { +#ifdef DEBUG + fprintf(stderr,"SIOCGIFCONF failed\n"); +#endif + close(fd); + return -1; + } + + ifr = ifc.ifc_req; + /* Loop through interfaces, looking for given IP address */ + i = ifc.ifc_len; + while (i > 0) { +#ifdef DEBUG + fprintf(stderr,"interface %s\n", + inet_ntoa((*(struct sockaddr_in *)&ifr->ifr_addr).sin_addr)); +#endif + if (ipaddr->s_addr == + (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) { + break; + } + i -= ifr->ifr_addr.sa_len + IFNAMSIZ; + ifr = (struct ifreq*) ((char*) ifr + ifr->ifr_addr.sa_len + + IFNAMSIZ); + } + + +#ifdef DEBUG + if (i <= 0) { + fprintf(stderr,"interface not found\n"); + close(fd); + return -1; + } +#endif + + if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) { +#ifdef DEBUG + fprintf(stderr,"SIOCGIFNETMASK failed\n"); +#endif + close(fd); + return -1; + } + + close(fd); + + (*nmask) = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; +#ifdef DEBUG + fprintf(stderr,"netmask %s\n", inet_ntoa(*nmask)); +#endif + return 0; +} + +#else /* a dummy version */ +struct in_addr; /* it may not have been declared before */ + int get_netmask(struct in_addr *ipaddr, struct in_addr *nmask) +{ + return -1; +} +#endif + + +#ifdef AUTOCONF +/* this is the autoconf driver to test get_netmask() */ + + main() +{ + char buf[1024]; + struct hostent *hp; + struct in_addr ip, nmask; + + if (gethostname(buf, sizeof(buf)-1) != 0) { + fprintf(stderr,"gethostname failed\n"); + exit(1); + } + + hp = gethostbyname(buf); + + if (!hp) { + fprintf(stderr,"gethostbyname failed\n"); + exit(1); + } + + memcpy((char *)&ip, (char *)hp->h_addr, hp->h_length); + + if (get_netmask(&ip, &nmask) == 0) exit(0); + + fprintf(stderr,"get_netmask failed\n"); + exit(1); +} +#endif diff --git a/source/lib/pidfile.c b/source/lib/pidfile.c new file mode 100644 index 00000000000..7e98438dba7 --- /dev/null +++ b/source/lib/pidfile.c @@ -0,0 +1,95 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + pidfile handling + Copyright (C) Andrew Tridgell 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + + +extern int DEBUGLEVEL; + +#ifndef O_NONBLOCK +#define O_NONBLOCK +#endif + +/* return the pid in a pidfile. return 0 if the process (or pidfile) + does not exist */ +pid_t pidfile_pid(char *name) +{ + FILE *f; + unsigned ret; + pstring pidFile; + + slprintf(pidFile, sizeof(pidFile)-1, "%s/%s.pid", lp_lockdir(), name); + + f = fopen(pidFile, "r"); + if (!f) { + return 0; + } + + if (fscanf(f,"%u", &ret) != 1) { + fclose(f); + return 0; + } + fclose(f); + + if (!process_exists(ret)) return 0; + + return (pid_t)ret; +} + +/* create a pid file in the lock directory. open it and leave it locked */ +void pidfile_create(char *name) +{ + int fd; + char buf[20]; + pstring pidFile; + int pid; + + slprintf(pidFile, sizeof(pidFile)-1, "%s/%s.pid", lp_lockdir(), name); + + pid = pidfile_pid(name); + if (pid > 0 && process_exists(pid)) { + DEBUG(0,("ERROR: %s is already running. File %s exists and process id %d is running.\n", + name, pidFile, pid)); + exit(1); + } + + fd = open(pidFile, O_NONBLOCK | O_CREAT | O_WRONLY, 0644); + if (fd < 0) { + DEBUG(0,("ERROR: can't open %s: Error was %s\n", pidFile, + strerror(errno))); + exit(1); + } + + if (fcntl_lock(fd,SMB_F_SETLK,0,1,F_WRLCK)==False) { + DEBUG(0,("ERROR: %s : fcntl lock of file %s failed. Error was %s\n", + name, pidFile, strerror(errno))); + exit(1); + } + + memset(buf, 0, sizeof(buf)); + slprintf(buf, sizeof(buf) - 1, "%u\n", (unsigned int) getpid()); + if (write(fd, buf, sizeof(buf)) != sizeof(buf)) { + DEBUG(0,("ERROR: can't write to file %s: %s\n", + pidFile, strerror(errno))); + exit(1); + } + /* Leave pid file open & locked for the duration... */ +} diff --git a/source/lib/replace.c b/source/lib/replace.c new file mode 100644 index 00000000000..6441efe44c7 --- /dev/null +++ b/source/lib/replace.c @@ -0,0 +1,295 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + replacement routines for broken systems + Copyright (C) Andrew Tridgell 1992-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +extern int DEBUGLEVEL; + + + void replace_dummy(void) +{} + + +#ifndef HAVE_FTRUNCATE + /******************************************************************* +ftruncate for operating systems that don't have it +********************************************************************/ + int ftruncate(int f,SMB_OFF_T l) +{ + struct flock fl; + + fl.l_whence = 0; + fl.l_len = 0; + fl.l_start = l; + fl.l_type = F_WRLCK; + return fcntl(f, F_FREESP, &fl); +} +#endif + + +#ifndef HAVE_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; + } + + return(epoch); +} +#endif /* !HAVE_MKTIME */ + + + +#ifndef HAVE_RENAME +/* Rename a file. (from libiberty in GNU binutils) */ + int rename(const char *zfrom, const char *zto) +{ + if (link (zfrom, zto) < 0) + { + if (errno != EEXIST) + return -1; + if (unlink (zto) < 0 + || link (zfrom, zto) < 0) + return -1; + } + return unlink (zfrom); +} +#endif + + +#ifndef HAVE_INNETGR +/* + * Search for a match in a netgroup. This replaces it on broken systems. + */ + int innetgr(char *group,char *host,char *user,char *dom) +{ + char *hst, *usr, *dm; + + setnetgrent(group); + while (getnetgrent(&hst, &usr, &dm)) { + if (((host == 0) || (hst == 0) || !strcmp(host, hst)) && + ((user == 0) || (usr == 0) || !strcmp(user, usr)) && + ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) { + endnetgrent(); + return (1); + } + } + endnetgrent(); + return (0); +} +#endif + + + +#ifndef HAVE_INITGROUPS +/**************************************************************************** + some systems don't have an initgroups call +****************************************************************************/ + int initgroups(char *name,gid_t id) +{ +#ifndef HAVE_SETGROUPS + static int done; + if (!done) { + DEBUG(1,("WARNING: running without setgroups\n")); + done=1; + } + /* yikes! no SETGROUPS or INITGROUPS? how can this work? */ + return(0); +#else + 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 (defined(SecureWare) && defined(SCO)) +/* This is needed due to needing the nap() function but we don't want + to include the Xenix libraries since that will break other things... + BTW: system call # 0x0c28 is the same as calling nap() */ + long nap(long milliseconds) { + return syscall(0x0c28, milliseconds); + } +#endif + + +#ifndef HAVE_MEMMOVE +/******************************************************************* +safely copies memory, ensuring no overlap problems. +this is only used if the machine does not have it's own memmove(). +this is not the fastest algorithm in town, but it will do for our +needs. +********************************************************************/ + void *memmove(void *dest,const void *src,int size) +{ + unsigned long d,s; + int i; + if (dest==src || !size) return(dest); + + d = (unsigned long)dest; + s = (unsigned long)src; + + if ((d >= (s+size)) || (s >= (d+size))) { + /* no overlap */ + memcpy(dest,src,size); + return(dest); + } + + if (d < s) { + /* we can forward copy */ + if (s-d >= sizeof(int) && + !(s%sizeof(int)) && + !(d%sizeof(int)) && + !(size%sizeof(int))) { + /* do it all as words */ + int *idest = (int *)dest; + int *isrc = (int *)src; + size /= sizeof(int); + for (i=0;i<size;i++) idest[i] = isrc[i]; + } else { + /* simplest */ + char *cdest = (char *)dest; + char *csrc = (char *)src; + for (i=0;i<size;i++) cdest[i] = csrc[i]; + } + } else { + /* must backward copy */ + if (d-s >= sizeof(int) && + !(s%sizeof(int)) && + !(d%sizeof(int)) && + !(size%sizeof(int))) { + /* do it all as words */ + int *idest = (int *)dest; + int *isrc = (int *)src; + size /= sizeof(int); + for (i=size-1;i>=0;i--) idest[i] = isrc[i]; + } else { + /* simplest */ + char *cdest = (char *)dest; + char *csrc = (char *)src; + for (i=size-1;i>=0;i--) cdest[i] = csrc[i]; + } + } + return(dest); +} +#endif + +#ifndef HAVE_STRDUP +/**************************************************************************** +duplicate a string +****************************************************************************/ + char *strdup(const char *s) +{ + int len; + char *ret; + + if (!s) return(NULL); + + len = strlen(s)+1; + ret = (char *)malloc(len); + if (!ret) return(NULL); + memcpy(ret,s,len); + return(ret); +} +#endif + +#ifdef REPLACE_INET_NTOA +char *rep_inet_ntoa(struct in_addr ip) +{ + unsigned char *p = (unsigned char *)&ip.s_addr; + static char buf[18]; +#if WORDS_BIGENDIAN + slprintf(buf, 17, "%d.%d.%d.%d", + (int)p[0], (int)p[1], (int)p[2], (int)p[3]); +#else + slprintf(buf, 17, "%d.%d.%d.%d", + (int)p[3], (int)p[2], (int)p[1], (int)p[0]); +#endif + return buf; +} +#endif diff --git a/source/lib/signal.c b/source/lib/signal.c new file mode 100644 index 00000000000..bb1c6fe189b --- /dev/null +++ b/source/lib/signal.c @@ -0,0 +1,102 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + signal handling functions + + Copyright (C) Andrew Tridgell 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + + +/**************************************************************************** +catch child exits +****************************************************************************/ +static void sig_cld(int signum) +{ + while (sys_waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0) ; + + CatchSignal(SIGCLD, sig_cld); +} + + + +/******************************************************************* +block sigs +********************************************************************/ +void BlockSignals(BOOL block,int signum) +{ +#ifdef HAVE_SIGPROCMASK + sigset_t set; + sigemptyset(&set); + sigaddset(&set,signum); + sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL); +#elif defined(HAVE_SIGBLOCK) + int block_mask = sigmask(signum); + static int oldmask = 0; + if (block) { + oldmask = sigblock(block_mask); + } else { + sigsetmask(oldmask); + } +#else + /* yikes! This platform can't block signals? */ + static int done; + if (!done) { + DEBUG(0,("WARNING: No signal blocking available\n")); + done=1; + } +#endif +} + + + +/******************************************************************* +catch a signal. This should implement the following semantics: + +1) the handler remains installed after being called +2) the signal should be blocked during handler execution +********************************************************************/ +void CatchSignal(int signum,void (*handler)(int )) +{ +#ifdef HAVE_SIGACTION + struct sigaction act; + + ZERO_STRUCT(act); + + act.sa_handler = handler; +#ifdef SA_RESTART + act.sa_flags = SA_RESTART; +#endif + sigemptyset(&act.sa_mask); + sigaddset(&act.sa_mask,signum); + sigaction(signum,&act,NULL); +#else + /* FIXME: need to handle sigvec and systems with broken signal() */ + signal(signum, handler); +#endif +} + + + +/******************************************************************* +ignore SIGCLD via whatever means is necessary for this OS +********************************************************************/ +void CatchChild(void) +{ + CatchSignal(SIGCLD, sig_cld); +} diff --git a/source/lib/slprintf.c b/source/lib/slprintf.c new file mode 100644 index 00000000000..acdcfee38fd --- /dev/null +++ b/source/lib/slprintf.c @@ -0,0 +1,111 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + snprintf replacement + Copyright (C) Andrew Tridgell 1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +extern int DEBUGLEVEL; + + +/* this is like vsnprintf but the 'n' limit does not include + the terminating null. So if you have a 1024 byte buffer then + pass 1023 for n */ +int vslprintf(char *str, int n, char *format, va_list ap) +{ +#ifdef HAVE_VSNPRINTF + int ret = vsnprintf(str, n, format, ap); + if (ret > n || ret < 0) { + str[n] = 0; + return -1; + } + str[ret] = 0; + return ret; +#else + static char *buf; + static int len=8000; + int ret; + + /* this code is NOT a proper vsnprintf() implementation. It + relies on the fact that all calls to slprintf() in Samba + pass strings which have already been through pstrcpy() or + fstrcpy() and never more than 2 strings are + concatenated. This means the above buffer is absolutely + ample and can never be overflowed. + + In the future we would like to replace this with a proper + vsnprintf() implementation but right now we need a solution + that is secure and portable. This is it. */ + + if (!buf) { + buf = malloc(len); + if (!buf) { + /* can't call debug or we would recurse */ + exit(1); + } + } + + vsprintf(buf, format, ap); + ret = strlen(buf); + + if (ret < 0) { + str[0] = 0; + return -1; + } + + if (ret < n) { + n = ret; + } else if (ret > n) { + ret = -1; + } + + buf[n] = 0; + + memcpy(str, buf, n+1); + + return ret; +#endif +} + +#ifdef HAVE_STDARG_H + int slprintf(char *str, int n, char *format, ...) +{ +#else + int slprintf(va_alist) +va_dcl +{ + char *str, *format; + int n; +#endif + va_list ap; + int ret; + +#ifdef HAVE_STDARG_H + va_start(ap, format); +#else + va_start(ap); + str = va_arg(ap,char *); + n = va_arg(ap,int); + format = va_arg(ap,char *); +#endif + + ret = vslprintf(str,n,format,ap); + va_end(ap); + return ret; +} diff --git a/source/lib/smbrun.c b/source/lib/smbrun.c new file mode 100644 index 00000000000..86d7cf9e03f --- /dev/null +++ b/source/lib/smbrun.c @@ -0,0 +1,178 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + run a command as a specified user + Copyright (C) Andrew Tridgell 1992-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* need to move this from here!! need some sleep ... */ +struct current_user current_user; + +extern int DEBUGLEVEL; + +/**************************************************************************** +This is a utility function of smbrun(). It must be called only from +the child as it may leave the caller in a privilaged state. +****************************************************************************/ +static BOOL setup_stdout_file(char *outfile,BOOL shared) +{ + int fd; + SMB_STRUCT_STAT st; + mode_t mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH; + int flags = O_RDWR|O_CREAT|O_TRUNC|O_EXCL; + + close(1); + + if (shared) { + /* become root - unprivilaged users can't delete these files */ +#ifdef HAVE_SETRESUID + setresgid(0,0,0); + setresuid(0,0,0); +#else + setuid(0); + seteuid(0); +#endif + } + + if(sys_stat(outfile, &st) == 0) { + /* Check we're not deleting a device file. */ + if(st.st_mode & S_IFREG) + unlink(outfile); + else + flags = O_RDWR; + } + /* now create the file */ + fd = open(outfile,flags,mode); + + if (fd == -1) return False; + + if (fd != 1) { + if (dup2(fd,1) != 0) { + DEBUG(2,("Failed to create stdout file descriptor\n")); + close(fd); + return False; + } + close(fd); + } + return True; +} + + +/**************************************************************************** +run a command being careful about uid/gid handling and putting the output in +outfile (or discard it if outfile is NULL). + +if shared is True then ensure the file will be writeable by all users +but created such that its owned by root. This overcomes a security hole. + +if shared is not set then open the file with O_EXCL set +****************************************************************************/ +int smbrun(char *cmd,char *outfile,BOOL shared) +{ + int fd,pid; + int uid = current_user.uid; + int gid = current_user.gid; + + /* + * Lose any kernel oplock capabilities we may have. + */ + set_process_capability(KERNEL_OPLOCK_CAPABILITY, False); + set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY, False); + +#ifndef HAVE_EXECL + int ret; + pstring syscmd; + char *path = lp_smbrun(); + + /* in the old method we use system() to execute smbrun which then + executes the command (using system() again!). This involves lots + of shell launches and is very slow. It also suffers from a + potential security hole */ + if (!file_exist(path,NULL)) { + DEBUG(0,("SMBRUN ERROR: Can't find %s. Installation problem?\n",path)); + return(1); + } + + slprintf(syscmd,sizeof(syscmd)-1,"%s %d %d \"(%s 2>&1) > %s\"", + path,uid,gid,cmd, + outfile?outfile:"/dev/null"); + + DEBUG(5,("smbrun - running %s ",syscmd)); + ret = system(syscmd); + DEBUG(5,("gave %d\n",ret)); + return(ret); +#else + /* in this newer method we will exec /bin/sh with the correct + arguments, after first setting stdout to point at the file */ + + if ((pid=fork())) { + int status=0; + /* the parent just waits for the child to exit */ + if (sys_waitpid(pid,&status,0) != pid) { + DEBUG(2,("waitpid(%d) : %s\n",pid,strerror(errno))); + return -1; + } + return status; + } + + + /* we are in the child. we exec /bin/sh to do the work for us. we + don't directly exec the command we want because it may be a + pipeline or anything else the config file specifies */ + + /* point our stdout at the file we want output to go into */ + if (outfile && !setup_stdout_file(outfile,shared)) { + exit(80); + } + + /* now completely lose our privilages. This is a fairly paranoid + way of doing it, but it does work on all systems that I know of */ +#ifdef HAVE_SETRESUID + setresgid(0,0,0); + setresuid(0,0,0); + setresgid(gid,gid,gid); + setresuid(uid,uid,uid); +#else + setuid(0); + seteuid(0); + setgid(gid); + setegid(gid); + setuid(uid); + seteuid(uid); +#endif + + if (getuid() != uid || geteuid() != uid || + getgid() != gid || getegid() != gid) { + /* we failed to lose our privilages - do not execute + the command */ + exit(81); /* we can't print stuff at this stage, + instead use exit codes for debugging */ + } + + /* close all other file descriptors, leaving only 0, 1 and 2. 0 and + 2 point to /dev/null from the startup code */ + for (fd=3;fd<256;fd++) close(fd); + + execl("/bin/sh","sh","-c",cmd,NULL); + + /* not reached */ + exit(82); +#endif + return 1; +} diff --git a/source/lib/system.c b/source/lib/system.c index 938746e9c9d..f474633dd11 100644 --- a/source/lib/system.c +++ b/source/lib/system.c @@ -2,7 +2,7 @@ Unix SMB/Netbios implementation. Version 1.9. Samba system utilities - Copyright (C) Andrew Tridgell 1992-1995 + Copyright (C) Andrew Tridgell 1992-1998 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,13 +25,17 @@ extern int DEBUGLEVEL; /* The idea is that this file will eventually have wrappers around all - important system calls in samba. The aim is twofold: + important system calls in samba. The aims are: - to enable easier porting by putting OS dependent stuff in here - to allow for hooks into other "pseudo-filesystems" - to allow easier integration of things like the japanese extensions + + - to support the philosophy of Samba to expose the features of + the OS within the SMB model. In general whatever file/printer/variable + expansions/etc make sense to the OS should be acceptable to Samba. */ @@ -40,7 +44,7 @@ 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 +#ifndef HAVE_SELECT static int pollfd(int fd) { int r=0; @@ -56,7 +60,7 @@ static int pollfd(int fd) return(r); } -int sys_select(fd_set *fds,struct timeval *tval) +int sys_select(int maxfd, fd_set *fds,struct timeval *tval) { fd_set fds2; int counter=0; @@ -65,147 +69,411 @@ int sys_select(fd_set *fds,struct timeval *tval) 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); - } + { + int i; + for (i=0;i<maxfd;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 (found) { + memcpy((void *)fds,(void *)&fds2,sizeof(fds2)); + return(found); + } - if (tval && tval.tv_sec < counter) return(0); + if (tval && tval->tv_sec < counter) return(0); sleep(1); counter++; - } + } } -#else -int sys_select(fd_set *fds,struct timeval *tval) +#else /* !NO_SELECT */ +int sys_select(int maxfd, fd_set *fds,struct timeval *tval) { +#ifdef USE_POLL + struct pollfd pfd[256]; + int i; + int maxpoll; + int timeout; + int pollrtn; + + maxpoll = 0; + for( i = 0; i < maxfd; i++) { + if(FD_ISSET(i,fds)) { + struct pollfd *pfdp = &pfd[maxpoll++]; + pfdp->fd = i; + pfdp->events = POLLIN; + pfdp->revents = 0; + } + } + + timeout = (tval != NULL) ? (tval->tv_sec * 1000) + (tval->tv_usec/1000) : + -1; + errno = 0; + do { + pollrtn = poll( &pfd[0], maxpoll, timeout); + } while (pollrtn<0 && errno == EINTR); + + FD_ZERO(fds); + + for( i = 0; i < maxpoll; i++) + if( pfd[i].revents & POLLIN ) + FD_SET(pfd[i].fd,fds); + + return pollrtn; +#else /* USE_POLL */ + 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); + selrtn = select(maxfd,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL); } while (selrtn<0 && errno == EINTR); return(selrtn); } +#endif /* USE_POLL */ +#endif /* NO_SELECT */ + +/******************************************************************* +A stat() wrapper that will deal with 64 bit filesizes. +********************************************************************/ + +int sys_stat(char *fname,SMB_STRUCT_STAT *sbuf) +{ +#if defined(HAVE_OFF64_T) && defined(HAVE_STAT64) + return stat64(fname, sbuf); +#else + return stat(fname, sbuf); #endif +} +/******************************************************************* + An fstat() wrapper that will deal with 64 bit filesizes. +********************************************************************/ + +int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf) +{ +#if defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64) + return fstat64(fd, sbuf); +#else + return fstat(fd, sbuf); +#endif +} + +/******************************************************************* + An lstat() wrapper that will deal with 64 bit filesizes. +********************************************************************/ + +int sys_lstat(char *fname,SMB_STRUCT_STAT *sbuf) +{ +#if defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64) + return lstat64(fname, sbuf); +#else + return lstat(fname, sbuf); +#endif +} + +/******************************************************************* + An ftruncate() wrapper that will deal with 64 bit filesizes. +********************************************************************/ + +int sys_ftruncate(int fd, SMB_OFF_T offset) +{ +#if defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64) + return ftruncate64(fd, offset); +#else + return ftruncate(fd, offset); +#endif +} + +/******************************************************************* + An lseek() wrapper that will deal with 64 bit filesizes. +********************************************************************/ + +SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence) +{ +#if defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64) + return lseek64(fd, offset, whence); +#else + return lseek(fd, offset, whence); +#endif +} + +/******************************************************************* + An fseek() wrapper that will deal with 64 bit filesizes. +********************************************************************/ + +int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence) +{ +#if defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64) + return fseek64(fp, offset, whence); +#else + return fseek(fp, offset, whence); +#endif +} + +/******************************************************************* + An ftell() wrapper that will deal with 64 bit filesizes. +********************************************************************/ + +SMB_OFF_T sys_ftell(FILE *fp) +{ +#if defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64) + return (SMB_OFF_T)ftell64(fp); +#else + return (SMB_OFF_T)ftell(fp); +#endif +} /******************************************************************* -just a unlink wrapper +just a unlink wrapper that calls dos_to_unix. ********************************************************************/ -int sys_unlink(char *fname) +int dos_unlink(char *fname) { return(unlink(dos_to_unix(fname,False))); } /******************************************************************* -a simple open() wrapper +a simple open() wrapper that calls dos_to_unix. ********************************************************************/ -int sys_open(char *fname,int flags,int mode) +int dos_open(char *fname,int flags,mode_t mode) { return(open(dos_to_unix(fname,False),flags,mode)); } /******************************************************************* -a simple opendir() wrapper +a simple opendir() wrapper that calls dos_to_unix ********************************************************************/ -DIR *sys_opendir(char *dname) +DIR *dos_opendir(char *dname) { - return(opendir(dos_to_unix(dname,False))); + return(opendir(dos_to_unix(dname,False))); } - /******************************************************************* -and a stat() wrapper +and a stat() wrapper that calls dos_to_unix. ********************************************************************/ -int sys_stat(char *fname,struct stat *sbuf) +int dos_stat(char *fname,SMB_STRUCT_STAT *sbuf) { - return(stat(dos_to_unix(fname,False),sbuf)); + return(sys_stat(dos_to_unix(fname,False),sbuf)); } /******************************************************************* -don't forget lstat() +The wait() calls vary between systems ********************************************************************/ -int sys_lstat(char *fname,struct stat *sbuf) +int sys_waitpid(pid_t pid,int *status,int options) { - return(lstat(dos_to_unix(fname,False),sbuf)); +#ifdef HAVE_WAITPID + return waitpid(pid,status,options); +#else /* HAVE_WAITPID */ + return wait4(pid, status, options, NULL); +#endif /* HAVE_WAITPID */ } +/******************************************************************* +don't forget lstat() that calls dos_to_unix. +********************************************************************/ +int dos_lstat(char *fname,SMB_STRUCT_STAT *sbuf) +{ + return(sys_lstat(dos_to_unix(fname,False),sbuf)); +} /******************************************************************* -mkdir() gets a wrapper +mkdir() gets a wrapper that calls dos_to_unix. ********************************************************************/ -int sys_mkdir(char *dname,int mode) +int dos_mkdir(char *dname,mode_t mode) { return(mkdir(dos_to_unix(dname,False),mode)); } - /******************************************************************* -do does rmdir() +do does rmdir() - call dos_to_unix ********************************************************************/ -int sys_rmdir(char *dname) +int dos_rmdir(char *dname) { return(rmdir(dos_to_unix(dname,False))); } - /******************************************************************* -I almost forgot chdir() +I almost forgot chdir() - call dos_to_unix. ********************************************************************/ -int sys_chdir(char *dname) +int dos_chdir(char *dname) { return(chdir(dos_to_unix(dname,False))); } - /******************************************************************* -now for utime() +now for utime() - call dos_to_unix. ********************************************************************/ -int sys_utime(char *fname,struct utimbuf *times) +int dos_utime(char *fname,struct utimbuf *times) { + /* if the modtime is 0 or -1 then ignore the call and + return success */ + if (times->modtime == (time_t)0 || times->modtime == (time_t)-1) + return 0; + + /* if the access time is 0 or -1 then set it to the modtime */ + if (times->actime == (time_t)0 || times->actime == (time_t)-1) + times->actime = times->modtime; + return(utime(dos_to_unix(fname,False),times)); } +/********************************************************* +for rename across filesystems Patch from Warren Birnbaum +<warrenb@hpcvscdp.cv.hp.com> +**********************************************************/ + +static int copy_reg(char *source, const char *dest) +{ + SMB_STRUCT_STAT source_stats; + int ifd; + int ofd; + char *buf; + int len; /* Number of bytes read into `buf'. */ + + sys_lstat (source, &source_stats); + if (!S_ISREG (source_stats.st_mode)) + return 1; + + if (unlink (dest) && errno != ENOENT) + return 1; + + if((ifd = open (source, O_RDONLY, 0)) < 0) + return 1; + + if((ofd = open (dest, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0 ) + { + close (ifd); + return 1; + } + + if((buf = malloc( COPYBUF_SIZE )) == NULL) + { + close (ifd); + close (ofd); + unlink (dest); + return 1; + } + + while ((len = read(ifd, buf, COPYBUF_SIZE)) > 0) + { + if (write_data(ofd, buf, len) < 0) + { + close (ifd); + close (ofd); + unlink (dest); + free(buf); + return 1; + } + } + free(buf); + if (len < 0) + { + close (ifd); + close (ofd); + unlink (dest); + return 1; + } + + if (close (ifd) < 0) + { + close (ofd); + return 1; + } + if (close (ofd) < 0) + return 1; + + /* chown turns off set[ug]id bits for non-root, + so do the chmod last. */ + + /* Try to copy the old file's modtime and access time. */ + { + struct utimbuf tv; + + tv.actime = source_stats.st_atime; + tv.modtime = source_stats.st_mtime; + if (utime (dest, &tv)) + return 1; + } + + /* Try to preserve ownership. For non-root it might fail, but that's ok. + But root probably wants to know, e.g. if NFS disallows it. */ + if (chown (dest, source_stats.st_uid, source_stats.st_gid) + && (errno != EPERM)) + return 1; + + if (chmod (dest, source_stats.st_mode & 07777)) + return 1; + + unlink (source); + return 0; +} + /******************************************************************* -for rename() +for rename() - call dos_to_unix. ********************************************************************/ -int sys_rename(char *from, char *to) +int dos_rename(char *from, char *to) { -#ifdef KANJI + int rcode; 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 */ + + pstrcpy (zfrom, dos_to_unix (from, False)); + pstrcpy (zto, dos_to_unix (to, False)); + rcode = rename (zfrom, zto); + + if (errno == EXDEV) + { + /* Rename across filesystems needed. */ + rcode = copy_reg (zfrom, zto); + } + return rcode; } +/******************************************************************* +for chmod - call dos_to_unix. +********************************************************************/ +int dos_chmod(char *fname,mode_t mode) +{ + return(chmod(dos_to_unix(fname,False),mode)); +} + +/******************************************************************* +for getwd - takes a UNIX directory name and returns the name +in dos format. +********************************************************************/ +char *dos_getwd(char *s) +{ + char *wd; +#ifdef HAVE_GETCWD + wd = (char *)getcwd(s, sizeof (pstring)); +#else + wd = (char *)getwd(s); +#endif + if (wd) + unix_to_dos(wd, True); + return wd; +} /******************************************************************* 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)); +#ifndef HAVE_CHOWN + static int done; + if (!done) { + DEBUG(1,("WARNING: no chown!\n")); + done=1; + } #else - return(chown(fname,uid,gid)); + return(chown(fname,uid,gid)); #endif } @@ -214,9 +482,155 @@ os/2 also doesn't have chroot ********************************************************************/ int sys_chroot(char *dname) { -#ifdef NO_CHROOT - DEBUG(1,("Warning - chroot(%s) not done\n",dname)); +#ifndef HAVE_CHROOT + static int done; + if (!done) { + DEBUG(1,("WARNING: no chroot!\n")); + done=1; + } +#else + return(chroot(dname)); +#endif +} + +/************************************************************************** +A wrapper for gethostbyname() that tries avoids looking up hostnames +in the root domain, which can cause dial-on-demand links to come up for no +apparent reason. +****************************************************************************/ +struct hostent *sys_gethostbyname(char *name) +{ +#ifdef REDUCE_ROOT_DNS_LOOKUPS + char query[256], hostname[256]; + char *domain; + + /* Does this name have any dots in it? If so, make no change */ + + if (strchr(name, '.')) + return(gethostbyname(name)); + + /* Get my hostname, which should have domain name + attached. If not, just do the gethostname on the + original string. + */ + + gethostname(hostname, sizeof(hostname) - 1); + hostname[sizeof(hostname) - 1] = 0; + if ((domain = strchr(hostname, '.')) == NULL) + return(gethostbyname(name)); + + /* Attach domain name to query and do modified query. + If names too large, just do gethostname on the + original string. + */ + + if((strlen(name) + strlen(domain)) >= sizeof(query)) + return(gethostbyname(name)); + + slprintf(query, sizeof(query)-1, "%s%s", name, domain); + return(gethostbyname(query)); +#else /* REDUCE_ROOT_DNS_LOOKUPS */ + return(gethostbyname(name)); +#endif /* REDUCE_ROOT_DNS_LOOKUPS */ +} + + +/************************************************************************** + Try and abstract process capabilities (for systems that have them). +****************************************************************************/ + +BOOL set_process_capability( uint32 cap_flag, BOOL enable ) +{ +#if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES) + if(cap_flag == KERNEL_OPLOCK_CAPABILITY) + { + cap_t cap = cap_get_proc(); + + if (cap == NULL) { + DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n", + strerror(errno))); + return False; + } + + if(enable) + cap->cap_effective |= CAP_NETWORK_MGT; + else + cap->cap_effective &= ~CAP_NETWORK_MGT; + + if (cap_set_proc(cap) == -1) { + DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n", + strerror(errno))); + return False; + } + + DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n")); + } +#endif + return True; +} + +/************************************************************************** + Try and abstract inherited process capabilities (for systems that have them). +****************************************************************************/ + +BOOL set_inherited_process_capability( uint32 cap_flag, BOOL enable ) +{ +#if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES) + if(cap_flag == KERNEL_OPLOCK_CAPABILITY) + { + cap_t cap = cap_get_proc(); + + if (cap == NULL) { + DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n", + strerror(errno))); + return False; + } + + if(enable) + cap->cap_inheritable |= CAP_NETWORK_MGT; + else + cap->cap_inheritable &= ~CAP_NETWORK_MGT; + + if (cap_set_proc(cap) == -1) { + DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n", + strerror(errno))); + return False; + } + + DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n")); + } +#endif + return True; +} + +/************************************************************************** + Wrapper for random(). +****************************************************************************/ + +long sys_random(void) +{ +#if defined(HAVE_RANDOM) + return (long)random(); +#elif defined(HAVE_RAND) + return (long)rand(); +#else + DEBUG(0,("Error - no random function available !\n")); + exit(1); +#endif +} + +/************************************************************************** + Wrapper for srandom(). +****************************************************************************/ + +void sys_srandom(unsigned int seed) +{ +#if defined(HAVE_SRANDOM) + srandom(seed); +#elif defined(HAVE_SRAND) + srand(seed); #else - return(chroot(dname)); + DEBUG(0,("Error - no srandom function available !\n")); + exit(1); #endif } diff --git a/source/lib/time.c b/source/lib/time.c new file mode 100644 index 00000000000..529f0ceb447 --- /dev/null +++ b/source/lib/time.c @@ -0,0 +1,546 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + time handling functions + Copyright (C) Andrew Tridgell 1992-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* + This stuff was largely rewritten by Paul Eggert <eggert@twinsun.com> + in May 1996 + */ + + +int serverzone=0; +int extra_time_offset = 0; + +extern int DEBUGLEVEL; + +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +#ifndef TIME_T_MIN +#define TIME_T_MIN ((time_t)0 < (time_t) -1 ? (time_t) 0 \ + : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1)) +#endif +#ifndef TIME_T_MAX +#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN) +#endif + + + +/******************************************************************* +a gettimeofday wrapper +********************************************************************/ +void GetTimeOfDay(struct timeval *tval) +{ +#ifdef HAVE_GETTIMEOFDAY_TZ + gettimeofday(tval,NULL); +#else + gettimeofday(tval); +#endif +} + +#define TM_YEAR_BASE 1900 + +/******************************************************************* +yield the difference between *A and *B, in seconds, ignoring leap seconds +********************************************************************/ +static int tm_diff(struct tm *a, struct tm *b) +{ + int ay = a->tm_year + (TM_YEAR_BASE - 1); + int by = b->tm_year + (TM_YEAR_BASE - 1); + int intervening_leap_days = + (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400); + int years = ay - by; + int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday); + int hours = 24*days + (a->tm_hour - b->tm_hour); + int minutes = 60*hours + (a->tm_min - b->tm_min); + int seconds = 60*minutes + (a->tm_sec - b->tm_sec); + + return seconds; +} + +/******************************************************************* + return the UTC offset in seconds west of UTC, or 0 if it cannot be determined + ******************************************************************/ +static int TimeZone(time_t t) +{ + struct tm *tm = gmtime(&t); + struct tm tm_utc; + if (!tm) + return 0; + tm_utc = *tm; + tm = localtime(&t); + if (!tm) + return 0; + return tm_diff(&tm_utc,tm); + +} + + +/******************************************************************* +init the time differences +********************************************************************/ +void TimeInit(void) +{ + serverzone = TimeZone(time(NULL)); + + if ((serverzone % 60) != 0) { + DEBUG(1,("WARNING: Your timezone is not a multiple of 1 minute.\n")); + } + + DEBUG(4,("Serverzone is %d\n",serverzone)); +} + + +/******************************************************************* +return the same value as TimeZone, but it should be more efficient. + +We keep a table of DST offsets to prevent calling localtime() on each +call of this function. This saves a LOT of time on many unixes. + +Updated by Paul Eggert <eggert@twinsun.com> +********************************************************************/ +static int TimeZoneFaster(time_t t) +{ + static struct dst_table {time_t start,end; int zone;} *dst_table = NULL; + static int table_size = 0; + int i; + int zone = 0; + + if (t == 0) t = time(NULL); + + /* Tunis has a 8 day DST region, we need to be careful ... */ +#define MAX_DST_WIDTH (365*24*60*60) +#define MAX_DST_SKIP (7*24*60*60) + + for (i=0;i<table_size;i++) + if (t >= dst_table[i].start && t <= dst_table[i].end) break; + + if (i<table_size) { + zone = dst_table[i].zone; + } else { + time_t low,high; + + zone = TimeZone(t); + dst_table = (struct dst_table *)Realloc(dst_table, + sizeof(dst_table[0])*(i+1)); + if (!dst_table) { + table_size = 0; + } else { + table_size++; + + dst_table[i].zone = zone; + dst_table[i].start = dst_table[i].end = t; + + /* no entry will cover more than 6 months */ + low = t - MAX_DST_WIDTH/2; + if (t < low) + low = TIME_T_MIN; + + high = t + MAX_DST_WIDTH/2; + if (high < t) + high = TIME_T_MAX; + + /* widen the new entry using two bisection searches */ + while (low+60*60 < dst_table[i].start) { + if (dst_table[i].start - low > MAX_DST_SKIP*2) + t = dst_table[i].start - MAX_DST_SKIP; + else + t = low + (dst_table[i].start-low)/2; + if (TimeZone(t) == zone) + dst_table[i].start = t; + else + low = t; + } + + while (high-60*60 > dst_table[i].end) { + if (high - dst_table[i].end > MAX_DST_SKIP*2) + t = dst_table[i].end + MAX_DST_SKIP; + else + t = high - (high-dst_table[i].end)/2; + if (TimeZone(t) == zone) + dst_table[i].end = t; + else + high = t; + } +#if 0 + DEBUG(1,("Added DST entry from %s ", + asctime(localtime(&dst_table[i].start)))); + DEBUG(1,("to %s (%d)\n",asctime(localtime(&dst_table[i].end)), + dst_table[i].zone)); +#endif + } + } + return zone; +} + +/**************************************************************************** + return the UTC offset in seconds west of UTC, adjusted for extra time offset + **************************************************************************/ +int TimeDiff(time_t t) +{ + return TimeZoneFaster(t) + 60*extra_time_offset; +} + + +/**************************************************************************** + return the UTC offset in seconds west of UTC, adjusted for extra time + offset, for a local time value. If ut = lt + LocTimeDiff(lt), then + lt = ut - TimeDiff(ut), but the converse does not necessarily hold near + daylight savings transitions because some local times are ambiguous. + LocTimeDiff(t) equals TimeDiff(t) except near daylight savings transitions. + +**************************************************************************/ +static int LocTimeDiff(time_t lte) +{ + time_t lt = lte - 60*extra_time_offset; + int d = TimeZoneFaster(lt); + time_t t = lt + d; + + /* if overflow occurred, ignore all the adjustments so far */ + if (((lte < lt) ^ (extra_time_offset < 0)) | ((t < lt) ^ (d < 0))) + t = lte; + + /* now t should be close enough to the true UTC to yield the right answer */ + return TimeDiff(t); +} + + +/**************************************************************************** +try to optimise the localtime call, it can be quite expensive on some machines +****************************************************************************/ +struct tm *LocalTime(time_t *t) +{ + time_t t2 = *t; + + t2 -= TimeDiff(t2); + + return(gmtime(&t2)); +} + +/**************************************************************************** +take an NTTIME structure, containing high / low time. convert to unix time. +lkclXXXX this may need 2 SIVALs not a memcpy. we'll see... +****************************************************************************/ +time_t interpret_nt_time(NTTIME *t) +{ + char data[8]; + memcpy(data, t, sizeof(data)); + return interpret_long_date(data); +} + + +#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; + /* The next two lines are a fix needed for the + broken SCO compiler. JRA. */ + time_t l_time_min = TIME_T_MIN; + time_t l_time_max = TIME_T_MAX; + + 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 (!(l_time_min <= d && d <= l_time_max)) + return(0); + + ret = (time_t)(d+0.5); + + /* this takes us from kludge-GMT to real GMT */ + ret -= serverzone; + ret += LocTimeDiff(ret); + + return(ret); +} + + +/**************************************************************************** +put a 8 byte filetime from a time_t +This takes real GMT as input and converts to kludge-GMT +****************************************************************************/ +void put_long_date(char *p,time_t t) +{ + uint32 tlow,thigh; + double d; + + if (t==0) { + SIVAL(p,0,0); SIVAL(p,4,0); + return; + } + + /* this converts GMT to kludge-GMT */ + t -= LocTimeDiff(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); +} + + +/**************************************************************************** +check if it's a null mtime +****************************************************************************/ +BOOL null_mtime(time_t mtime) +{ + if (mtime == 0 || mtime == 0xFFFFFFFF || mtime == (time_t)-1) + return(True); + return(False); +} + +/******************************************************************* + create a 16 bit dos packed date +********************************************************************/ +static uint16 make_dos_date1(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); + if (!t) + return 0xFFFFFFFF; + + 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 -= TimeDiff(unixdate); + SIVAL(buf,offset,unixdate); +} + +/******************************************************************* + interpret a 32 bit dos packed date/time to some parameters +********************************************************************/ +static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second) +{ + uint32 p0,p1,p2,p3; + + p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF; + p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF; + + *second = 2*(p0 & 0x1F); + *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3); + *hour = (p1>>3)&0xFF; + *day = (p2&0x1F); + *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1; + *year = ((p3>>1)&0xFF) + 80; +} + +/******************************************************************* + create a unix date (int GMT) from a dos date (which is actually in + localtime) +********************************************************************/ +time_t make_unix_date(void *date_ptr) +{ + uint32 dos_date=0; + struct tm t; + time_t ret; + + dos_date = IVAL(date_ptr,0); + + if (dos_date == 0) return(0); + + interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon, + &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec); + t.tm_isdst = -1; + + /* mktime() also does the local to GMT time conversion for us */ + ret = mktime(&t); + + return(ret); +} + +/******************************************************************* +like make_unix_date() but the words are reversed +********************************************************************/ +time_t make_unix_date2(void *date_ptr) +{ + uint32 x,x2; + + x = IVAL(date_ptr,0); + x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16); + SIVAL(&x,0,x2); + + return(make_unix_date((void *)&x)); +} + +/******************************************************************* + create a unix GMT date from a dos date in 32 bit "unix like" format + these generally arrive as localtimes, with corresponding DST + ******************************************************************/ +time_t make_unix_date3(void *date_ptr) +{ + time_t t = (time_t)IVAL(date_ptr,0); + if (!null_mtime(t)) + t += LocTimeDiff(t); + return(t); +} + + +/*************************************************************************** +return a HTTP/1.0 time string + ***************************************************************************/ +char *http_timestring(time_t t) +{ + static fstring buf; + struct tm *tm = LocalTime(&t); + + if (!tm) + slprintf(buf,sizeof(buf)-1,"%ld seconds since the Epoch",(long)t); + else +#ifndef HAVE_STRFTIME + fstrcpy(buf, asctime(tm)); +#else /* !HAVE_STRFTIME */ + strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S %Z", tm); +#endif /* !HAVE_STRFTIME */ + return buf; +} + + + +/**************************************************************************** + return the date and time as a string +****************************************************************************/ +char *timestring(void ) +{ + static fstring TimeBuf; + time_t t = time(NULL); + struct tm *tm = LocalTime(&t); + + if (!tm) { + slprintf(TimeBuf,sizeof(TimeBuf)-1,"%ld seconds since the Epoch",(long)t); + } else { +#ifdef HAVE_STRFTIME + strftime(TimeBuf,100,"%Y/%m/%d %T",tm); +#else + fstrcpy(TimeBuf, asctime(tm)); +#endif + } + return(TimeBuf); +} + +/**************************************************************************** + return the best approximation to a 'create time' under UNIX from a stat + structure. +****************************************************************************/ + +time_t get_create_time(SMB_STRUCT_STAT *st,BOOL fake_dirs) +{ + time_t ret, ret1; + + if(S_ISDIR(st->st_mode) && fake_dirs) + return (time_t)315493200L; /* 1/1/1980 */ + + ret = MIN(st->st_ctime, st->st_mtime); + ret1 = MIN(ret, st->st_atime); + + if(ret1 != (time_t)0) + return ret1; + + /* + * One of ctime, mtime or atime was zero (probably atime). + * Just return MIN(ctime, mtime). + */ + return ret; +} + diff --git a/source/lib/ufc.c b/source/lib/ufc.c index 8417285821a..f464953498e 100644 --- a/source/lib/ufc.c +++ b/source/lib/ufc.c @@ -16,12 +16,14 @@ */ -#ifdef UFC_CRYPT +#include "includes.h" + +#ifndef HAVE_CRYPT /* * UFC-crypt: ultra fast crypt(3) implementation * - * Copyright (C) 1991, 1992, Free Software Foundation, Inc. + * Copyright (C) 1991-1998, Free Software Foundation, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -42,7 +44,6 @@ * Support routines * */ -#include "includes.h" #ifndef long32 @@ -656,11 +657,11 @@ static char *output_conversion(v1, v2, salt) return outbuf; } -ufc_long *_ufc_doit(); - /* * UNIX crypt function */ + +static ufc_long *_ufc_doit(ufc_long , ufc_long, ufc_long, ufc_long, ufc_long); char *ufc_crypt(char *key,char *salt) { ufc_long *s; @@ -702,7 +703,7 @@ extern long32 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[]; #define SBA(sb, v) (*(long32*)((char*)(sb)+(v))) -ufc_long *_ufc_doit(l1, l2, r1, r2, itr) +static ufc_long *_ufc_doit(l1, l2, r1, r2, itr) ufc_long l1, l2, r1, r2, itr; { int i; long32 s, *k; @@ -742,7 +743,7 @@ extern long64 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[]; #define SBA(sb, v) (*(long64*)((char*)(sb)+(v))) -ufc_long *_ufc_doit(l1, l2, r1, r2, itr) +static ufc_long *_ufc_doit(l1, l2, r1, r2, itr) ufc_long l1, l2, r1, r2, itr; { int i; long64 l, r, s, *k; @@ -777,6 +778,6 @@ ufc_long *_ufc_doit(l1, l2, r1, r2, itr) #else -int ufc_dummy_procedure(void) + int ufc_dummy_procedure(void) {return 0;} #endif diff --git a/source/lib/username.c b/source/lib/username.c index 3d214fbbdab..f56f7efce2e 100644 --- a/source/lib/username.c +++ b/source/lib/username.c @@ -2,7 +2,7 @@ Unix SMB/Netbios implementation. Version 1.9. Username handling - Copyright (C) Andrew Tridgell 1992-1995 + Copyright (C) Andrew Tridgell 1992-1998 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,18 +20,20 @@ */ #include "includes.h" -#include "loadparm.h" extern int DEBUGLEVEL; +/* internal functions */ +static struct passwd *uname_string_combinations(char *s, struct passwd * (*fn) (char *), int N); +static struct passwd *uname_string_combinations2(char *s, int offset, struct passwd * (*fn) (char *), int N); /**************************************************************************** -get a users home directory. tries as-is then lower case +get a users home directory. ****************************************************************************/ char *get_home_dir(char *user) { static struct passwd *pass; - pass = Get_Pwnam(user,False); + pass = Get_Pwnam(user, False); if (!pass) return(NULL); return(pass->pw_dir); @@ -40,76 +42,109 @@ char *get_home_dir(char *user) /******************************************************************* map a username from a dos name to a unix name by looking in the username -map +map. Note that this modifies the name in place. +This is the main function that should be called *once* on +any incoming or new username - in order to canonicalize the name. +This is being done to de-couple the case conversions from the user mapping +function. Previously, the map_username was being called +every time Get_Pwnam was called. +Returns True if username was changed, false otherwise. ********************************************************************/ -void map_username(char *user) +BOOL 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; + char *s; + pstring buf; + BOOL mapped_user = False; - if (!*user) return; + if (!*user) + return False; + + if (!*mapfile) + return False; if (!initialised) { *last_from = *last_to = 0; initialised = True; } - if (strequal(user,last_to)) return; + if (strequal(user,last_to)) + return False; if (strequal(user,last_from)) { DEBUG(3,("Mapped user %s to %s\n",user,last_to)); - strcpy(user,last_to); - return; + fstrcpy(user,last_to); + return True; } f = fopen(mapfile,"r"); if (!f) { DEBUG(0,("can't open username map %s\n",mapfile)); - return; + return False; } DEBUG(4,("Scanning username map %s\n",mapfile)); - depth++; - - for (; (s=fgets_slash(NULL,80,f)); free(s)) { + while((s=fgets_slash(buf,sizeof(buf),f))!=NULL) { char *unixname = s; char *dosname = strchr(unixname,'='); + BOOL return_if_mapped = False; + + if (!dosname) + continue; - if (!dosname) continue; *dosname++ = 0; - while (isspace(*unixname)) unixname++; - if (!*unixname || strchr("#;",*unixname)) continue; + while (isspace(*unixname)) + unixname++; + if ('!' == *unixname) { + return_if_mapped = True; + unixname++; + while (*unixname && isspace(*unixname)) + unixname++; + } + + if (!*unixname || strchr("#;",*unixname)) + continue; { int l = strlen(unixname); while (l && isspace(unixname[l-1])) { - unixname[l-1] = 0; - l--; + 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); + mapped_user = True; + fstrcpy(last_from,user); sscanf(unixname,"%s",user); - StrnCpy(last_to,user,sizeof(last_to)-1); + fstrcpy(last_to,user); + if(return_if_mapped) { + fclose(f); + return True; + } } } fclose(f); - depth--; + /* + * Setup the last_from and last_to as an optimization so + * that we don't scan the file again for the same user. + */ + fstrcpy(last_from,user); + fstrcpy(last_to,user); + + return mapped_user; } /**************************************************************************** -internals of Get_Pwnam wrapper +Get_Pwnam wrapper ****************************************************************************/ static struct passwd *_Get_Pwnam(char *s) { @@ -118,7 +153,7 @@ static struct passwd *_Get_Pwnam(char *s) ret = getpwnam(s); if (ret) { -#ifdef GETPWANAM +#ifdef HAVE_GETPWANAM struct passwd_adjunct *pwret; pwret = getpwanam(s); if (pwret) @@ -137,11 +172,13 @@ static struct passwd *_Get_Pwnam(char *s) /**************************************************************************** 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! +Note that this can change user! ****************************************************************************/ struct passwd *Get_Pwnam(char *user,BOOL allow_change) { fstring user2; + int last_char; + int usernamelevel = lp_usernamelevel(); struct passwd *ret; @@ -154,8 +191,6 @@ struct passwd *Get_Pwnam(char *user,BOOL allow_change) user = &user2[0]; } - map_username(user); - ret = _Get_Pwnam(user); if (ret) return(ret); @@ -173,74 +208,216 @@ struct passwd *Get_Pwnam(char *user,BOOL allow_change) ret = _Get_Pwnam(user); if (ret) return(ret); + /* try with last letter capitalised */ + strlower(user); + last_char = strlen(user)-1; + user[last_char] = toupper(user[last_char]); + ret = _Get_Pwnam(user); + if (ret) return(ret); + + /* try all combinations up to usernamelevel */ + strlower(user); + ret = uname_string_combinations(user, _Get_Pwnam, usernamelevel); + if (ret) return(ret); + if (allow_change) - strcpy(user,user2); + fstrcpy(user,user2); return(NULL); } +/**************************************************************************** +check if a user is in a netgroup user list +****************************************************************************/ +static BOOL user_in_netgroup_list(char *user,char *ngname) +{ +#ifdef HAVE_NETGROUP + static char *mydomain = NULL; + if (mydomain == NULL) + yp_get_default_domain(&mydomain); + + if(mydomain == NULL) + { + DEBUG(5,("Unable to get default yp domain\n")); + } + else + { + DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", + user, mydomain, ngname)); + DEBUG(5,("innetgr is %s\n", + innetgr(ngname, NULL, user, mydomain) + ? "TRUE" : "FALSE")); + + if (innetgr(ngname, NULL, user, mydomain)) + return (True); + } +#endif /* HAVE_NETGROUP */ + return False; +} + +/**************************************************************************** +check if a user is in a UNIX user list +****************************************************************************/ +static BOOL user_in_group_list(char *user,char *gname) +{ +#ifdef HAVE_GETGRNAM + 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,gname)) + return(True); + } + + gptr = (struct group *)getgrnam(gname); + + if (gptr) + { + member = gptr->gr_mem; + while (member && *member) + { + if (strequal(*member,user)) + return(True); + member++; + } + } +#endif /* HAVE_GETGRNAM */ + return False; +} /**************************************************************************** -check if a user is in a user list +check if a user is in a user list - can check combinations of UNIX +and netgroup lists. ****************************************************************************/ BOOL user_in_list(char *user,char *list) { pstring tok; char *p=list; - while (next_token(&p,tok,LIST_SEP)) + while (next_token(&p,tok,LIST_SEP, sizeof(tok))) + { + /* + * Check raw username. + */ + if (strequal(user,tok)) + return(True); + + /* + * Now check to see if any combination + * of UNIX and netgroups has been specified. + */ + + if(*tok == '@') + { + /* + * Old behaviour. Check netgroup list + * followed by UNIX list. + */ + if(user_in_netgroup_list(user,&tok[1])) + return True; + if(user_in_group_list(user,&tok[1])) + return True; + } + else if (*tok == '+') + { + if(tok[1] == '&') + { + /* + * Search UNIX list followed by netgroup. + */ + if(user_in_group_list(user,&tok[2])) + return True; + if(user_in_netgroup_list(user,&tok[2])) + return True; + } + else + { + /* + * Just search UNIX list. + */ + if(user_in_group_list(user,&tok[1])) + return True; + } + } + else if (*tok == '&') { - if (strequal(user,tok)) - return(True); + if(tok[1] == '&') + { + /* + * Search netgroup list followed by UNIX list. + */ + if(user_in_netgroup_list(user,&tok[2])) + return True; + if(user_in_group_list(user,&tok[2])) + return True; + } + else + { + /* + * Just search netgroup list. + */ + if(user_in_netgroup_list(user,&tok[1])) + return True; + } + } + } + return(False); +} -#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); - } +/* The functions below have been taken from password.c and slightly modified */ +/**************************************************************************** +apply a function to upper/lower case combinations +of a string and return true if one of them returns true. +try all combinations with N uppercase letters. +offset is the first char to try and change (start with 0) +it assumes the string starts lowercased +****************************************************************************/ +static struct passwd *uname_string_combinations2(char *s,int offset,struct passwd *(*fn)(char *),int N) +{ + int len = strlen(s); + int i; + struct passwd *ret; + +#ifdef PASSWORD_LENGTH + len = MIN(len,PASSWORD_LENGTH); #endif + if (N <= 0 || offset >= len) + return(fn(s)); -#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 + + for (i=offset;i<(len-(N-1));i++) + + { + char c = s[i]; + if (!islower(c)) continue; + s[i] = toupper(c); + ret = uname_string_combinations2(s,i+1,fn,N-1); + if(ret) return(ret); + s[i] = c; } - return(False); + return(NULL); } +/**************************************************************************** +apply a function to upper/lower case combinations +of a string and return true if one of them returns true. +try all combinations with up to N uppercase letters. +offset is the first char to try and change (start with 0) +it assumes the string starts lowercased +****************************************************************************/ +static struct passwd * uname_string_combinations(char *s,struct passwd * (*fn)(char *),int N) +{ + int n; + struct passwd *ret; + for (n=1;n<=N;n++) + { + ret = uname_string_combinations2(s,0,fn,n); + if(ret) return(ret); + } + return(NULL); +} diff --git a/source/lib/util.c b/source/lib/util.c index 7bd6298c4ca..8561c4f3f4a 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -2,7 +2,7 @@ Unix SMB/Netbios implementation. Version 1.9. Samba utility functions - Copyright (C) Andrew Tridgell 1992-1995 + Copyright (C) Andrew Tridgell 1992-1998 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,41 +20,44 @@ */ #include "includes.h" -#include "loadparm.h" + +#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT)) +#ifdef WITH_NISPLUS_HOME +#include <rpcsvc/nis.h> +#else +#include "rpcsvc/ypclnt.h" +#endif +#endif + +#ifdef WITH_SSL +#include <ssl.h> +#undef Realloc /* SSLeay defines this and samba has a function of this name */ +extern SSL *ssl; +extern int sslFd; +#endif /* WITH_SSL */ pstring scope = ""; -int DEBUGLEVEL = 1; +extern int DEBUGLEVEL; 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; +/* this is used by the chaining code */ +int chain_size = 0; int trans_num = 0; @@ -63,13 +66,6 @@ int trans_num = 0; */ int case_default = CASE_LOWER; - -/* size of reads during a direct file to file transfer */ -int ReadSize = 16*1024; - -pstring debugf = "/tmp/log.samba"; -int syslog_level; - /* the following control case operations - they are put here so the client can link easily */ BOOL case_sensitive; @@ -81,448 +77,39 @@ BOOL case_mangle; fstring remote_machine=""; fstring local_machine=""; fstring remote_arch="UNKNOWN"; +static enum remote_arch_types ra_type = RA_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; - } -} +pstring sesssetup_user=""; +pstring samlogon_user=""; -BOOL append_log=False; +BOOL sam_logon_in_ssb = False; +pstring global_myname = ""; +fstring global_myworkgroup = ""; +char **my_netbios_names; -/**************************************************************************** -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()); +int smb_read_error = 0; - 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 +static char *filename_dos(char *path,char *buf); - 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) + find a suitable temporary directory. The result should be copied immediately + as it may be overwritten by a subsequent call + ****************************************************************************/ +char *tmpdir(void) { -#if HAVE_FCNTL_LOCK - struct flock lock; - int ret; - -#if 1 - uint32 mask = 0xC0000000; - - /* make sure the count is reasonable, we might kill the lockd otherwise */ - count &= ~mask; - - /* the offset is often strange - remove 2 of its bits if either of - the top two bits are set. Shift the top ones by two bits. This - still allows OLE2 apps to operate, but should stop lockd from - dieing */ - if ((offset & mask) != 0) - offset = (offset & ~mask) | ((offset & mask) >> 2); -#else - unsigned long mask = ((unsigned)1<<31); - - /* interpret negative counts as large numbers */ - if (count < 0) - count &= ~mask; - - /* no negative offsets */ - offset &= ~mask; - - /* count + offset must be in range */ - while ((offset < 0 || (offset + count < 0)) && mask) - { - offset &= ~mask; - mask = mask >> 1; - } -#endif - - - DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type)); - - lock.l_type = type; - lock.l_whence = SEEK_SET; - lock.l_start = (int)offset; - lock.l_len = (int)count; - lock.l_pid = 0; - - errno = 0; - - ret = fcntl(fd,op,&lock); - - if (errno != 0) - DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno))); - - /* a lock query */ - if (op == F_GETLK) - { - if ((ret != -1) && - (lock.l_type != F_UNLCK) && - (lock.l_pid != 0) && - (lock.l_pid != getpid())) - { - DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid)); - return(True); - } - - /* it must be not locked or locked by me */ - return(False); - } - - /* a lock set or unset */ - if (ret == -1) - { - DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n", - offset,count,op,type,strerror(errno))); - - /* perhaps it doesn't support this sort of locking?? */ - if (errno == EINVAL) - { - DEBUG(3,("locking not supported? returning True\n")); - return(True); - } - - return(False); - } - - /* everything went OK */ - DEBUG(5,("Lock call successful\n")); - - return(True); -#else - return(False); -#endif -} - -/******************************************************************* -lock a file - returning a open file descriptor or -1 on failure -The timeout is in seconds. 0 means no timeout -********************************************************************/ -int file_lock(char *name,int timeout) -{ - int fd = open(name,O_RDWR|O_CREAT,0666); - time_t t=0; - if (fd < 0) return(-1); - -#if HAVE_FCNTL_LOCK - if (timeout) t = time(NULL); - while (!timeout || (time(NULL)-t < timeout)) { - if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)) return(fd); - msleep(LOCK_RETRY_TIMEOUT); - } - return(-1); -#else - return(fd); -#endif -} - -/******************************************************************* -unlock a file locked by file_lock -********************************************************************/ -void file_unlock(int fd) -{ - if (fd<0) return; -#if HAVE_FCNTL_LOCK - fcntl_lock(fd,F_SETLK,0,1,F_UNLCK); -#endif - close(fd); -} - -/******************************************************************* -a gettimeofday wrapper -********************************************************************/ -void GetTimeOfDay(struct timeval *tval) -{ -#ifdef GETTIMEOFDAY1 - gettimeofday(tval); -#else - gettimeofday(tval,NULL); -#endif -} - -int extra_time_offset = 0; - -static int timediff = 0; - -/******************************************************************* -init the time differences -********************************************************************/ -void TimeInit(void) -{ - struct tm tm_utc,tm_local; - time_t t; - - t = time(NULL); - - tm_utc = *(gmtime(&t)); - tm_local = *(localtime(&t)); - -#ifdef HAVE_GMTOFF - timediff = -tm_local.tm_gmtoff; -#else - timediff = mktime(&tm_utc) - mktime(&tm_local); -#endif - - if (serverzone == 0) { - serverzone = timediff - DSTDiff(t); - DEBUG(4,("Serverzone is %d\n",serverzone)); - } -} - - -/******************************************************************* -return the DST offset for a particular time -We keep a table of DST offsets to prevent calling localtime() on each -call of this function. This saves a LOT of time on many unixes. -********************************************************************/ -int DSTDiff(time_t t) -{ - static struct dst_table {time_t start,end; BOOL is_dst;} *dst_table = NULL; - static int table_size = 0; - int i; - BOOL is_dst = False; - - if (t == 0) t = time(NULL); - -#ifndef NO_ISDST - for (i=0;i<table_size;i++) - if (t >= dst_table[i].start && t <= dst_table[i].end) break; - - if (i<table_size) { - is_dst = dst_table[i].is_dst; - } else { - time_t low,high; - - dst_table = (struct dst_table *)Realloc(dst_table, - sizeof(dst_table[0])*(i+1)); - if (!dst_table) { - table_size = 0; - return(0); - } - - table_size++; - - dst_table[i].is_dst = is_dst = (localtime(&t)->tm_isdst?True:False);; - dst_table[i].start = dst_table[i].end = t; - - /* no entry will cover more than 6 months */ - low = t - 3*30*24*60*60; - high = t + 3*30*24*60*60; - - /* widen the new entry using two bisection searches */ - while (low+60*60 < dst_table[i].start) { - t = low + (dst_table[i].start-low)/2; - if ((localtime(&t)->tm_isdst?True:False) == is_dst) - dst_table[i].start = t; - else - low = t; - } - - while (high-60*60 > dst_table[i].end) { - t = high + (high-dst_table[i].end)/2; - if ((localtime(&t)->tm_isdst?True:False) == is_dst) - dst_table[i].end = t; - else - high = t; - } - -/* - DEBUG(1,("Added DST entry from %s ", - asctime(localtime(&dst_table[i].start)))); - DEBUG(1,("to %s (%d)\n",asctime(localtime(&dst_table[i].end)), - dst_table[i].is_dst)); -*/ + char *p; + if ((p = getenv("TMPDIR"))) { + return p; } -#endif - - return((is_dst?60*60:0) - (extra_time_offset*60)); + return "/tmp"; } -/**************************************************************************** -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)); -} /**************************************************************************** @@ -544,10 +131,11 @@ static char *last_ptr=NULL; 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) +BOOL next_token(char **ptr,char *buff,char *sep, int bufsize) { char *s; BOOL quoted; + int len=1; if (!ptr) ptr = &last_ptr; if (!ptr) return(False); @@ -564,12 +152,14 @@ BOOL next_token(char **ptr,char *buff,char *sep) if (! *s) return(False); /* copy over the token */ - for (quoted = False; *s && (quoted || !strchr(sep,*s)); s++) + for (quoted = False; len < bufsize && *s && (quoted || !strchr(sep,*s)); s++) { - if (*s == '\"') - quoted = !quoted; - else - *buff++ = *s; + if (*s == '\"') { + quoted = !quoted; + } else { + len++; + *buff++ = *s; + } } *ptr = (*s) ? s+1 : s; @@ -616,71 +206,10 @@ char **toktocliplist(int *ctok, char *sep) 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) +static void array_promote(char *array,int elsize,int element) { char *p; if (element == 0) @@ -733,6 +262,12 @@ struct #ifdef SO_RCVLOWAT {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT}, #endif +#ifdef SO_SNDTIMEO + {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT}, +#endif +#ifdef SO_RCVTIMEO + {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT}, +#endif {NULL,0,0,0,0}}; @@ -742,9 +277,9 @@ set user socket options ****************************************************************************/ void set_socket_options(int fd, char *options) { - string tok; + fstring tok; - while (next_token(&options,tok," \t,")) + while (next_token(&options,tok," \t,", sizeof(tok))) { int ret=0,i; int value = 1; @@ -800,50 +335,28 @@ void set_socket_options(int fd, char *options) ****************************************************************************/ void close_sockets(void ) { +#ifdef WITH_SSL + sslutil_disconnect(Client); +#endif /* WITH_SSL */ + 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) +BOOL in_group(gid_t group, int current_gid, int ngroups, GID_T *groups) { - int i; + int i; - if (group == current_gid) return(True); + if (group == current_gid) return(True); - for (i=0;i<ngroups;i++) - if (group == groups[i]) - return(True); + for (i=0;i<ngroups;i++) + if (group == groups[i]) + return(True); - return(False); + return(False); } /**************************************************************************** @@ -853,13 +366,8 @@ 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 + SMB_ASSERT(dest && src); if (!dest) return(NULL); if (!src) { @@ -873,7 +381,7 @@ char *StrCpy(char *dest,char *src) /**************************************************************************** line strncpy but always null terminates. Make sure there is room! ****************************************************************************/ -char *StrnCpy(char *dest,const char *src,int n) +char *StrnCpy(char *dest,char *src,int n) { char *d = dest; if (!dest) return(NULL); @@ -896,6 +404,46 @@ void putip(void *dest,void *src) } +#define TRUNCATE_NETBIOS_NAME 1 + +/******************************************************************* + convert, possibly using a stupid microsoft-ism which has destroyed + the transport independence of netbios (for CIFS vendors that usually + use the Win95-type methods, not for NT to NT communication, which uses + DCE/RPC and therefore full-length unicode strings...) a dns name into + a netbios name. + + the netbios name (NOT necessarily null-terminated) is truncated to 15 + characters. + + ******************************************************************/ +char *dns_to_netbios_name(char *dns_name) +{ + static char netbios_name[16]; + int i; + StrnCpy(netbios_name, dns_name, 15); + netbios_name[15] = 0; + +#ifdef TRUNCATE_NETBIOS_NAME + /* ok. this is because of a stupid microsoft-ism. if the called host + name contains a '.', microsoft clients expect you to truncate the + netbios name up to and including the '.' this even applies, by + mistake, to workgroup (domain) names, which is _really_ daft. + */ + for (i = 15; i >= 0; i--) + { + if (netbios_name[i] == '.') + { + netbios_name[i] = 0; + break; + } + } +#endif /* TRUNCATE_NETBIOS_NAME */ + + return netbios_name; +} + + /**************************************************************************** interpret the weird netbios "name". Return the name type ****************************************************************************/ @@ -938,58 +486,71 @@ static int name_interpret(char *in,char *out) /**************************************************************************** mangle a name into netbios format + + Note: <Out> must be (33 + strlen(scope) + 2) bytes long, at minimum. ****************************************************************************/ -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; +int name_mangle( char *In, char *Out, char name_type ) + { + int i; + int c; + int len; + char buf[20]; + char *p = Out; + + /* Safely copy the input string, In, into buf[]. */ + (void)memset( buf, 0, 20 ); + if( '*' == In[0] ) + buf[0] = '*'; + else + (void)slprintf( buf, sizeof(buf) - 1, "%-15.15s%c", In, name_type ); - 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); - } + /* Place the length of the first field into the output buffer. */ + p[0] = 32; + p++; - *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) + /* Now convert the name to the rfc1001/1002 format. */ + for( i = 0; i < 16; i++ ) { - 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 == '.'); + c = toupper( buf[i] ); + p[i*2] = ( (c >> 4) & 0x000F ) + 'A'; + p[(i*2)+1] = (c & 0x000F) + 'A'; + } + p += 32; + p[0] = '\0'; + + /* Add the scope string. */ + for( i = 0, len = 0; NULL != scope; i++, len++ ) + { + switch( scope[i] ) + { + case '\0': + p[0] = len; + if( len > 0 ) + p[len+1] = 0; + return( name_len(Out) ); + case '.': + p[0] = len; + p += (len + 1); + len = 0; + break; + default: + p[len+1] = scope[i]; + break; + } } - *out = 0; - return(name_len(Out)); -} + return( name_len(Out) ); + } /* name_mangle */ /******************************************************************* check if a file exists ********************************************************************/ -BOOL file_exist(char *fname,struct stat *sbuf) +BOOL file_exist(char *fname,SMB_STRUCT_STAT *sbuf) { - struct stat st; + SMB_STRUCT_STAT st; if (!sbuf) sbuf = &st; - if (sys_stat(fname,sbuf) != 0) + if (dos_stat(fname,sbuf) != 0) return(False); return(S_ISREG(sbuf->st_mode)); @@ -1000,9 +561,9 @@ check a files mod time ********************************************************************/ time_t file_modtime(char *fname) { - struct stat st; + SMB_STRUCT_STAT st; - if (sys_stat(fname,&st) != 0) + if (dos_stat(fname,&st) != 0) return(0); return(st.st_mtime); @@ -1011,196 +572,48 @@ time_t file_modtime(char *fname) /******************************************************************* check if a directory exists ********************************************************************/ -BOOL directory_exist(char *dname,struct stat *st) +BOOL directory_exist(char *dname,SMB_STRUCT_STAT *st) { - struct stat st2; + SMB_STRUCT_STAT st2; + BOOL ret; + if (!st) st = &st2; - if (sys_stat(dname,st) != 0) + if (dos_stat(dname,st) != 0) return(False); - return(S_ISDIR(st->st_mode)); + ret = S_ISDIR(st->st_mode); + if(!ret) + errno = ENOTDIR; + return ret; } /******************************************************************* returns the size in bytes of the named file ********************************************************************/ -uint32 file_size(char *file_name) +SMB_OFF_T file_size(char *file_name) { - struct stat buf; + SMB_STRUCT_STAT buf; buf.st_size = 0; - sys_stat(file_name,&buf); + dos_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]; + static fstring attrstr; attrstr[0] = 0; - if (mode & aVOLID) strcat(attrstr,"V"); - if (mode & aDIR) strcat(attrstr,"D"); - if (mode & aARCH) strcat(attrstr,"A"); - if (mode & aHIDDEN) strcat(attrstr,"H"); - if (mode & aSYSTEM) strcat(attrstr,"S"); - if (mode & aRONLY) strcat(attrstr,"R"); + if (mode & aVOLID) fstrcat(attrstr,"V"); + if (mode & aDIR) fstrcat(attrstr,"D"); + if (mode & aARCH) fstrcat(attrstr,"A"); + if (mode & aHIDDEN) fstrcat(attrstr,"H"); + if (mode & aSYSTEM) fstrcat(attrstr,"S"); + if (mode & aRONLY) fstrcat(attrstr,"R"); return(attrstr); } @@ -1211,10 +624,72 @@ char *attrib_string(int mode) ********************************************************************/ int StrCaseCmp(char *s, char *t) { - for (; tolower(*s) == tolower(*t); ++s, ++t) - if (!*s) return 0; + /* compare until we run out of string, either t or s, or find a difference */ + /* We *must* use toupper rather than tolower here due to the + asynchronous upper to lower mapping. + */ +#if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + + if(lp_client_code_page() == KANJI_CODEPAGE) + { + /* Win95 treats full width ascii characters as case sensitive. */ + int diff; + for (;;) + { + if (!*s || !*t) + return toupper (*s) - toupper (*t); + else if (is_sj_alph (*s) && is_sj_alph (*t)) + { + diff = sj_toupper2 (*(s+1)) - sj_toupper2 (*(t+1)); + if (diff) + return diff; + s += 2; + t += 2; + } + else if (is_shift_jis (*s) && is_shift_jis (*t)) + { + diff = ((int) (unsigned char) *s) - ((int) (unsigned char) *t); + if (diff) + return diff; + diff = ((int) (unsigned char) *(s+1)) - ((int) (unsigned char) *(t+1)); + if (diff) + return diff; + s += 2; + t += 2; + } + else if (is_shift_jis (*s)) + return 1; + else if (is_shift_jis (*t)) + return -1; + else + { + diff = toupper (*s) - toupper (*t); + if (diff) + return diff; + s++; + t++; + } + } + } + else +#endif /* KANJI_WIN95_COMPATIBILITY */ + { + while (*s && *t && toupper(*s) == toupper(*t)) + { + s++; + t++; + } - return tolower(*s) - tolower(*t); + return(toupper(*s) - toupper(*t)); + } } /******************************************************************* @@ -1222,19 +697,89 @@ int StrCaseCmp(char *s, char *t) ********************************************************************/ int StrnCaseCmp(char *s, char *t, int n) { - while (n-- && *s && *t) { - if (tolower(*s) != tolower(*t)) return(tolower(*s) - tolower(*t)); - s++; t++; + /* compare until we run out of string, either t or s, or chars */ + /* We *must* use toupper rather than tolower here due to the + asynchronous upper to lower mapping. + */ +#if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + + if(lp_client_code_page() == KANJI_CODEPAGE) + { + /* Win95 treats full width ascii characters as case sensitive. */ + int diff; + for (;n > 0;) + { + if (!*s || !*t) + return toupper (*s) - toupper (*t); + else if (is_sj_alph (*s) && is_sj_alph (*t)) + { + diff = sj_toupper2 (*(s+1)) - sj_toupper2 (*(t+1)); + if (diff) + return diff; + s += 2; + t += 2; + n -= 2; + } + else if (is_shift_jis (*s) && is_shift_jis (*t)) + { + diff = ((int) (unsigned char) *s) - ((int) (unsigned char) *t); + if (diff) + return diff; + diff = ((int) (unsigned char) *(s+1)) - ((int) (unsigned char) *(t+1)); + if (diff) + return diff; + s += 2; + t += 2; + n -= 2; + } + else if (is_shift_jis (*s)) + return 1; + else if (is_shift_jis (*t)) + return -1; + else + { + diff = toupper (*s) - toupper (*t); + if (diff) + return diff; + s++; + t++; + n--; + } + } + return 0; } - if (n) return(tolower(*s) - tolower(*t)); + else +#endif /* KANJI_WIN95_COMPATIBILITY */ + { + while (n && *s && *t && toupper(*s) == toupper(*t)) + { + s++; + t++; + n--; + } - return(0); + /* not run out of chars - strings are different lengths */ + if (n) + return(toupper(*s) - toupper(*t)); + + /* identical up to where we run out of chars, + and strings are same length */ + return(0); + } } /******************************************************************* compare 2 strings ********************************************************************/ -BOOL strequal(char *s1,char *s2) +BOOL strequal(char *s1, char *s2) { if (s1 == s2) return(True); if (!s1 || !s2) return(False); @@ -1271,23 +816,51 @@ BOOL strcsequal(char *s1,char *s2) void strlower(char *s) { while (*s) + { +#if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + + if(lp_client_code_page() == KANJI_CODEPAGE) { -#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 */ + /* Win95 treats full width ascii characters as case sensitive. */ + if (is_shift_jis (*s)) + { + if (is_sj_upper (s[0], s[1])) + s[1] = sj_tolower2 (s[1]); + s += 2; + } + else if (is_kana (*s)) + { + s++; + } + else + { + if (isupper(*s)) + *s = tolower(*s); + s++; + } } + else +#endif /* KANJI_WIN95_COMPATIBILITY */ + { + int skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else + { + if (isupper(*s)) + *s = tolower(*s); + s++; + } + } + } } /******************************************************************* @@ -1296,23 +869,51 @@ void strlower(char *s) void strupper(char *s) { while (*s) + { +#if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + + if(lp_client_code_page() == KANJI_CODEPAGE) { -#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 + /* Win95 treats full width ascii characters as case sensitive. */ + if (is_shift_jis (*s)) + { + if (is_sj_lower (s[0], s[1])) + s[1] = sj_toupper2 (s[1]); + s += 2; + } + else if (is_kana (*s)) + { + s++; + } + else + { + if (islower(*s)) + *s = toupper(*s); + s++; + } } + else +#endif /* KANJI_WIN95_COMPATIBILITY */ + { + int skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else + { + if (islower(*s)) + *s = toupper(*s); + s++; + } + } + } } /******************************************************************* @@ -1343,24 +944,19 @@ BOOL strisnormal(char *s) ****************************************************************************/ void string_replace(char *s,char oldc,char newc) { + int skip; while (*s) + { + skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else { -#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 = newc; s++; -#endif /* KANJI */ } + } } /**************************************************************************** @@ -1368,18 +964,7 @@ void string_replace(char *s,char oldc,char newc) ****************************************************************************/ 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); - } } /**************************************************************************** @@ -1387,49 +972,53 @@ void unix_format(char *fname) ****************************************************************************/ 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; + 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))); + } - 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")); -} + bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct))); + DEBUG(5,("smb_bcc=%d\n",bcc)); + + if (DEBUGLEVEL < 10) return; + + if (DEBUGLEVEL < 50) + { + bcc = MIN(bcc, 512); + } + + dump_data(10, smb_buf(buf), bcc); +} /******************************************************************* return the length of an smb packet ********************************************************************/ @@ -1478,7 +1067,7 @@ int set_message(char *buf,int num_words,int num_bytes,BOOL zero) /******************************************************************* return the number of smb words ********************************************************************/ -int smb_numwords(char *buf) +static int smb_numwords(char *buf) { return (CVAL(buf,smb_wct)); } @@ -1494,7 +1083,7 @@ int smb_buflen(char *buf) /******************************************************************* return a pointer to the smb_buf data area ********************************************************************/ -int smb_buf_ofs(char *buf) +static int smb_buf_ofs(char *buf) { return (smb_size + CVAL(buf,smb_wct)*2); } @@ -1512,7 +1101,7 @@ return the SMB offset into an SMB buffer ********************************************************************/ int smb_offset(char *p,char *buf) { - return(PTR_DIFF(p,buf+4)); + return(PTR_DIFF(p,buf+4) + chain_size); } @@ -1532,23 +1121,30 @@ 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)) + size_t front_len = (front && *front) ? strlen(front) : 0; + size_t back_len = (back && *back) ? strlen(back) : 0; + size_t s_len; + + while (front_len && strncmp(s, front, front_len) == 0) + { + char *p = s; + ret = True; + while (1) { - ret = True; - s[strlen(s)-strlen(back)] = 0; + if (!(*p = p[front_len])) + break; + p++; } + } + + s_len = strlen(s); + while (back_len && s_len >= back_len && + (strncmp(s + s_len - back_len, back, back_len)==0)) + { + ret = True; + s[s_len - back_len] = 0; + s_len = strlen(s); + } return(ret); } @@ -1570,13 +1166,13 @@ void dos_clean_name(char *s) pstring s1; *p = 0; - strcpy(s1,p+3); + pstrcpy(s1,p+3); if ((p=strrchr(s,'\\')) != NULL) *p = 0; else *s = 0; - strcat(s,s1); + pstrcat(s,s1); } trim_string(s,NULL,"\\.."); @@ -1596,18 +1192,25 @@ void unix_clean_name(char *s) /* remove any double slashes */ string_sub(s, "//","/"); + /* Remove leading ./ characters */ + if(strncmp(s, "./", 2) == 0) { + trim_string(s, "./", NULL); + if(*s == 0) + pstrcpy(s,"./"); + } + while ((p = strstr(s,"/../")) != NULL) { pstring s1; *p = 0; - strcpy(s1,p+3); + pstrcpy(s1,p+3); if ((p=strrchr(s,'/')) != NULL) *p = 0; else *s = 0; - strcat(s,s1); + pstrcat(s,s1); } trim_string(s,NULL,"/.."); @@ -1626,122 +1229,110 @@ int ChDir(char *path) if (*path == '/' && strcsequal(LastDir,path)) return(0); DEBUG(3,("chdir to %s\n",path)); - res = sys_chdir(path); + res = dos_chdir(path); if (!res) - strcpy(LastDir,path); + pstrcpy(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; + SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */ + SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */ + char *text; /* The pathname in DOS format. */ BOOL valid; } ino_list[MAX_GETWDCACHE]; BOOL use_getwd_cache=True; /******************************************************************* - return the absolute current directory path + return the absolute current directory path - given a UNIX pathname. + Note that this path is returned in DOS format, not UNIX + format. ********************************************************************/ char *GetWd(char *str) { pstring s; static BOOL getwd_cache_init = False; - struct stat st, st2; + SMB_STRUCT_STAT st, st2; int i; *s = 0; if (!use_getwd_cache) - return(Dumb_GetWd(str)); + return(dos_getwd(str)); /* init the cache */ if (!getwd_cache_init) + { + getwd_cache_init = True; + for (i=0;i<MAX_GETWDCACHE;i++) { - getwd_cache_init = True; - for (i=0;i<MAX_GETWDCACHE;i++) - { - string_init(&ino_list[i].text,""); - ino_list[i].valid = False; - } + 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)); - } + if (dos_stat(".",&st) == -1) + { + DEBUG(0,("Very strange, couldn't stat \".\"\n")); + return(dos_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 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; - } - } - } + if (st.st_ino == ino_list[i].inode && + st.st_dev == ino_list[i].dev) + { + if (dos_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) + { + pstrcpy (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); - } + if (!dos_getwd(s)) + { + DEBUG(0,("Getwd failed, errno %s\n",strerror(errno))); + return (NULL); + } - strcpy(str,s); + pstrcpy(str,s); DEBUG(5,("GetWd %s, inode %d, dev %x\n",s,(int)st.st_ino,(int)st.st_dev)); @@ -1774,12 +1365,12 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) #else pstring dir2; pstring wd; - pstring basename; + pstring base_name; pstring newname; char *p=NULL; BOOL relative = (*s != '/'); - *dir2 = *wd = *basename = *newname = 0; + *dir2 = *wd = *base_name = *newname = 0; if (widelinks) { @@ -1790,6 +1381,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) DEBUG(3,("Illegal file name? (%s)\n",s)); return(False); } + + if (strlen(s) == 0) + pstrcpy(s,"./"); + return(True); } @@ -1798,8 +1393,8 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) /* remove any double slashes */ string_sub(s,"//","/"); - strcpy(basename,s); - p = strrchr(basename,'/'); + pstrcpy(base_name,s); + p = strrchr(base_name,'/'); if (!p) return(True); @@ -1824,7 +1419,7 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) } - if (p && (p != basename)) + if (p && (p != base_name)) { *p = 0; if (strcmp(p+1,".")==0) @@ -1833,10 +1428,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) *p = '/'; } - if (ChDir(basename) != 0) + if (ChDir(base_name) != 0) { ChDir(wd); - DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,basename)); + DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,base_name)); return(False); } @@ -1847,10 +1442,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) return(False); } - if (p && (p != basename)) + if (p && (p != base_name)) { - strcat(newname,"/"); - strcat(newname,p+1); + pstrcat(newname,"/"); + pstrcat(newname,p+1); } { @@ -1868,18 +1463,18 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) if (relative) { if (newname[l] == '/') - strcpy(s,newname + l + 1); + pstrcpy(s,newname + l + 1); else - strcpy(s,newname+l); + pstrcpy(s,newname+l); } else - strcpy(s,newname); + pstrcpy(s,newname); } ChDir(wd); if (strlen(s) == 0) - strcpy(s,"./"); + pstrcpy(s,"./"); DEBUG(3,("reduced to %s\n",s)); return(True); @@ -1897,14 +1492,34 @@ static void expand_one(char *Mask,int len) int lfill = (len+1) - strlen(Mask); int l1= (p1 - Mask); pstring tmp; - strcpy(tmp,Mask); + pstrcpy(tmp,Mask); memset(tmp+l1,'?',lfill); - strcpy(tmp + l1 + lfill,Mask + l1 + 1); - strcpy(Mask,tmp); + pstrcpy(tmp + l1 + lfill,Mask + l1 + 1); + pstrcpy(Mask,tmp); } } /**************************************************************************** +parse out a directory name from a path name. Assumes dos style filenames. +****************************************************************************/ +static char *dirname_dos(char *path,char *buf) +{ + char *p = strrchr(path,'\\'); + + if (!p) + pstrcpy(buf,path); + else + { + *p = 0; + pstrcpy(buf,path); + *p = '\\'; + } + + return(buf); +} + + +/**************************************************************************** expand a wildcard expression, replacing *s with ?s ****************************************************************************/ void expand_mask(char *Mask,BOOL doext) @@ -1924,42 +1539,42 @@ void expand_mask(char *Mask,BOOL doext) filename_dos(Mask,filepart); - strcpy(mbeg,filepart); + pstrcpy(mbeg,filepart); if ((p1 = strchr(mbeg,'.')) != NULL) { hasdot = True; *p1 = 0; p1++; - strcpy(mext,p1); + pstrcpy(mext,p1); } else { - strcpy(mext,""); + pstrcpy(mext,""); if (strlen(mbeg) > 8) { - strcpy(mext,mbeg + 8); + pstrcpy(mext,mbeg + 8); mbeg[8] = 0; } } if (*mbeg == 0) - strcpy(mbeg,"????????"); + pstrcpy(mbeg,"????????"); if ((*mext == 0) && doext && !hasdot) - strcpy(mext,"???"); + pstrcpy(mext,"???"); if (strequal(mbeg,"*") && *mext==0) - strcpy(mext,"*"); + pstrcpy(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); + pstrcpy(Mask,dirpart); + if (*dirpart || absolute) pstrcat(Mask,"\\"); + pstrcat(Mask,mbeg); + pstrcat(Mask,"."); + pstrcat(Mask,mext); DEBUG(6,("Mask expanded to [%s]\n",Mask)); } @@ -1971,21 +1586,44 @@ does a string have any uppercase chars in it? BOOL strhasupper(char *s) { while (*s) + { +#if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + + if(lp_client_code_page() == KANJI_CODEPAGE) { -#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 */ + /* Win95 treats full width ascii characters as case sensitive. */ + if (is_shift_jis (*s)) + s += 2; + else if (is_kana (*s)) + s++; + else + { + if (isupper(*s)) + return(True); + s++; + } } + else +#endif /* KANJI_WIN95_COMPATIBILITY */ + { + int skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else { + if (isupper(*s)) + return(True); + s++; + } + } + } return(False); } @@ -1995,21 +1633,52 @@ does a string have any lowercase chars in it? BOOL strhaslower(char *s) { while (*s) + { +#if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + + if(lp_client_code_page() == KANJI_CODEPAGE) { -#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 */ + /* Win95 treats full width ascii characters as case sensitive. */ + if (is_shift_jis (*s)) + { + if (is_sj_upper (s[0], s[1])) + return(True); + if (is_sj_lower (s[0], s[1])) + return (True); + s += 2; + } + else if (is_kana (*s)) + { + s++; + } + else + { + if (islower(*s)) + return(True); + s++; + } + } + else +#endif /* KANJI_WIN95_COMPATIBILITY */ + { + int skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else { + if (islower(*s)) + return(True); + s++; + } } + } return(False); } @@ -2019,12 +1688,47 @@ find the number of chars in a string int count_chars(char *s,char c) { int count=0; - while (*s) + +#if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + + if(lp_client_code_page() == KANJI_CODEPAGE) + { + /* Win95 treats full width ascii characters as case sensitive. */ + while (*s) { - if (*s == c) - count++; - s++; + if (is_shift_jis (*s)) + s += 2; + else + { + if (*s == c) + count++; + s++; + } } + } + else +#endif /* KANJI_WIN95_COMPATIBILITY */ + { + while (*s) + { + int skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else { + if (*s == c) + count++; + s++; + } + } + } return(count); } @@ -2032,12 +1736,12 @@ int count_chars(char *s,char c) /**************************************************************************** make a dir struct ****************************************************************************/ -void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode,time_t date) +void make_dir_struct(char *buf,char *mask,char *fname,SMB_OFF_T size,int mode,time_t date) { char *p; pstring mask2; - strcpy(mask2,mask); + pstrcpy(mask2,mask); if ((mode & aDIR) != 0) size = 0; @@ -2057,7 +1761,7 @@ void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode CVAL(buf,21) = mode; put_dos_date(buf,22,date); SSVAL(buf,26,size & 0xFFFF); - SSVAL(buf,28,size >> 16); + SSVAL(buf,28,(size >> 16)&0xFFFF); StrnCpy(buf+30,fname,12); if (!case_sensitive) strupper(buf+30); @@ -2089,57 +1793,15 @@ void close_low_fds(void) } } - -/**************************************************************************** -write to a socket -****************************************************************************/ -int write_socket(int fd,char *buf,int len) -{ - int ret=0; - - if (passive) - return(len); - DEBUG(6,("write_socket(%d,%d)\n",fd,len)); - ret = write_data(fd,buf,len); - - DEBUG(6,("write_socket(%d,%d) wrote %d\n",fd,len,ret)); - return(ret); -} - -/**************************************************************************** -read from a socket -****************************************************************************/ -int read_udp_socket(int fd,char *buf,int len) -{ - int ret; - struct sockaddr sock; - int socklen; - - socklen = sizeof(sock); - bzero((char *)&sock,socklen); - bzero((char *)&lastip,sizeof(lastip)); - ret = recvfrom(fd,buf,len,0,&sock,&socklen); - if (ret <= 0) - { - DEBUG(2,("read socket failed. ERRNO=%d\n",errno)); - return(0); - } - - lastip = *(struct in_addr *) &sock.sa_data[2]; - lastport = ntohs(((struct sockaddr_in *)&sock)->sin_port); - - return(ret); -} - /**************************************************************************** Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available, else if SYSV use O_NDELAY if BSD use FNDELAY ****************************************************************************/ -int set_blocking(int fd, BOOL set) +static int set_blocking(int fd, BOOL set) { -int val; + int val; #ifdef O_NONBLOCK #define FLAG_TO_SET O_NONBLOCK #else @@ -2150,7 +1812,7 @@ int val; #endif #endif - if((val = fcntl(fd, F_GETFL, 0))==-1) + if((val = fcntl(fd, F_GETFL, 0)) == -1) return -1; if(set) /* Turn blocking on - ie. clear nonblock flag */ val &= ~FLAG_TO_SET; @@ -2162,178 +1824,158 @@ int val; /**************************************************************************** -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 +write to a socket ****************************************************************************/ -static int tval_sub( struct timeval *retval, struct timeval *val1, struct timeval *val2) +ssize_t write_socket(int fd,char *buf,size_t len) { - int usecdiff = val1->tv_usec - val2->tv_usec; - int secdiff = val1->tv_sec - val2->tv_sec; - if(usecdiff < 0) { - usecdiff = 1000000 + usecdiff; - secdiff--; + ssize_t 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)); + if(ret <= 0) + DEBUG(0,("write_socket: Error writing %d bytes to socket %d: ERRNO = %s\n", + len, fd, strerror(errno) )); + + return(ret); +} + +/**************************************************************************** +read from a socket +****************************************************************************/ +ssize_t read_udp_socket(int fd,char *buf,size_t len) +{ + ssize_t ret; + struct sockaddr_in sock; + int socklen; + + socklen = sizeof(sock); + bzero((char *)&sock,socklen); + bzero((char *)&lastip,sizeof(lastip)); + ret = (ssize_t)recvfrom(fd,buf,len,0,(struct sockaddr *)&sock,&socklen); + if (ret <= 0) { + DEBUG(2,("read socket failed. ERRNO=%s\n",strerror(errno))); + return(0); } - 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); + + lastip = sock.sin_addr; + lastport = ntohs(sock.sin_port); + + DEBUG(10,("read_udp_socket: lastip %s lastport %d read: %d\n", + inet_ntoa(lastip), lastport, ret)); + + return(ret); } /**************************************************************************** read data from a device with a timout in msec. mincount = if timeout, minimum to read before returning maxcount = number to be read. +time_out = timeout in milliseconds ****************************************************************************/ -int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact) + +ssize_t read_with_timeout(int fd,char *buf,size_t mincnt,size_t maxcnt,unsigned int time_out) { fd_set fds; int selrtn; - int readret; - int nread = 0; - struct timeval timeout, tval1, tval2, tvaldiff; - int error_limit = 5; + ssize_t readret; + size_t nread = 0; + struct timeval timeout; /* just checking .... */ if (maxcnt <= 0) return(0); - if(time_out == -2) - time_out = DEFAULT_PIPE_TIMEOUT; + smb_read_error = 0; /* Blocking read */ - if(time_out < 0) { + 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; + while (nread < mincnt) { +#ifdef WITH_SSL + if(fd == sslFd){ + readret = SSL_read(ssl, buf + nread, maxcnt - nread); + }else{ + readret = read(fd, buf + nread, maxcnt - nread); + } +#else /* WITH_SSL */ + readret = read(fd, buf + nread, maxcnt - nread); +#endif /* WITH_SSL */ + + if (readret == 0) { + smb_read_error = READ_EOF; + return -1; } - return(nread); + + if (readret == -1) { + smb_read_error = READ_ERROR; + return -1; + } + nread += readret; + } + return((ssize_t)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 */ + mincnt is greater then the filesize then + system performance will suffer severely as + select always returns true on disk files */ /* Set initial timeout */ - timeout.tv_sec = time_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); - } + timeout.tv_sec = (time_t)(time_out / 1000); + timeout.tv_usec = (long)(1000 * (time_out % 1000)); - 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; + for (nread=0; nread < mincnt; ) + { + FD_ZERO(&fds); + FD_SET(fd,&fds); - /* 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); + selrtn = sys_select(fd+1,&fds,&timeout); + + /* Check if error */ + if(selrtn == -1) { + /* something is wrong. Maybe the socket is dead? */ + smb_read_error = READ_ERROR; + return -1; + } - if (tval_sub(&timeout, &timeout, &tvaldiff) <= 0) - break; /* We timed out */ - } + /* Did we timeout ? */ + if (selrtn == 0) { + smb_read_error = READ_TIMEOUT; + return -1; + } - /* Save the time of day as we need to do the select - again (saves a system call) */ - tval1 = tval2; +#ifdef WITH_SSL + if(fd == sslFd){ + readret = SSL_read(ssl, buf + nread, maxcnt - nread); + }else{ + readret = read(fd, buf + nread, maxcnt - nread); } +#else /* WITH_SSL */ + readret = read(fd, buf+nread, maxcnt-nread); +#endif /* WITH_SSL */ - /* 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; + if (readret == 0) { + /* we got EOF on the file descriptor */ + smb_read_error = READ_EOF; + return -1; + } - nread = read_udp_socket(fd, buffer, bufsize); + if (readret == -1) { + /* the descriptor is probably dead */ + smb_read_error = READ_ERROR; + return -1; + } + + nread += readret; + } - /* return the number got */ - return(nread); + /* Return the number we got */ + return((ssize_t)nread); } /******************************************************************* @@ -2364,184 +2006,92 @@ BOOL send_keepalive(int client) /**************************************************************************** read data from the client, reading exactly N bytes. ****************************************************************************/ -int read_data(int fd,char *buffer,int N) +ssize_t read_data(int fd,char *buffer,size_t N) { - int ret; - int total=0; + ssize_t ret; + size_t total=0; + smb_read_error = 0; + while (total < N) - { + { +#ifdef WITH_SSL + if(fd == sslFd){ + ret = SSL_read(ssl, buffer + total, N - total); + }else{ ret = read(fd,buffer + total,N - total); - - /* this is for portability */ - if (ret < 0) - errno = EBADF; - - if (ret <= 0) - return total; - total += ret; } - return total; -} +#else /* WITH_SSL */ + ret = read(fd,buffer + total,N - total); +#endif /* WITH_SSL */ - -/**************************************************************************** - write data to a fd -****************************************************************************/ -int write_data(int fd,char *buffer,int N) -{ - int total=0; - int ret; - - while (total < N) + if (ret == 0) { - ret = write(fd,buffer + total,N - total); - - if (ret <= 0) - return total; - - total += ret; + smb_read_error = READ_EOF; + return 0; } - 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) + if (ret == -1) { - 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)); + smb_read_error = READ_ERROR; + return -1; } - - 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; + total += ret; } - - if (ret < 0) ret = 0; - - return(ret); + return (ssize_t)total; } + /**************************************************************************** -pre-read some data + write data to a fd ****************************************************************************/ -void do_read_prediction() +ssize_t write_data(int fd,char *buffer,size_t N) { - 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; + size_t total=0; + ssize_t ret; - 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; - } + while (total < N) + { +#ifdef WITH_SSL + if(fd == sslFd){ + ret = SSL_write(ssl,buffer + total,N - total); + }else{ + ret = write(fd,buffer + total,N - total); } +#else /* WITH_SSL */ + ret = write(fd,buffer + total,N - total); +#endif /* WITH_SSL */ - if (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; -} + if (ret == -1) return -1; + if (ret == 0) return total; -/**************************************************************************** -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; + total += ret; + } + return (ssize_t)total; } /**************************************************************************** transfer some data between two fd's ****************************************************************************/ -int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align) +SMB_OFF_T transfer_file(int infd,int outfd,SMB_OFF_T n,char *header,int headlen,int align) { static char *buf=NULL; + static int size=0; char *buf1,*abuf; - static int size = 0; - int total = 0; + SMB_OFF_T total = 0; - DEBUG(4,("transfer_file %d (head=%d) called\n",n,headlen)); + DEBUG(4,("transfer_file n=%.0f (head=%d) called\n",(double)n,headlen)); - if ((size < ReadSize) && buf) { - free(buf); - buf = NULL; + if (size == 0) { + size = lp_readsize(); + size = MAX(size,1024); } - 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); @@ -2553,159 +2103,195 @@ int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align) n += headlen; while (n > 0) - { - int s = MIN(n,size); - int ret,ret2=0; + { + int s = (int)MIN(n,(SMB_OFF_T)size); + int ret,ret2=0; - ret = 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 >= 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 (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 (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; + 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 +store the result in the buffer +This version of the function will return a length of zero on receiving +a keepalive packet. +timeout is in milliseconds. ****************************************************************************/ -int read_smb_length(int fd,char *inbuf,int timeout) +static ssize_t read_smb_length_return_keepalive(int fd,char *inbuf,unsigned int timeout) { - char *buffer; - char buf[4]; - int len=0, msg_type; - BOOL ok=False; - - if (inbuf) - buffer = inbuf; - else - buffer = buf; + ssize_t len=0; + int msg_type; + BOOL ok = False; 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 (timeout > 0) + ok = (read_with_timeout(fd,inbuf,4,4,timeout) == 4); + else + ok = (read_data(fd,inbuf,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); - } - } + if (!ok) + return(-1); - len = smb_len(buffer); - msg_type = CVAL(buffer,0); + len = smb_len(inbuf); + msg_type = CVAL(inbuf,0); - if (msg_type == 0x85) - { - DEBUG(5,( "Got keepalive packet\n")); - ok = False; - } - } + if (msg_type == 0x85) + DEBUG(5,("Got keepalive packet\n")); + } DEBUG(10,("got smb length of %d\n",len)); return(len); } +/**************************************************************************** +read 4 bytes of a smb packet and return the smb length of the packet +store the result in the buffer. This version of the function will +never return a session keepalive (length of zero). +timeout is in milliseconds. +****************************************************************************/ +ssize_t read_smb_length(int fd,char *inbuf,unsigned int timeout) +{ + ssize_t len; + for(;;) + { + len = read_smb_length_return_keepalive(fd, inbuf, timeout); + + if(len < 0) + return len; + + /* Ignore session keepalives. */ + if(CVAL(inbuf,0) != 0x85) + break; + } + + return len; +} /**************************************************************************** - read an smb from a fd and return it's length -The timeout is in milli seconds + read an smb from a fd. Note that the buffer *MUST* be of size + BUFFER_SIZE+SAFETY_MARGIN. + The timeout is in milliseconds. + This function will return on a + receipt of a session keepalive packet. ****************************************************************************/ -BOOL receive_smb(int fd,char *buffer,int timeout) +BOOL receive_smb(int fd,char *buffer, unsigned int timeout) { - int len; - BOOL ok; + ssize_t len,ret; + + smb_read_error = 0; bzero(buffer,smb_size + 100); - len = read_smb_length(fd,buffer,timeout); - if (len == -1) + len = read_smb_length_return_keepalive(fd,buffer,timeout); + if (len < 0) 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(); + if (len > BUFFER_SIZE) { + DEBUG(0,("Invalid packet length! (%d bytes).\n",len)); + if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) exit(1); - } + } + if(len > 0) { + ret = read_data(fd,buffer+4,len); + if (ret != len) { + smb_read_error = READ_ERROR; + return False; + } + } return(True); } +/**************************************************************************** + read an smb from a fd ignoring all keepalive packets. Note that the buffer + *MUST* be of size BUFFER_SIZE+SAFETY_MARGIN. + The timeout is in milliseconds + + This is exactly the same as receive_smb except that it never returns + a session keepalive packet (just as receive_smb used to do). + receive_smb was changed to return keepalives as the oplock processing means this call + should never go into a blocking read. +****************************************************************************/ + +BOOL client_receive_smb(int fd,char *buffer, unsigned int timeout) +{ + BOOL ret; + + for(;;) + { + ret = receive_smb(fd, buffer, timeout); + + if(ret == False) + return ret; + + /* Ignore session keepalive packets. */ + if(CVAL(buffer,0) != 0x85) + break; + } + return ret; +} /**************************************************************************** send an smb to a fd ****************************************************************************/ BOOL send_smb(int fd,char *buffer) { - int len; - int ret,nwritten=0; + size_t len; + size_t nwritten=0; + ssize_t ret; len = smb_len(buffer) + 4; while (nwritten < len) + { + ret = write_socket(fd,buffer+nwritten,len - nwritten); + if (ret <= 0) { - ret = write_socket(fd,buffer+nwritten,len - nwritten); - if (ret <= 0) - { - DEBUG(0,("Error writing %d bytes to client. %d. Exiting\n",len,ret)); - close_sockets(); - exit(1); - } - nwritten += ret; + DEBUG(0,("Error writing %d bytes to client. %d. Exiting\n",len,ret)); + close_sockets(); + exit(1); } - + nwritten += ret; + } return True; } @@ -2714,7 +2300,7 @@ BOOL send_smb(int fd,char *buffer) /**************************************************************************** find a pointer to a netbios name ****************************************************************************/ -char *name_ptr(char *buf,int ofs) +static char *name_ptr(char *buf,int ofs) { unsigned char c = *(unsigned char *)(buf+ofs); @@ -2739,24 +2325,30 @@ int name_extract(char *buf,int ofs,char *name) { char *p = name_ptr(buf,ofs); int d = PTR_DIFF(p,buf+ofs); - strcpy(name,""); + pstrcpy(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) +int name_len( char *s ) { - char *s0=s; - unsigned char c = *(unsigned char *)s; - if ((c & 0xC0) == 0xC0) + int len; + + /* If the two high bits of the byte are set, return 2. */ + if( 0xC0 == (*(unsigned char *)s & 0xC0) ) return(2); - while (*s) s += (*s)+1; - return(PTR_DIFF(s,s0)+1); -} + + /* Add up the length bytes. */ + for( len = 1; (*s); s += (*s) + 1 ) + { + len += *s + 1; + } + + return( len ); +} /* name_len */ /**************************************************************************** send a single packet to a port on another machine @@ -2792,8 +2384,8 @@ BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type) 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)); + DEBUG(0,("Packet send to %s(%d) failed ERRNO=%s\n", + inet_ntoa(ip),port,strerror(errno))); close(out_fd); return(ret); @@ -2802,7 +2394,7 @@ BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type) /******************************************************************* sleep for a specified number of milliseconds ********************************************************************/ -void msleep(int t) +static void msleep(int t) { int tdiff=0; struct timeval tval,t1,t2; @@ -2817,7 +2409,7 @@ void msleep(int t) FD_ZERO(&fds); errno = 0; - sys_select(&fds,&tval); + sys_select(0,&fds,&tval); GetTimeOfDay(&t2); tdiff = TvalDiff(&t1,&t2); @@ -2834,16 +2426,15 @@ BOOL in_list(char *s,char *list,BOOL casesensitive) 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); - } + while (next_token(&p,tok,LIST_SEP,sizeof(tok))) { + if (casesensitive) { + if (strcmp(tok,s) == 0) + return(True); + } else { + if (StrCaseCmp(tok,s) == 0) + return(True); } + } return(False); } @@ -2863,16 +2454,24 @@ BOOL string_init(char **dest,char *src) if (l == 0) { - if (!null_string) - null_string = (char *)malloc(1); - - *null_string = 0; + if (!null_string) { + if((null_string = (char *)malloc(1)) == NULL) { + DEBUG(0,("string_init: malloc fail for null_string.\n")); + return False; + } + *null_string = 0; + } *dest = null_string; } else { - *dest = (char *)malloc(l+1); - strcpy(*dest,src); + (*dest) = (char *)malloc(l+1); + if ((*dest) == NULL) { + DEBUG(0,("Out of memory in string_init\n")); + return False; + } + + pstrcpy(*dest,src); } return(True); } @@ -2934,13 +2533,12 @@ BOOL string_sub(char *s,char *pattern,char *insert) return(ret); } - - /********************************************************* -* Recursive routine that is called by mask_match. -* Does the actual matching. +* Recursive routine that is called by unix_mask_match. +* Does the actual matching. This is the 'original code' +* used by the unix matcher. *********************************************************/ -BOOL do_match(char *str, char *regexp, int case_sig) +static BOOL unix_do_match(char *str, char *regexp, int case_sig) { char *p; @@ -2959,7 +2557,7 @@ BOOL do_match(char *str, char *regexp, int case_sig) while(*str) { while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str)))) str++; - if(do_match(str,p,case_sig)) + if(unix_do_match(str,p,case_sig)) return True; if(!*str) return False; @@ -3002,8 +2600,10 @@ BOOL do_match(char *str, char *regexp, int case_sig) * Routine to match a given string with a regexp - uses * simplified regexp that takes * and ? only. Case can be * significant or not. +* This is the 'original code' used by the unix matcher. *********************************************************/ -BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2) + +static BOOL unix_mask_match(char *str, char *regexp, int case_sig,BOOL trans2) { char *p; pstring p1, p2; @@ -3016,301 +2616,365 @@ BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2) StrnCpy(p2,str,sizeof(pstring)-1); if (!strchr(p2,'.')) { - strcat(p2,"."); - } - -/* - if (!strchr(p1,'.')) { - strcat(p1,"."); + pstrcat(p2,"."); } -*/ - -#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]); + (void)pstrcpy( &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)); + DEBUG(8,("unix_mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig)); if (trans2) { - strcpy(ebase,p1); - strcpy(sbase,p2); + fstrcpy(ebase,p1); + fstrcpy(sbase,p2); } else { if ((p=strrchr(p1,'.'))) { *p = 0; - strcpy(ebase,p1); - strcpy(eext,p+1); + fstrcpy(ebase,p1); + fstrcpy(eext,p+1); } else { - strcpy(ebase,p1); + fstrcpy(ebase,p1); eext[0] = 0; } if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) { *p = 0; - strcpy(sbase,p2); - strcpy(sext,p+1); + fstrcpy(sbase,p2); + fstrcpy(sext,p+1); } else { - strcpy(sbase,p2); - strcpy(sext,""); + fstrcpy(sbase,p2); + fstrcpy(sext,""); } } - matched = do_match(sbase,ebase,case_sig) && - (trans2 || do_match(sext,eext,case_sig)); + matched = unix_do_match(sbase,ebase,case_sig) && + (trans2 || unix_do_match(sext,eext,case_sig)); - DEBUG(5,("mask_match returning %d\n", matched)); + DEBUG(8,("unix_mask_match returning %d\n", matched)); return matched; } +/********************************************************* +* Recursive routine that is called by mask_match. +* Does the actual matching. Returns True if matched, +* False if failed. This is the 'new' NT style matcher. +*********************************************************/ - -/**************************************************************************** -become a daemon, discarding the controlling terminal -****************************************************************************/ -void become_daemon(void) +BOOL do_match(char *str, char *regexp, int case_sig) { -#ifndef NO_FORK_DEBUG - if (fork()) - exit(0); + char *p; - /* 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); + 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++; + /* Now eat all characters that match, as + we want the *last* character to match. */ + while(*str && (case_sig ? (*p == *str) : (toupper(*p)==toupper(*str)))) + str++; + str--; /* We've eaten the match char after the '*' */ + 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; + } } -#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; + if(!*p && !*str) + return True; + + if (!*p && str[0] == '.' && str[1] == 0) { + return(True); } - inm->s_addr = htonl(nm); + + if (!*str && *p == '?') { + while (*p == '?') + p++; + return(!*p); + } + + if(!*str && (*p == '*' && p[1] == '\0')) { + return True; + } + + return False; } -/**************************************************************************** - 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 +/********************************************************* +* Routine to match a given string with a regexp - uses +* simplified regexp that takes * and ? only. Case can be +* significant or not. +* The 8.3 handling was rewritten by Ums Harald <Harald.Ums@pro-sieben.de> +* This is the new 'NT style' matcher. +*********************************************************/ - /* get a default netmask and broadcast */ - default_netmask(if_nmask, if_ipaddr); +BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2) +{ + char *p; + pstring t_pattern, t_filename, te_pattern, te_filename; + fstring ebase,eext,sbase,sext; -#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) + BOOL matched = False; + + /* Make local copies of str and regexp */ + pstrcpy(t_pattern,regexp); + pstrcpy(t_filename,str); + +#if 0 + /* + * Not sure if this is a good idea. JRA. + */ + if(trans2 && is_8_3(t_pattern,False) && is_8_3(t_filename,False)) + trans2 = False; #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 0 + if (!strchr(t_filename,'.')) { + pstrcat(t_filename,"."); + } +#endif - if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) - DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno))); - else { - ifr = ifc.ifc_req; + /* Remove any *? and ** as they are meaningless */ + string_sub(t_pattern, "*?", "*"); + string_sub(t_pattern, "**", "*"); - 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; - } - } + if (strequal(t_pattern,"*")) + return(True); + + DEBUG(8,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", t_filename, t_pattern, case_sig)); + + if(trans2) { + /* + * Match each component of the regexp, split up by '.' + * characters. + */ + char *fp, *rp, *cp2, *cp1; + BOOL last_wcard_was_star = False; + int num_path_components, num_regexp_components; + + pstrcpy(te_pattern,t_pattern); + pstrcpy(te_filename,t_filename); + /* + * Remove multiple "*." patterns. + */ + string_sub(te_pattern, "*.*.", "*."); + num_regexp_components = count_chars(te_pattern, '.'); + num_path_components = count_chars(te_filename, '.'); + + /* + * Check for special 'hack' case of "DIR a*z". - needs to match a.b.c...z + */ + if(num_regexp_components == 0) + matched = do_match( te_filename, te_pattern, case_sig); + else { + for( cp1 = te_pattern, cp2 = te_filename; cp1;) { + fp = strchr(cp2, '.'); + if(fp) + *fp = '\0'; + rp = strchr(cp1, '.'); + if(rp) + *rp = '\0'; + + if(cp1[strlen(cp1)-1] == '*') + last_wcard_was_star = True; + else + last_wcard_was_star = False; + + if(!do_match(cp2, cp1, case_sig)) + break; + + cp1 = rp ? rp + 1 : NULL; + cp2 = fp ? fp + 1 : ""; + + if(last_wcard_was_star || ((cp1 != NULL) && (*cp1 == '*'))) { + /* Eat the extra path components. */ + int i; + + for(i = 0; i < num_path_components - num_regexp_components; i++) { + fp = strchr(cp2, '.'); + if(fp) + *fp = '\0'; + + if((cp1 != NULL) && do_match( cp2, cp1, case_sig)) { + cp2 = fp ? fp + 1 : ""; + break; + } + cp2 = fp ? fp + 1 : ""; + } + num_path_components -= i; + } + } + if(cp1 == NULL && ((*cp2 == '\0') || last_wcard_was_star)) + matched = True; } - } -#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; + + /* ------------------------------------------------- + * Behaviour of Win95 + * for 8.3 filenames and 8.3 Wildcards + * ------------------------------------------------- + */ + if (strequal (t_filename, ".")) { + /* + * Patterns: *.* *. ?. ? are valid + * + */ + if(strequal(t_pattern, "*.*") || strequal(t_pattern, "*.") || + strequal(t_pattern, "?.") || strequal(t_pattern, "?")) + matched = True; + } else if (strequal (t_filename, "..")) { + /* + * Patterns: *.* *. ?. ? *.? are valid + * + */ + if(strequal(t_pattern, "*.*") || strequal(t_pattern, "*.") || + strequal(t_pattern, "?.") || strequal(t_pattern, "?") || + strequal(t_pattern, "*.?") || strequal(t_pattern, "?.*")) + matched = True; + } else { + + if ((p = strrchr (t_pattern, '.'))) { + /* + * Wildcard has a suffix. + */ + *p = 0; + fstrcpy (ebase, t_pattern); + if (p[1]) { + fstrcpy (eext, p + 1); + } else { + /* pattern ends in DOT: treat as if there is no DOT */ + *eext = 0; + if (strequal (ebase, "*")) + return (True); + } + } else { + /* + * No suffix for wildcard. + */ + fstrcpy (ebase, t_pattern); + eext[0] = 0; } - } - } -#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; + + p = strrchr (t_filename, '.'); + if (p && (p[1] == 0) ) { + /* + * Filename has an extension of '.' only. + */ + *p = 0; /* nuke dot at end of string */ + p = 0; /* and treat it as if there is no extension */ } - 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; + + if (p) { + /* + * Filename has an extension. + */ + *p = 0; + fstrcpy (sbase, t_filename); + fstrcpy (sext, p + 1); + if (*eext) { + matched = do_match(sbase, ebase, case_sig) + && do_match(sext, eext, case_sig); + } else { + /* pattern has no extension */ + /* Really: match complete filename with pattern ??? means exactly 3 chars */ + matched = do_match(str, ebase, case_sig); + } + } else { + /* + * Filename has no extension. + */ + fstrcpy (sbase, t_filename); + fstrcpy (sext, ""); + if (*eext) { + /* pattern has extension */ + matched = do_match(sbase, ebase, case_sig) + && do_match(sext, eext, case_sig); + } else { + matched = do_match(sbase, ebase, case_sig); +#ifdef EMULATE_WEIRD_W95_MATCHING + /* + * Even Microsoft has some problems + * Behaviour Win95 -> local disk + * is different from Win95 -> smb drive from Nt 4.0 + * This branch would reflect the Win95 local disk behaviour + */ + if (!matched) { + /* a? matches aa and a in w95 */ + fstrcat (sbase, "."); + matched = do_match(sbase, ebase, case_sig); + } #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))); - } + DEBUG(8,("mask_match returning %d\n", matched)); - /* Close up shop */ - (void) close(sock); - -#endif + return matched; +} - /* 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); - } - } +/**************************************************************************** +become a daemon, discarding the controlling terminal +****************************************************************************/ +void become_daemon(void) +{ + if (fork()) { + _exit(0); + } - /* 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 */ + /* detach from the terminal */ +#ifdef HAVE_SETSID + setsid(); +#elif defined(TIOCNOTTY) + { + int i = open("/dev/tty", O_RDWR); + if (i != -1) { + ioctl(i, (int) TIOCNOTTY, (char *)0); + close(i); + } + } +#endif /* HAVE_SETSID */ + + /* Close fd's 0,1,2. Needed if started by rsh */ + close_low_fds(); +} /**************************************************************************** @@ -3402,18 +3066,18 @@ char *fgets_slash(char *s2,int maxlen,FILE *f) set the length of a file from a filedescriptor. Returns 0 on success, -1 on failure. ****************************************************************************/ -int set_filelen(int fd, long len) +int set_filelen(int fd, SMB_OFF_T 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); +#ifdef HAVE_FTRUNCATE_EXTEND + return sys_ftruncate(fd, len); #else - struct stat st; + SMB_STRUCT_STAT st; char c = 0; - long currpos = lseek(fd, 0L, SEEK_CUR); + SMB_OFF_T currpos = sys_lseek(fd, (SMB_OFF_T)0, SEEK_CUR); if(currpos < 0) return -1; @@ -3421,7 +3085,7 @@ int set_filelen(int fd, long len) 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) + if(sys_fstat(fd, &st)<0) return -1; #ifdef S_ISFIFO @@ -3431,38 +3095,24 @@ int set_filelen(int fd, long len) if(st.st_size == len) return 0; if(st.st_size > len) - return ftruncate(fd, len); + return sys_ftruncate(fd, len); - if(lseek(fd, len-1, SEEK_SET) != len -1) + if(sys_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); + sys_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) + void setbuffer(FILE *f,char *buf,int bufsize) { setvbuf(f,buf,_IOFBF,bufsize); } @@ -3470,26 +3120,6 @@ void setbuffer(FILE *f,char *buf,int bufsize) /**************************************************************************** -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) @@ -3497,9 +3127,9 @@ static char *filename_dos(char *path,char *buf) char *p = strrchr(path,'\\'); if (!p) - strcpy(buf,path); + pstrcpy(buf,path); else - strcpy(buf,p+1); + pstrcpy(buf,p+1); return(buf); } @@ -3509,9 +3139,16 @@ static char *filename_dos(char *path,char *buf) /**************************************************************************** expand a pointer to be a particular size ****************************************************************************/ -void *Realloc(void *p,int size) +void *Realloc(void *p,size_t size) { void *ret=NULL; + + if (size == 0) { + if (p) free(p); + DEBUG(5,("Realloc asked for 0 bytes\n")); + return NULL; + } + if (!p) ret = (void *)malloc(size); else @@ -3523,138 +3160,11 @@ void *Realloc(void *p,int 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,×)) { - 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) +BOOL get_myname(char *my_name,struct in_addr *ip) { struct hostent *hp; pstring hostname; @@ -3671,17 +3181,17 @@ BOOL get_myname(char *myname,struct in_addr *ip) /* get host info */ if ((hp = Get_Hostbyname(hostname)) == 0) { - DEBUG(0,( "Get_Hostbyname: Unknown host %s.\n",hostname)); + DEBUG(0,( "Get_Hostbyname: Unknown host %s\n",hostname)); return False; } - if (myname) + if (my_name) { /* split off any parts after an initial . */ char *p = strchr(hostname,'.'); if (p) *p = 0; - strcpy(myname,hostname); + fstrcpy(my_name,hostname); } if (ip) @@ -3696,7 +3206,7 @@ true if two IP addresses are equal ****************************************************************************/ BOOL ip_equal(struct in_addr ip1,struct in_addr ip2) { - unsigned long a1,a2; + uint32 a1,a2; a1 = ntohl(ip1.s_addr); a2 = ntohl(ip2.s_addr); return(a1 == a2); @@ -3706,7 +3216,7 @@ BOOL ip_equal(struct in_addr ip1,struct in_addr ip2) /**************************************************************************** open a socket of the specified type, port and address for incoming data ****************************************************************************/ -int open_socket_in(int type, int port, int dlevel) +int open_socket_in(int type, int port, int dlevel,uint32 socket_addr) { struct hostent *hp; struct sockaddr_in sock; @@ -3714,28 +3224,25 @@ int open_socket_in(int type, int port, int dlevel) 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)); + 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 */ + +#ifdef HAVE_SOCK_SIN_LEN sock.sin_len = sizeof(sock); #endif sock.sin_port = htons( port ); sock.sin_family = hp->h_addrtype; - sock.sin_addr.s_addr = INADDR_ANY; + sock.sin_addr.s_addr = socket_addr; res = socket(hp->h_addrtype, type, 0); if (res == -1) { DEBUG(0,("socket failed\n")); return -1; } @@ -3749,16 +3256,16 @@ int open_socket_in(int type, int port, int dlevel) 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))); + if (port == SMB_PORT || port == NMB_PORT) + DEBUG(dlevel,("bind failed on port %d socket_addr=%s (%s)\n", + port,inet_ntoa(sock.sin_addr),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(open_socket_in(type,port+1,dlevel,socket_addr)); } return(-1); @@ -3772,10 +3279,12 @@ int open_socket_in(int type, int port, int dlevel) /**************************************************************************** create an outgoing socket **************************************************************************/ -int open_socket_out(int type, struct in_addr *addr, int port ) +int open_socket_out(int type, struct in_addr *addr, int port ,int timeout) { struct sockaddr_in sock_out; - int res; + int res,ret; + int connect_loop = 250; /* 250 milliseconds */ + int loops = (timeout * 1000) / connect_loop; /* create a socket to write to */ res = socket(PF_INET, type, 0); @@ -3790,15 +3299,46 @@ int open_socket_out(int type, struct in_addr *addr, int port ) sock_out.sin_port = htons( port ); sock_out.sin_family = PF_INET; + /* set it non-blocking */ + set_blocking(res,False); + DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port)); /* and connect it to the destination */ - if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))<0) { - DEBUG(0,("connect error: %s\n",strerror(errno))); - close(res); - return(-1); +connect_again: + ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out)); + + /* Some systems return EAGAIN when they mean EINPROGRESS */ + if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY || + errno == EAGAIN) && loops--) { + msleep(connect_loop); + goto connect_again; } + if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY || + errno == EAGAIN)) { + DEBUG(1,("timeout connecting to %s:%d\n",inet_ntoa(*addr),port)); + close(res); + return -1; + } + +#ifdef EISCONN + if (ret < 0 && errno == EISCONN) { + errno = 0; + ret = 0; + } +#endif + + if (ret < 0) { + DEBUG(1,("error connecting to %s:%d (%s)\n", + inet_ntoa(*addr),port,strerror(errno))); + close(res); + return -1; + } + + /* set it blocking again */ + set_blocking(res,True); + return res; } @@ -3826,48 +3366,42 @@ int interpret_protocol(char *str,int def) 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) +uint32 interpret_addr(char *str) { struct hostent *hp; - unsigned long res; + uint32 res; + int i; + BOOL pure_address = True; if (strcmp(str,"0.0.0.0") == 0) return(0); if (strcmp(str,"255.255.255.255") == 0) return(0xFFFFFFFF); + for (i=0; pure_address && str[i]; i++) + if (!(isdigit((int)str[i]) || str[i] == '.')) + pure_address = False; + /* if it's in the form of an IP address then get the lib to interpret it */ - if (isdigit(str[0])) { + if (pure_address) { res = inet_addr(str); } else { - /* otherwise assume it's a network name of some sort and use Get_Hostbyname */ + /* 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; } + if(hp->h_addr == NULL) { + DEBUG(3,("Get_Hostbyname: host address is invalid for host %s\n",str)); + return 0; + } putip((char *)&res,(char *)hp->h_addr); } - if (res == (unsigned long)-1) return(0); + if (res == (uint32)-1) return(0); return(res); } @@ -3878,8 +3412,8 @@ unsigned long interpret_addr(char *str) struct in_addr *interpret_addr2(char *str) { static struct in_addr ret; - unsigned long a = interpret_addr(str); - putip((char *)&ret,(char *)&a); + uint32 a = interpret_addr(str); + ret.s_addr = a; return(&ret); } @@ -3888,121 +3422,534 @@ struct in_addr *interpret_addr2(char *str) ******************************************************************/ BOOL zero_ip(struct in_addr ip) { - unsigned long a; + uint32 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) +/******************************************************************* + matchname - determine if host name matches IP address + ******************************************************************/ +static BOOL matchname(char *remotehost,struct in_addr addr) { - double d; - time_t ret; - uint32 tlow,thigh; - tlow = IVAL(p,0); - thigh = IVAL(p,4); + struct hostent *hp; + int i; + + if ((hp = Get_Hostbyname(remotehost)) == 0) { + DEBUG(0,("Get_Hostbyname(%s): lookup failure", remotehost)); + return False; + } + + /* + * Make sure that gethostbyname() returns the "correct" host name. + * Unfortunately, gethostbyname("localhost") sometimes yields + * "localhost.domain". Since the latter host name comes from the + * local DNS, we just have to trust it (all bets are off if the local + * DNS is perverted). We always check the address list, though. + */ + + if (strcasecmp(remotehost, hp->h_name) + && strcasecmp(remotehost, "localhost")) { + DEBUG(0,("host name/name mismatch: %s != %s", + remotehost, hp->h_name)); + return False; + } + + /* Look up the host address in the address list we just got. */ + for (i = 0; hp->h_addr_list[i]; i++) { + if (memcmp(hp->h_addr_list[i], (caddr_t) & addr, sizeof(addr)) == 0) + return True; + } + + /* + * The host name does not map to the original host address. Perhaps + * someone has compromised a name server. More likely someone botched + * it, but that could be dangerous, too. + */ + + DEBUG(0,("host name/address mismatch: %s != %s", + inet_ntoa(addr), hp->h_name)); + return False; +} - if (thigh == 0) return(0); +/******************************************************************* + Reset the 'done' variables so after a client process is created + from a fork call these calls will be re-done. This should be + expanded if more variables need reseting. + ******************************************************************/ + +static BOOL global_client_name_done = False; +static BOOL global_client_addr_done = False; + +void reset_globals_after_fork(void) +{ + global_client_name_done = False; + global_client_addr_done = False; - d = ((double)thigh)*4.0*(double)(1<<30); - d += (tlow&0xFFF00000); - d *= 1.0e-7; + /* + * Re-seed the random crypto generator, so all smbd's + * started from the same parent won't generate the same + * sequence. + */ + { + unsigned char dummy; + generate_random_buffer( &dummy, 1, True); + } +} - /* now adjust by 369 years to make the secs since 1970 */ - d -= TIME_FIXUP_CONSTANT; +/******************************************************************* + return the DNS name of the client + ******************************************************************/ +char *client_name(int fd) +{ + struct sockaddr sa; + struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); + int length = sizeof(sa); + static pstring name_buf; + struct hostent *hp; + static int last_fd=-1; + + if (global_client_name_done && last_fd == fd) + return name_buf; + + last_fd = fd; + global_client_name_done = False; + + pstrcpy(name_buf,"UNKNOWN"); + + if (fd == -1) { + return name_buf; + } + + if (getpeername(fd, &sa, &length) < 0) { + DEBUG(0,("getpeername failed\n")); + return name_buf; + } + + /* 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",client_addr(fd))); + StrnCpy(name_buf,client_addr(fd),sizeof(name_buf) - 1); + } else { + StrnCpy(name_buf,(char *)hp->h_name,sizeof(name_buf) - 1); + if (!matchname(name_buf, sockin->sin_addr)) { + DEBUG(0,("Matchname failed on %s %s\n",name_buf,client_addr(fd))); + pstrcpy(name_buf,"UNKNOWN"); + } + } + global_client_name_done = True; + return name_buf; +} - if (d>=MAXINT) - return(0); +/******************************************************************* + return the IP addr of the client as a string + ******************************************************************/ +char *client_addr(int fd) +{ + struct sockaddr sa; + struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); + int length = sizeof(sa); + static fstring addr_buf; + static int last_fd = -1; - ret = (time_t)(d+0.5); + if (global_client_addr_done && fd == last_fd) + return addr_buf; - /* this takes us from kludge-GMT to real GMT */ - ret += TimeDiff(ret) - serverzone; + last_fd = fd; + global_client_addr_done = False; - return(ret); + fstrcpy(addr_buf,"0.0.0.0"); + + if (fd == -1) { + return addr_buf; + } + + if (getpeername(fd, &sa, &length) < 0) { + DEBUG(0,("getpeername failed\n")); + return addr_buf; + } + + fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr)); + + global_client_addr_done = True; + return addr_buf; } +#if (defined(HAVE_NETGROUP) && defined(WITH_AUTOMOUNT)) +/****************************************************************** + Remove any mount options such as -rsize=2048,wsize=2048 etc. + Based on a fix from <Thomas.Hepper@icem.de>. +*******************************************************************/ -/**************************************************************************** -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) +static void strip_mount_options( pstring *str) { - uint32 tlow,thigh; - double d; + if (**str == '-') + { + char *p = *str; + while(*p && !isspace(*p)) + p++; + while(*p && isspace(*p)) + p++; + if(*p) { + pstring tmp_str; - if (t==0) { - SIVAL(p,0,0); SIVAL(p,4,0); - return; + pstrcpy(tmp_str, p); + pstrcpy(*str, tmp_str); + } } +} - /* this converts GMT to kludge-GMT */ - t -= TimeDiff(t) - serverzone; +/******************************************************************* + Patch from jkf@soton.ac.uk + Split Luke's automount_server into YP lookup and string splitter + so can easily implement automount_path(). + As we may end up doing both, cache the last YP result. +*******************************************************************/ - d = (double) (t); +#ifdef WITH_NISPLUS_HOME +static char *automount_lookup(char *user_name) +{ + static fstring last_key = ""; + static pstring last_value = ""; + + char *nis_map = (char *)lp_nis_home_map_name(); + + char nis_domain[NIS_MAXNAMELEN + 1]; + char buffer[NIS_MAXATTRVAL + 1]; + nis_result *result; + nis_object *object; + entry_obj *entry; + + strncpy(nis_domain, (char *)nis_local_directory(), NIS_MAXNAMELEN); + nis_domain[NIS_MAXNAMELEN] = '\0'; + + DEBUG(5, ("NIS+ Domain: %s\n", nis_domain)); + + if (strcmp(user_name, last_key)) + { + slprintf(buffer, sizeof(buffer)-1, "[%s=%s]%s.%s", "key", user_name, nis_map, nis_domain); + DEBUG(5, ("NIS+ querystring: %s\n", buffer)); + + if (result = nis_list(buffer, RETURN_RESULT, NULL, NULL)) + { + if (result->status != NIS_SUCCESS) + { + DEBUG(3, ("NIS+ query failed: %s\n", nis_sperrno(result->status))); + fstrcpy(last_key, ""); pstrcpy(last_value, ""); + } + else + { + object = result->objects.objects_val; + if (object->zo_data.zo_type == ENTRY_OBJ) + { + entry = &object->zo_data.objdata_u.en_data; + DEBUG(5, ("NIS+ entry type: %s\n", entry->en_type)); + DEBUG(3, ("NIS+ result: %s\n", entry->en_cols.en_cols_val[1].ec_value.ec_value_val)); + + pstrcpy(last_value, entry->en_cols.en_cols_val[1].ec_value.ec_value_val); + string_sub(last_value, "&", user_name); + fstrcpy(last_key, user_name); + } + } + } + nis_freeresult(result); + } + + strip_mount_options(&last_value); - d += TIME_FIXUP_CONSTANT; + DEBUG(4, ("NIS+ Lookup: %s resulted in %s\n", user_name, last_value)); + return last_value; +} +#else /* WITH_NISPLUS_HOME */ +static char *automount_lookup(char *user_name) +{ + static fstring last_key = ""; + static pstring last_value = ""; + + int nis_error; /* returned by yp all functions */ + char *nis_result; /* yp_match inits this */ + int nis_result_len; /* and set this */ + char *nis_domain; /* yp_get_default_domain inits this */ + char *nis_map = (char *)lp_nis_home_map_name(); - d *= 1.0e7; + if ((nis_error = yp_get_default_domain(&nis_domain)) != 0) + { + DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error))); + return last_value; + } - thigh = (uint32)(d * (1.0/(4.0*(double)(1<<30)))); - tlow = (uint32)(d - ((double)thigh)*4.0*(double)(1<<30)); + DEBUG(5, ("NIS Domain: %s\n", nis_domain)); - SIVAL(p,0,tlow); - SIVAL(p,4,thigh); + if (!strcmp(user_name, last_key)) + { + nis_result = last_value; + nis_result_len = strlen(last_value); + nis_error = 0; + } + else + { + if ((nis_error = yp_match(nis_domain, nis_map, + user_name, strlen(user_name), + &nis_result, &nis_result_len)) != 0) + { + DEBUG(3, ("YP Error: \"%s\" while looking up \"%s\" in map \"%s\"\n", + yperr_string(nis_error), user_name, nis_map)); + } + if (!nis_error && nis_result_len >= sizeof(pstring)) + { + nis_result_len = sizeof(pstring)-1; + } + fstrcpy(last_key, user_name); + strncpy(last_value, nis_result, nis_result_len); + last_value[nis_result_len] = '\0'; + } + + strip_mount_options(&last_value); + + DEBUG(4, ("YP Lookup: %s resulted in %s\n", user_name, last_value)); + return last_value; } +#endif /* WITH_NISPLUS_HOME */ +#endif /******************************************************************* -sub strings with useful parameters -********************************************************************/ -void standard_sub_basic(char *s) + Patch from jkf@soton.ac.uk + This is Luke's original function with the NIS lookup code + moved out to a separate function. +*******************************************************************/ +static char *automount_server(char *user_name) { - if (!strchr(s,'%')) return; + static pstring server_name; - string_sub(s,"%R",remote_proto); - string_sub(s,"%a",remote_arch); - string_sub(s,"%m",remote_machine); - string_sub(s,"%L",local_machine); + /* use the local machine name as the default */ + /* this will be the default if WITH_AUTOMOUNT is not used or fails */ + pstrcpy(server_name, local_machine); - if (!strchr(s,'%')) return; +#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT)) - string_sub(s,"%v",VERSION); - string_sub(s,"%h",myhostname); - string_sub(s,"%U",sesssetup_user); + if (lp_nis_home_map()) + { + int home_server_len; + char *automount_value = automount_lookup(user_name); + home_server_len = strcspn(automount_value,":"); + DEBUG(5, ("NIS lookup succeeded. Home server length: %d\n",home_server_len)); + if (home_server_len > sizeof(pstring)) + { + home_server_len = sizeof(pstring); + } + strncpy(server_name, automount_value, home_server_len); + server_name[home_server_len] = '\0'; + } +#endif - if (!strchr(s,'%')) return; + DEBUG(4,("Home server: %s\n", server_name)); - string_sub(s,"%I",Client_info.addr); - string_sub(s,"%M",Client_info.name); - string_sub(s,"%T",timestring()); + return server_name; +} - if (!strchr(s,'%')) return; +/******************************************************************* + Patch from jkf@soton.ac.uk + Added this to implement %p (NIS auto-map version of %H) +*******************************************************************/ +static char *automount_path(char *user_name) +{ + static pstring server_path; - { - char pidstr[10]; - sprintf(pidstr,"%d",(int)getpid()); - string_sub(s,"%d",pidstr); - } + /* use the passwd entry as the default */ + /* this will be the default if WITH_AUTOMOUNT is not used or fails */ + /* pstrcpy() copes with get_home_dir() returning NULL */ + pstrcpy(server_path, get_home_dir(user_name)); - if (!strchr(s,'%')) return; +#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT)) - { - struct passwd *pass = Get_Pwnam(sesssetup_user,False); - if (pass) { - string_sub(s,"%G",gidtoname(pass->pw_gid)); - } - } + if (lp_nis_home_map()) + { + char *home_path_start; + char *automount_value = automount_lookup(user_name); + home_path_start = strchr(automount_value,':'); + if (home_path_start != NULL) + { + DEBUG(5, ("NIS lookup succeeded. Home path is: %s\n", + home_path_start?(home_path_start+1):"")); + pstrcpy(server_path, home_path_start+1); + } + } +#endif + + DEBUG(4,("Home server path: %s\n", server_path)); + + return server_path; +} + + +/******************************************************************* +sub strings with useful parameters +Rewritten by Stefaan A Eeckels <Stefaan.Eeckels@ecc.lu> and +Paul Rippin <pr3245@nopc.eurostat.cec.be> +********************************************************************/ +void standard_sub_basic(char *str) +{ + char *s, *p; + char pidstr[10]; + struct passwd *pass; + char *username = sam_logon_in_ssb ? samlogon_user : sesssetup_user; + + for (s = str ; s && *s && (p = strchr(s,'%')); s = p ) + { + switch (*(p+1)) + { + case 'G' : + { + if ((pass = Get_Pwnam(username,False))!=NULL) + { + string_sub(p,"%G",gidtoname(pass->pw_gid)); + } + else + { + p += 2; + } + break; + } + case 'N' : string_sub(p,"%N", automount_server(username)); break; + case 'I' : string_sub(p,"%I", client_addr(Client)); break; + case 'L' : string_sub(p,"%L", local_machine); break; + case 'M' : string_sub(p,"%M", client_name(Client)); break; + case 'R' : string_sub(p,"%R", remote_proto); break; + case 'T' : string_sub(p,"%T", timestring()); break; + case 'U' : string_sub(p,"%U", username); break; + case 'a' : string_sub(p,"%a", remote_arch); break; + case 'd' : + { + slprintf(pidstr,sizeof(pidstr) - 1, "%d",(int)getpid()); + string_sub(p,"%d", pidstr); + break; + } + case 'h' : string_sub(p,"%h", myhostname); break; + case 'm' : string_sub(p,"%m", remote_machine); break; + case 'v' : string_sub(p,"%v", VERSION); break; + case '$' : /* Expand environment variables */ + { + /* Contributed by Branko Cibej <branko.cibej@hermes.si> */ + fstring envname; + char *envval; + char *q, *r; + int copylen; + + if (*(p+2) != '(') + { + p+=2; + break; + } + if ((q = strchr(p,')')) == NULL) + { + DEBUG(0,("standard_sub_basic: Unterminated environment \ + variable [%s]\n", p)); + p+=2; + break; + } + + r = p+3; + copylen = MIN((q-r),(sizeof(envname)-1)); + strncpy(envname,r,copylen); + envname[copylen] = '\0'; + + if ((envval = getenv(envname)) == NULL) + { + DEBUG(0,("standard_sub_basic: Environment variable [%s] not set\n", + envname)); + p+=2; + break; + } + + copylen = MIN((q+1-p),(sizeof(envname)-1)); + strncpy(envname,p,copylen); + envname[copylen] = '\0'; + string_sub(p,envname,envval); + break; + } + case '\0': p++; break; /* don't run off end if last character is % */ + default : p+=2; break; + } + } + return; +} + + +/**************************************************************************** +do some standard substitutions in a string +****************************************************************************/ +void standard_sub(connection_struct *conn,char *str) +{ + char *p, *s, *home; + + for (s=str; (p=strchr(s, '%'));s=p) { + switch (*(p+1)) { + case 'H': + if ((home = get_home_dir(conn->user))) { + string_sub(p,"%H",home); + } else { + p += 2; + } + break; + + case 'P': + string_sub(p,"%P",conn->connectpath); + break; + + case 'S': + string_sub(p,"%S", + lp_servicename(SNUM(conn))); + break; + + case 'g': + string_sub(p,"%g", + gidtoname(conn->gid)); + break; + case 'u': + string_sub(p,"%u",conn->user); + break; + + /* Patch from jkf@soton.ac.uk Left the %N (NIS + * server name) in standard_sub_basic as it is + * a feature for logon servers, hence uses the + * username. The %p (NIS server path) code is + * here as it is used instead of the default + * "path =" string in [homes] and so needs the + * service name, not the username. */ + case 'p': + string_sub(p,"%p", + automount_path(lp_servicename(SNUM(conn)))); + break; + case '\0': + p++; + break; /* don't run off the end of the string + */ + + default: p+=2; + break; + } + } + + standard_sub_basic(str); +} + + + +/******************************************************************* +are two IPs on the same subnet? +********************************************************************/ +BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask) +{ + uint32 net1,net2,nmask; + + nmask = ntohl(mask.s_addr); + net1 = ntohl(ip1.s_addr); + net2 = ntohl(ip2.s_addr); + + return((net1 & nmask) == (net2 & nmask)); } @@ -4022,34 +3969,6 @@ int PutUniCode(char *dst,char *src) 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 @@ -4065,13 +3984,22 @@ struct hostent *Get_Hostbyname(char *name) exit(0); } + + /* + * This next test is redundent and causes some systems (with + * broken isalnum() calls) problems. + * JRA. + */ + +#if 0 if (!isalnum(*name2)) { free(name2); return(NULL); } +#endif /* 0 */ - ret = gethostbyname(name2); + ret = sys_gethostbyname(name2); if (ret != NULL) { free(name2); @@ -4080,7 +4008,7 @@ struct hostent *Get_Hostbyname(char *name) /* try with all lowercase */ strlower(name2); - ret = gethostbyname(name2); + ret = sys_gethostbyname(name2); if (ret != NULL) { free(name2); @@ -4089,7 +4017,7 @@ struct hostent *Get_Hostbyname(char *name) /* try with all uppercase */ strupper(name2); - ret = gethostbyname(name2); + ret = sys_gethostbyname(name2); if (ret != NULL) { free(name2); @@ -4107,32 +4035,7 @@ 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 + return(kill(pid,0) == 0 || errno != ESRCH); } @@ -4144,7 +4047,7 @@ char *uidtoname(int uid) static char name[40]; struct passwd *pass = getpwuid(uid); if (pass) return(pass->pw_name); - sprintf(name,"%d",uid); + slprintf(name, sizeof(name) - 1, "%d",uid); return(name); } @@ -4153,358 +4056,777 @@ 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); + static char name[40]; + struct group *grp = getgrgid(gid); + if (grp) return(grp->gr_name); + slprintf(name,sizeof(name) - 1, "%d",gid); + return(name); } /******************************************************************* -block sigs +something really nasty happened - panic! ********************************************************************/ -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 +void smb_panic(char *why) +{ + char *cmd = lp_panic_action(); + if (cmd && *cmd) { + system(cmd); + } + DEBUG(0,("PANIC: %s\n", why)); + exit(1); } -#if AJT + /******************************************************************* -my own panic function - not suitable for general use +a readdir wrapper which just returns the file name ********************************************************************/ -void ajt_panic(void) +char *readdirname(void *p) { - pstring cmd = "/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT &"; - smbrun(cmd,NULL); -} + struct dirent *ptr; + char *dname; + + if (!p) return(NULL); + + ptr = (struct dirent *)readdir(p); + if (!ptr) return(NULL); + + dname = ptr->d_name; + +#ifdef NEXT2 + if (telldir(p) < 0) return(NULL); #endif -#ifdef USE_DIRECT -#define DIRECT direct -#else -#define DIRECT dirent +#ifdef HAVE_BROKEN_READDIR + /* using /usr/ucb/cc is BAD */ + dname = dname - 2; #endif + { + static pstring buf; + memcpy(buf, dname, NAMLEN(ptr)+1); + unix_to_dos(buf, True); + dname = buf; + } + + return(dname); +} + /******************************************************************* -a readdir wrapper which just returns the file name -also return the inode number if requested + Utility function used to decide if the last component + of a path matches a (possibly wildcarded) entry in a namelist. ********************************************************************/ -char *readdirname(void *p) -{ - struct DIRECT *ptr; - char *dname; - if (!p) return(NULL); - - ptr = (struct DIRECT *)readdir(p); - if (!ptr) return(NULL); +BOOL is_in_path(char *name, name_compare_entry *namelist) +{ + pstring last_component; + char *p; - dname = ptr->d_name; + DEBUG(8, ("is_in_path: %s\n", name)); -#ifdef KANJI + /* if we have no list it's obviously not in the path */ + if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL))) { - static pstring buf; - strcpy(buf, dname); - unix_to_dos(buf, True); - dname = buf; + DEBUG(8,("is_in_path: no name list.\n")); + return False; } -#endif -#ifdef NEXT2 - if (telldir(p) < 0) return(NULL); -#endif + /* Get the last component of the unix name. */ + p = strrchr(name, '/'); + strncpy(last_component, p ? ++p : name, sizeof(last_component)-1); + last_component[sizeof(last_component)-1] = '\0'; -#ifdef SUNOS5 - /* this handles a broken compiler setup, causing a mixture - of BSD and SYSV headers and libraries */ + for(; namelist->name != NULL; namelist++) { - static BOOL broken_readdir = False; - if (!broken_readdir && !(*(dname)) && strequal("..",dname-2)) + if(namelist->is_wild) + { + /* + * Look for a wildcard match. Use the old + * 'unix style' mask match, rather than the + * new NT one. + */ + if (unix_mask_match(last_component, namelist->name, case_sensitive, False)) { - DEBUG(0,("Your readdir() is broken. You have somehow mixed SYSV and BSD headers and libraries\n")); - broken_readdir = True; + DEBUG(8,("is_in_path: mask match succeeded\n")); + return True; } - if (broken_readdir) - return(dname-2); + } + else + { + if((case_sensitive && (strcmp(last_component, namelist->name) == 0))|| + (!case_sensitive && (StrCaseCmp(last_component, namelist->name) == 0))) + { + DEBUG(8,("is_in_path: match succeeded\n")); + return True; + } + } } -#endif - - return(dname); + DEBUG(8,("is_in_path: match not found\n")); + + return False; } +/******************************************************************* + Strip a '/' separated list into an array of + name_compare_enties structures suitable for + passing to is_in_path(). We do this for + speed so we can pre-parse all the names in the list + and don't do it for each call to is_in_path(). + namelist is modified here and is assumed to be + a copy owned by the caller. + We also check if the entry contains a wildcard to + remove a potentially expensive call to mask_match + if possible. +********************************************************************/ + +void set_namearray(name_compare_entry **ppname_array, char *namelist) +{ + char *name_end; + char *nameptr = namelist; + int num_entries = 0; + int i; + + (*ppname_array) = NULL; + + if((nameptr == NULL ) || ((nameptr != NULL) && (*nameptr == '\0'))) + return; + + /* We need to make two passes over the string. The + first to count the number of elements, the second + to split it. + */ + while(*nameptr) + { + if ( *nameptr == '/' ) + { + /* cope with multiple (useless) /s) */ + nameptr++; + continue; + } + /* find the next / */ + name_end = strchr(nameptr, '/'); + + /* oops - the last check for a / didn't find one. */ + if (name_end == NULL) + break; + + /* next segment please */ + nameptr = name_end + 1; + num_entries++; + } + + if(num_entries == 0) + return; + + if(( (*ppname_array) = (name_compare_entry *)malloc( + (num_entries + 1) * sizeof(name_compare_entry))) == NULL) + { + DEBUG(0,("set_namearray: malloc fail\n")); + return; + } + + /* Now copy out the names */ + nameptr = namelist; + i = 0; + while(*nameptr) + { + if ( *nameptr == '/' ) + { + /* cope with multiple (useless) /s) */ + nameptr++; + continue; + } + /* find the next / */ + if ((name_end = strchr(nameptr, '/')) != NULL) + { + *name_end = 0; + } + + /* oops - the last check for a / didn't find one. */ + if(name_end == NULL) + break; + + (*ppname_array)[i].is_wild = ((strchr( nameptr, '?')!=NULL) || + (strchr( nameptr, '*')!=NULL)); + if(((*ppname_array)[i].name = strdup(nameptr)) == NULL) + { + DEBUG(0,("set_namearray: malloc fail (1)\n")); + return; + } + /* next segment please */ + nameptr = name_end + 1; + i++; + } + + (*ppname_array)[i].name = NULL; -#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); + return; } -#endif -#ifdef NO_INITGROUPS -#include <sys/types.h> -#include <limits.h> -#include <grp.h> +/**************************************************************************** +routine to free a namearray. +****************************************************************************/ -#ifndef NULL -#define NULL (void *)0 -#endif +void free_namearray(name_compare_entry *name_array) +{ + if(name_array == 0) + return; + + if(name_array->name != NULL) + free(name_array->name); + + free((char *)name_array); +} /**************************************************************************** - some systems don't have an initgroups call +routine to do file locking ****************************************************************************/ -int initgroups(char *name,gid_t id) +BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type) { -#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 HAVE_FCNTL_LOCK + SMB_STRUCT_FLOCK lock; + int ret; + + if(lp_ole_locking_compat()) { + SMB_OFF_T mask = ((SMB_OFF_T)0xC) << (SMB_OFF_T_BITS-4); + SMB_OFF_T mask2= ((SMB_OFF_T)0x3) << (SMB_OFF_T_BITS-4); + + /* 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) & mask2); + } else { + SMB_OFF_T mask = ((SMB_OFF_T)0x8) << (SMB_OFF_T_BITS-4); + SMB_OFF_T neg_mask = ~mask; + + /* interpret negative counts as large numbers */ + if (count < 0) + count &= ~mask; + + /* no negative offsets */ + if(offset < 0) + offset &= ~mask; + + /* count + offset must be in range */ + while ((offset < 0 || (offset + count < 0)) && mask) { - 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]; - } + offset &= ~mask; + mask = ((mask >> 1) & neg_mask); + } + } + + DEBUG(8,("fcntl_lock %d %d %.0f %.0f %d\n",fd,op,(double)offset,(double)count,type)); + + lock.l_type = type; + lock.l_whence = SEEK_SET; + lock.l_start = offset; + lock.l_len = count; + lock.l_pid = 0; + + errno = 0; + + ret = fcntl(fd,op,&lock); + if (errno == EFBIG) + { + if( DEBUGLVL( 0 )) + { + dbgtext("fcntl_lock: WARNING: lock request at offset %.0f, length %.0f returned\n", (double)offset,(double)count); + dbgtext("a 'file too large' error. This can happen when using 64 bit lock offsets\n"); + dbgtext("on 32 bit NFS mounted file systems. Retrying with 32 bit truncated length.\n"); } - endgrent(); - return(setgroups(i,grouplst)); + /* 32 bit NFS file system, retry with smaller offset */ + errno = 0; + lock.l_len = count & 0xffffffff; + 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 == SMB_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,(int)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 %.0f count %.0f op %d type %d (%s)\n", + (double)offset,(double)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(8,("Lock call successful\n")); + + return(True); +#else + return(False); #endif } -#endif +/******************************************************************* +is the name specified one of my netbios names +returns true is it is equal, false otherwise +********************************************************************/ +BOOL is_myname(char *s) +{ + int n; + BOOL ret = False; -#if WRAP_MALLOC + for (n=0; my_netbios_names[n]; n++) { + if (strequal(my_netbios_names[n], s)) + ret=True; + } + DEBUG(8, ("is_myname(\"%s\") returns %d\n", s, ret)); + return(ret); +} -/* undo the wrapping temporarily */ -#undef malloc -#undef realloc -#undef free +/******************************************************************* +set the horrid remote_arch string based on an enum. +********************************************************************/ +void set_remote_arch(enum remote_arch_types type) +{ + ra_type = type; + switch( type ) + { + case RA_WFWG: + fstrcpy(remote_arch, "WfWg"); + return; + case RA_OS2: + fstrcpy(remote_arch, "OS2"); + return; + case RA_WIN95: + fstrcpy(remote_arch, "Win95"); + return; + case RA_WINNT: + fstrcpy(remote_arch, "WinNT"); + return; + case RA_SAMBA: + fstrcpy(remote_arch,"Samba"); + return; + default: + ra_type = RA_UNKNOWN; + fstrcpy(remote_arch, "UNKNOWN"); + break; + } +} -/**************************************************************************** -wrapper for malloc() to catch memory errors -****************************************************************************/ -void *malloc_wrapped(int size,char *file,int line) +/******************************************************************* + Get the remote_arch type. +********************************************************************/ +enum remote_arch_types get_remote_arch(void) { -#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); + return ra_type; } -/**************************************************************************** -wrapper for realloc() to catch memory errors -****************************************************************************/ -void *realloc_wrapped(void *ptr,int size,char *file,int line) + +/******************************************************************* +skip past some unicode strings in a buffer +********************************************************************/ +char *skip_unicode_string(char *buf,int n) { -#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); + while (n--) + { + while (*buf) + buf += 2; + buf += 2; + } + return(buf); } -/**************************************************************************** -wrapper for free() to catch memory errors -****************************************************************************/ -void free_wrapped(void *ptr,char *file,int line) +/******************************************************************* +Return a ascii version of a unicode string +Hack alert: uses fixed buffer(s) and only handles ascii strings +********************************************************************/ +#define MAXUNI 1024 +char *unistrn2(uint16 *buf, int len) { -#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; + static char lbufs[8][MAXUNI]; + static int nexti; + char *lbuf = lbufs[nexti]; + char *p; + + nexti = (nexti+1)%8; + + DEBUG(10, ("unistrn2: ")); + + for (p = lbuf; *buf && p-lbuf < MAXUNI-2 && len > 0; len--, p++, buf++) + { + DEBUG(10, ("%4x ", *buf)); + *p = *buf; + } + + DEBUG(10,("\n")); + + *p = 0; + return lbuf; } -/* 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__) +/******************************************************************* +Return a ascii version of a unicode string +Hack alert: uses fixed buffer(s) and only handles ascii strings +********************************************************************/ +#define MAXUNI 1024 +char *unistr2(uint16 *buf) +{ + static char lbufs[8][MAXUNI]; + static int nexti; + char *lbuf = lbufs[nexti]; + char *p; -#endif + nexti = (nexti+1)%8; -#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) + DEBUG(10, ("unistr2: ")); + + for (p = lbuf; *buf && p-lbuf < MAXUNI-2; p++, buf++) + { + DEBUG(10, ("%4x ", *buf)); + *p = *buf; + } + + DEBUG(10,("\n")); + + *p = 0; + return lbuf; +} + +/******************************************************************* +create a null-terminated unicode string from a null-terminated ascii string. +return number of unicode chars copied, excluding the null character. + +only handles ascii strings +********************************************************************/ +#define MAXUNI 1024 +int struni2(uint16 *p, char *buf) { - int len = strlen(p); + int len = 0; - while ( *s != '\0' ) { - if ( strncmp(s, p, len) == 0 ) - return s; - s++; + if (p == NULL) return 0; + + DEBUG(10, ("struni2: ")); + + if (buf != NULL) + { + for (; *buf && len < MAXUNI-2; len++, p++, buf++) + { + DEBUG(10, ("%2x ", *buf)); + *p = *buf; + } + + DEBUG(10,("\n")); } - return NULL; + *p = 0; + + return len; +} + +/******************************************************************* +Return a ascii version of a unicode string +Hack alert: uses fixed buffer(s) and only handles ascii strings +********************************************************************/ +#define MAXUNI 1024 +char *unistr(char *buf) +{ + static char lbufs[8][MAXUNI]; + static int nexti; + char *lbuf = lbufs[nexti]; + char *p; + + nexti = (nexti+1)%8; + + for (p = lbuf; *buf && p-lbuf < MAXUNI-2; p++, buf += 2) + { + *p = *buf; + } + *p = 0; + return lbuf; } -#endif /* REPLACE_STRSTR */ -#ifdef REPLACE_MKTIME /******************************************************************* -a mktime() replacement for those who don't have it - contributed by -C.A. Lademann <cal@zls.com> +strcpy for unicode strings. returns length (in num of wide chars) ********************************************************************/ -#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++; - } - } +int unistrcpy(char *dst, char *src) +{ + int num_wchars = 0; - 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 - } + while (*src) + { + *dst++ = *src++; + *dst++ = *src++; + num_wchars++; + } + *dst++ = 0; + *dst++ = 0; - return(epoch); + return num_wchars; } -#endif /* REPLACE_MKTIME */ +/******************************************************************* +safe string copy into a known length string. maxlength does not +include the terminating zero. +********************************************************************/ +char *safe_strcpy(char *dest, char *src, int maxlength) +{ + int len; + + if (!dest) { + DEBUG(0,("ERROR: NULL dest in safe_strcpy\n")); + return NULL; + } + + if (!src) { + *dest = 0; + return dest; + } + len = strlen(src); -#ifdef REPLACE_RENAME -/* Rename a file. (from libiberty in GNU binutils) */ -int -rename (zfrom, zto) - const char *zfrom; - const char *zto; + if (len > maxlength) { + DEBUG(0,("ERROR: string overflow by %d in safe_strcpy [%.50s]\n", + len-maxlength, src)); + len = maxlength; + } + + memcpy(dest, src, len); + dest[len] = 0; + return dest; +} + +/******************************************************************* +safe string cat into a string. maxlength does not +include the terminating zero. +********************************************************************/ +char *safe_strcat(char *dest, char *src, int maxlength) { - if (link (zfrom, zto) < 0) - { - if (errno != EEXIST) - return -1; - if (unlink (zto) < 0 - || link (zfrom, zto) < 0) - return -1; + int src_len, dest_len; + + if (!dest) { + DEBUG(0,("ERROR: NULL dest in safe_strcat\n")); + return NULL; + } + + if (!src) { + return dest; + } + + src_len = strlen(src); + dest_len = strlen(dest); + + if (src_len + dest_len > maxlength) { + DEBUG(0,("ERROR: string overflow by %d in safe_strcat [%.50s]\n", + src_len + dest_len - maxlength, src)); + src_len = maxlength - dest_len; } - return unlink (zfrom); + + memcpy(&dest[dest_len], src, src_len); + dest[dest_len + src_len] = 0; + return dest; } -#endif +/******************************************************************* +align a pointer to a multiple of 2 bytes +********************************************************************/ +char *align2(char *q, char *base) +{ + if ((q - base) & 1) + { + q++; + } + return q; +} -#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; +void print_asc(int level, unsigned char *buf,int len) { - 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); + int i; + for (i=0;i<len;i++) + DEBUG(level,("%c", isprint(buf[i])?buf[i]:'.')); +} + +void dump_data(int level,char *buf1,int len) +{ + unsigned char *buf = (unsigned char *)buf1; + int i=0; + if (len<=0) return; + + DEBUG(level,("[%03X] ",i)); + for (i=0;i<len;) { + DEBUG(level,("%02X ",(int)buf[i])); + i++; + if (i%8 == 0) DEBUG(level,(" ")); + if (i%16 == 0) { + print_asc(level,&buf[i-16],8); DEBUG(level,(" ")); + print_asc(level,&buf[i-8],8); DEBUG(level,("\n")); + if (i<len) DEBUG(level,("[%03X] ",i)); } - endnetgrent(); - return (0); + } + if (i%16) { + int n; + + n = 16 - (i%16); + DEBUG(level,(" ")); + if (n>8) DEBUG(level,(" ")); + while (n--) DEBUG(level,(" ")); + + n = MIN(8,i%16); + print_asc(level,&buf[i-(i%16)],n); DEBUG(level,(" ")); + n = (i%16) - n; + if (n>0) print_asc(level,&buf[i-n],n); + DEBUG(level,("\n")); + } } -#endif +char *tab_depth(int depth) +{ + static pstring spaces; + memset(spaces, ' ', depth * 4); + spaces[depth * 4] = 0; + return spaces; +} -#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) +/***************************************************************** + Convert a SID to an ascii string. +*****************************************************************/ + +char *sid_to_string(pstring sidstr_out, DOM_SID *sid) { - 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 + char subauth[16]; + int i; + /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */ + uint32 ia = (sid->id_auth[5]) + + (sid->id_auth[4] << 8 ) + + (sid->id_auth[3] << 16) + + (sid->id_auth[2] << 24); + + slprintf(sidstr_out, sizeof(pstring) - 1, "S-%d-%d", sid->sid_rev_num, ia); + + for (i = 0; i < sid->num_auths; i++) + { + slprintf(subauth, sizeof(subauth)-1, "-%d", sid->sub_auths[i]); + pstrcat(sidstr_out, subauth); + } + + DEBUG(7,("sid_to_string returning %s\n", sidstr_out)); + return sidstr_out; } -#define memcpy(d,s,l) memcpy_wrapped(d,s,l,__FILE__,__LINE__) -#endif +/***************************************************************** + Convert a string to a SID. Returns True on success, False on fail. +*****************************************************************/ + +BOOL string_to_sid(DOM_SID *sidout, char *sidstr) +{ + pstring tok; + char *p = sidstr; + /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */ + uint32 ia; + + memset((char *)sidout, '\0', sizeof(DOM_SID)); + + if(StrnCaseCmp( sidstr, "S-", 2)) { + DEBUG(0,("string_to_sid: Sid %s does not start with 'S-'.\n", sidstr)); + return False; + } + + p += 2; + if(!next_token(&p, tok, "-", sizeof(tok))) { + DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr)); + return False; + } + + /* Get the revision number. */ + sidout->sid_rev_num = atoi(tok); + + if(!next_token(&p, tok, "-", sizeof(tok))) { + DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr)); + return False; + } + + /* identauth in decimal should be < 2^32 */ + ia = atoi(tok); + + /* NOTE - the ia value is in big-endian format. */ + sidout->id_auth[0] = 0; + sidout->id_auth[1] = 0; + sidout->id_auth[2] = (ia & 0xff000000) >> 24; + sidout->id_auth[3] = (ia & 0x00ff0000) >> 16; + sidout->id_auth[4] = (ia & 0x0000ff00) >> 8; + sidout->id_auth[5] = (ia & 0x000000ff); + + sidout->num_auths = 0; + + while(next_token(&p, tok, "-", sizeof(tok)) && + sidout->num_auths < MAXSUBAUTHS) { + /* + * NOTE - the subauths are in native machine-endian format. They + * are converted to little-endian when linearized onto the wire. + */ + sidout->sub_auths[sidout->num_auths++] = atoi(tok); + } + + DEBUG(7,("string_to_sid: converted SID %s ok\n", sidstr)); + + return True; +} + +/***************************************************************************** + * Provide a checksum on a string + * + * Input: s - the nul-terminated character string for which the checksum + * will be calculated. + * + * Output: The checksum value calculated for s. + * + * **************************************************************************** + */ +int str_checksum(char *s) +{ + int res = 0; + int c; + int i=0; + + while(*s) { + c = *s; + res ^= (c << (i % 15)) ^ (c >> (15-(i%15))); + s++; + i++; + } + return(res); +} /* str_checksum */ + +/***************************************************************** +zero a memory area then free it. Used to catch bugs faster +*****************************************************************/ +void zero_free(void *p, size_t size) +{ + memset(p, 0, size); + free(p); +} diff --git a/source/lib/util_hnd.c b/source/lib/util_hnd.c new file mode 100644 index 00000000000..b1e695360f7 --- /dev/null +++ b/source/lib/util_hnd.c @@ -0,0 +1,289 @@ + +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-1997, + * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, + * + * 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; + +#ifndef MAX_OPEN_POLS +#define MAX_OPEN_POLS 64 +#endif + +struct reg_info +{ + /* for use by \PIPE\winreg */ + fstring name; /* name of registry key */ +}; + +struct samr_info +{ + /* for use by the \PIPE\samr policy */ + DOM_SID sid; + uint32 rid; /* relative id associated with the pol_hnd */ + uint32 status; /* some sort of flag. best to record it. comes from opnum 0x39 */ +}; + +static struct policy +{ + struct policy *next, *prev; + int pnum; + BOOL open; + POLICY_HND pol_hnd; + + union { + struct samr_info samr; + struct reg_info reg; + } dev; +} *Policy; + +static struct bitmap *bmap; + + +/**************************************************************************** + create a unique policy handle +****************************************************************************/ +static void create_pol_hnd(POLICY_HND *hnd) +{ + static uint32 pol_hnd_low = 0; + static uint32 pol_hnd_high = 0; + + if (hnd == NULL) return; + + /* i severely doubt that pol_hnd_high will ever be non-zero... */ + pol_hnd_low++; + if (pol_hnd_low == 0) pol_hnd_high++; + + SIVAL(hnd->data, 0 , 0x0); /* first bit must be null */ + SIVAL(hnd->data, 4 , pol_hnd_low ); /* second bit is incrementing */ + SIVAL(hnd->data, 8 , pol_hnd_high); /* second bit is incrementing */ + SIVAL(hnd->data, 12, time(NULL)); /* something random */ + SIVAL(hnd->data, 16, getpid()); /* something more random */ +} + +/**************************************************************************** + initialise policy handle states... +****************************************************************************/ +void init_lsa_policy_hnd(void) +{ + bmap = bitmap_allocate(MAX_OPEN_POLS); + if (!bmap) { + exit_server("out of memory in init_lsa_policy_hnd\n"); + } +} + +/**************************************************************************** + find first available policy slot. creates a policy handle for you. +****************************************************************************/ +BOOL open_lsa_policy_hnd(POLICY_HND *hnd) +{ + int i; + struct policy *p; + + i = bitmap_find(bmap, 1); + + if (i == -1) { + DEBUG(0,("ERROR: out of Policy Handles!\n")); + return False; + } + + p = (struct policy *)malloc(sizeof(*p)); + if (!p) { + DEBUG(0,("ERROR: out of memory!\n")); + return False; + } + + ZERO_STRUCTP(p); + + p->open = True; + p->pnum = i; + + create_pol_hnd(hnd); + memcpy(&p->pol_hnd, hnd, sizeof(*hnd)); + + bitmap_set(bmap, i); + + DLIST_ADD(Policy, p); + + DEBUG(4,("Opened policy hnd[%x] ", i)); + dump_data(4, (char *)hnd->data, sizeof(hnd->data)); + + return True; +} + +/**************************************************************************** + find policy by handle +****************************************************************************/ +static struct policy *find_lsa_policy(POLICY_HND *hnd) +{ + struct policy *p; + + for (p=Policy;p;p=p->next) { + if (memcmp(&p->pol_hnd, hnd, sizeof(*hnd)) == 0) { + DEBUG(4,("Found policy hnd[%x] ", p->pnum)); + dump_data(4, (char *)hnd->data, sizeof(hnd->data)); + return p; + } + } + + DEBUG(4,("Policy not found: ")); + dump_data(4, (char *)hnd->data, sizeof(hnd->data)); + + return NULL; +} + +/**************************************************************************** + find policy index by handle +****************************************************************************/ +int find_lsa_policy_by_hnd(POLICY_HND *hnd) +{ + struct policy *p = find_lsa_policy(hnd); + + return p?p->pnum:-1; +} + +/**************************************************************************** + set samr rid +****************************************************************************/ +BOOL set_lsa_policy_samr_rid(POLICY_HND *hnd, uint32 rid) +{ + struct policy *p = find_lsa_policy(hnd); + + if (p && p->open) { + DEBUG(3,("Setting policy device rid=%x pnum=%x\n", + rid, p->pnum)); + + p->dev.samr.rid = rid; + return True; + } + + DEBUG(3,("Error setting policy rid=%x\n",rid)); + return False; +} + + +/**************************************************************************** + set samr pol status. absolutely no idea what this is. +****************************************************************************/ +BOOL set_lsa_policy_samr_pol_status(POLICY_HND *hnd, uint32 pol_status) +{ + struct policy *p = find_lsa_policy(hnd); + + if (p && p->open) { + DEBUG(3,("Setting policy status=%x pnum=%x\n", + pol_status, p->pnum)); + + p->dev.samr.status = pol_status; + return True; + } + + DEBUG(3,("Error setting policy status=%x\n", + pol_status)); + return False; +} + +/**************************************************************************** + set samr sid +****************************************************************************/ +BOOL set_lsa_policy_samr_sid(POLICY_HND *hnd, DOM_SID *sid) +{ + pstring sidstr; + struct policy *p = find_lsa_policy(hnd); + + if (p && p->open) { + DEBUG(3,("Setting policy sid=%s pnum=%x\n", + sid_to_string(sidstr, sid), p->pnum)); + + memcpy(&p->dev.samr.sid, sid, sizeof(*sid)); + return True; + } + + DEBUG(3,("Error setting policy sid=%s\n", + sid_to_string(sidstr, sid))); + return False; +} + +/**************************************************************************** + set samr rid +****************************************************************************/ +uint32 get_lsa_policy_samr_rid(POLICY_HND *hnd) +{ + struct policy *p = find_lsa_policy(hnd); + + if (p && p->open) { + uint32 rid = p->dev.samr.rid; + DEBUG(3,("Getting policy device rid=%x pnum=%x\n", + rid, p->pnum)); + + return rid; + } + + DEBUG(3,("Error getting policy\n")); + return 0xffffffff; +} + +/**************************************************************************** + set reg name +****************************************************************************/ +BOOL set_lsa_policy_reg_name(POLICY_HND *hnd, fstring name) +{ + struct policy *p = find_lsa_policy(hnd); + + if (p && p->open) { + DEBUG(3,("Setting policy pnum=%x name=%s\n", + p->pnum, name)); + + fstrcpy(p->dev.reg.name, name); + return True; + } + + DEBUG(3,("Error setting policy name=%s\n", name)); + return False; +} + +/**************************************************************************** + close an lsa policy +****************************************************************************/ +BOOL close_lsa_policy_hnd(POLICY_HND *hnd) +{ + struct policy *p = find_lsa_policy(hnd); + + if (!p) { + DEBUG(3,("Error closing policy\n")); + return False; + } + + DEBUG(3,("Closed policy name pnum=%x\n", p->pnum)); + + DLIST_REMOVE(Policy, p); + + bitmap_clear(bmap, p->pnum); + + ZERO_STRUCTP(p); + + free(p); + + return True; +} + |