diff options
author | Samba Release Account <samba-bugs@samba.org> | 1996-05-04 07:50:46 +0000 |
---|---|---|
committer | Samba Release Account <samba-bugs@samba.org> | 1996-05-04 07:50:46 +0000 |
commit | 0e8fd3398771da2f016d72830179507f3edda51b (patch) | |
tree | b5d07075a85050832720033f7b26c37a301ede72 /source3/lib | |
download | samba-0e8fd3398771da2f016d72830179507f3edda51b.tar.gz samba-0e8fd3398771da2f016d72830179507f3edda51b.tar.bz2 samba-0e8fd3398771da2f016d72830179507f3edda51b.zip |
Initial version imported to CVS
(This used to be commit 291551d80711daab7b7581720bcd9a08d6096517)
Diffstat (limited to 'source3/lib')
-rw-r--r-- | source3/lib/access.c | 389 | ||||
-rw-r--r-- | source3/lib/charcnv.c | 126 | ||||
-rw-r--r-- | source3/lib/charset.c | 111 | ||||
-rw-r--r-- | source3/lib/fault.c | 86 | ||||
-rw-r--r-- | source3/lib/getsmbpass.c | 166 | ||||
-rw-r--r-- | source3/lib/kanji.c | 895 | ||||
-rw-r--r-- | source3/lib/md4.c | 299 | ||||
-rw-r--r-- | source3/lib/system.c | 222 | ||||
-rw-r--r-- | source3/lib/ufc.c | 782 | ||||
-rw-r--r-- | source3/lib/username.c | 246 | ||||
-rw-r--r-- | source3/lib/util.c | 4510 |
11 files changed, 7832 insertions, 0 deletions
diff --git a/source3/lib/access.c b/source3/lib/access.c new file mode 100644 index 0000000000..14a84b2fb4 --- /dev/null +++ b/source3/lib/access.c @@ -0,0 +1,389 @@ +/* +This module is an adaption of code from the tcpd-1.4 package written +by Wietse Venema, Eindhoven University of Technology, The Netherlands. + +The code is used here with permission. + +The code has been considerably changed from the original. Bug reports +should be sent to Andrew.Tridgell@anu.edu.au +*/ + +#include "includes.h" +#include "loadparm.h" + +#define ALLOW_PURE_ADDRESSES + +extern int DEBUGLEVEL; + +#ifndef INADDR_NONE +#define INADDR_NONE ((unsigned long)~0) +#endif + + +#define FROM_ADDRLEN (4*3+3+1) +#define Good True +#define Bad False + +#define CLIENT_MATCH client_match + +/* Delimiters for lists of daemons or clients. */ + +static char sep[] = ", \t"; + +/* Constants to be used in assignments only, not in comparisons... */ + +#define YES 1 +#define NO 0 +#define FAIL (-1) + +/* Forward declarations. */ +BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client); +static int list_match(char *list,char *item, int (*match_fn)()); +static int client_match(char *tok,char *item); +static int string_match(char *tok,char *s); +static int masked_match(char *tok, char *slash, char *s); +static int matchname(char *remotehost,struct in_addr addr); +BOOL fromhost(int sock,struct from_host *f); + + +/* Size of logical line buffer. */ +#define BUFLEN 2048 + + +/* return true if access should be allowed to a service*/ +BOOL check_access(int snum) +{ + extern int Client; + extern struct from_host Client_info; + char *denyl,*allowl; + BOOL ret = False; + + denyl = lp_hostsdeny(snum); + if (denyl) denyl = strdup(denyl); + + allowl = lp_hostsallow(snum); + if (allowl) allowl = strdup(allowl); + + + fromhost(Client,&Client_info); + + if ((!denyl || *denyl==0) && (!allowl || *allowl==0)) + ret = True; + + if (!ret) + { + if (!fromhost(Client,&Client_info)) + DEBUG(0,("ERROR: Can't get from_host info\n")); + else + { + if (allow_access(denyl,allowl,&Client_info)) + { + if (snum >= 0) + DEBUG(2,("Allowed connection from %s (%s) to %s\n", + Client_info.name,Client_info.addr, + lp_servicename(snum))); + ret = True; + } + else + if (snum >= 0) + DEBUG(0,("Denied connection from %s (%s) to %s\n", + Client_info.name,Client_info.addr, + lp_servicename(snum))); + } + } + + if (denyl) free(denyl); + if (allowl) free(allowl); + return(ret); +} + + +/* return true if access should be allowed */ +BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client) +{ + /* if theres no deny list and no allow list then allow access */ + if ((!deny_list || *deny_list == 0) && (!allow_list || *allow_list == 0)) + return(True); + + /* if there is an allow list but no deny list then allow only hosts + on the allow list */ + if (!deny_list || *deny_list == 0) + return(list_match(allow_list,(char *)client,CLIENT_MATCH)); + + /* if theres a deny list but no allow list then allow + all hosts not on the deny list */ + if (!allow_list || *allow_list == 0) + return(!list_match(deny_list,(char *)client,CLIENT_MATCH)); + + /* if there are both type of list then allow all hosts on the allow list */ + if (list_match(allow_list,(char *)client,CLIENT_MATCH)) + return (True); + + /* if there are both type of list and it's not on the allow then + allow it if its not on the deny */ + if (list_match(deny_list,(char *)client,CLIENT_MATCH)) + return (False); + + return (True); +} + +/* list_match - match an item against a list of tokens with exceptions */ +/* (All modifications are marked with the initials "jkf") */ +static int list_match(char *list,char *item, int (*match_fn)()) +{ + char *tok; + char *listcopy; /* jkf */ + int match = NO; + + /* + * jkf@soton.ac.uk -- 31 August 1994 -- Stop list_match() + * overwriting the list given as its first parameter. + */ + + /* jkf -- can get called recursively with NULL list */ + listcopy = (list == 0) ? (char *)0 : strdup(list); + + /* + * Process tokens one at a time. We have exhausted all possible matches + * when we reach an "EXCEPT" token or the end of the list. If we do find + * a match, look for an "EXCEPT" list and recurse to determine whether + * the match is affected by any exceptions. + */ + + for (tok = strtok(listcopy, sep); tok ; tok = strtok(NULL, sep)) { + if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */ + break; + if ((match = (*match_fn) (tok, item))) /* YES or FAIL */ + break; + } + /* Process exceptions to YES or FAIL matches. */ + + if (match != NO) { + while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT")) + /* VOID */ ; + if (tok == 0 || list_match((char *) 0, item, match_fn) == NO) { + if (listcopy != 0) free(listcopy); /* jkf */ + return (match); + } + } + + if (listcopy != 0) free(listcopy); /* jkf */ + return (NO); +} + + +/* client_match - match host name and address against token */ +static int client_match(char *tok,char *item) +{ + struct from_host *client = (struct from_host *) item; + int match; + + /* + * Try to match the address first. If that fails, try to match the host + * name if available. + */ + + if ((match = string_match(tok, client->addr)) == 0) + if (client->name[0] != 0) + match = string_match(tok, client->name); + return (match); +} + +/* string_match - match string against token */ +static int string_match(char *tok,char *s) +{ + int tok_len; + int str_len; + char *cut; + + /* + * Return YES if a token has the magic value "ALL". Return FAIL if the + * token is "FAIL". If the token starts with a "." (domain name), return + * YES if it matches the last fields of the string. If the token has the + * magic value "LOCAL", return YES if the string does not contain a "." + * character. If the token ends on a "." (network number), return YES if + * it matches the first fields of the string. If the token begins with a + * "@" (netgroup name), return YES if the string is a (host) member of + * the netgroup. Return YES if the token fully matches the string. If the + * token is a netnumber/netmask pair, return YES if the address is a + * member of the specified subnet. + */ + + if (tok[0] == '.') { /* domain: match last fields */ + if ((str_len = strlen(s)) > (tok_len = strlen(tok)) + && strcasecmp(tok, s + str_len - tok_len) == 0) + return (YES); + } else if (tok[0] == '@') { /* netgroup: look it up */ +#ifdef NETGROUP + static char *mydomain = NULL; + char *hostname = NULL; + BOOL netgroup_ok = False; + + if (!mydomain) yp_get_default_domain(&mydomain); + + if (!(hostname = strdup(s))) { + DEBUG(1,("out of memory for strdup!\n")); + return NO; + } + + netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain); + + DEBUG(5,("looking for %s of domain %s in netgroup %s gave %s\n", + hostname, + mydomain, + tok+1, + BOOLSTR(netgroup_ok))); + +#ifdef NETGROUP_INSECURE + /* if you really want netgroups that match non qualified names + then define NETGROUP_INSECURE. It can, however, be a big + security hole */ + { + char *clnt_domain; + if (!netgroup_ok && (clnt_domain=strchr(hostname,'.'))) { + *clnt_domain++ = '\0'; + netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain); + } + } +#endif + + free(hostname); + + if (netgroup_ok) return(YES); +#else + DEBUG(0,("access: netgroup support is not configured")); + return (NO); +#endif + } else if (strcasecmp(tok, "ALL") == 0) { /* all: match any */ + return (YES); + } else if (strcasecmp(tok, "FAIL") == 0) { /* fail: match any */ + return (FAIL); + } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */ + if (strchr(s, '.') == 0 && strcasecmp(s, "unknown") != 0) + return (YES); + } else if (!strcasecmp(tok, s)) { /* match host name or address */ + return (YES); + } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { /* network */ + if (strncmp(tok, s, tok_len) == 0) + return (YES); + } else if ((cut = strchr(tok, '/')) != 0) { /* netnumber/netmask */ + if (isdigit(s[0]) && masked_match(tok, cut, s)) + return (YES); + } + return (NO); +} + +/* masked_match - match address against netnumber/netmask */ +static int masked_match(char *tok, char *slash, char *s) +{ + unsigned long net; + unsigned long mask; + unsigned long addr; + + if ((addr = interpret_addr(s)) == INADDR_NONE) + return (NO); + *slash = 0; + net = interpret_addr(tok); + *slash = '/'; + if (net == INADDR_NONE || (mask = interpret_addr(slash + 1)) == INADDR_NONE) { + DEBUG(0,("access: bad net/mask access control: %s", tok)); + return (NO); + } + return ((addr & mask) == net); +} + + +/* fromhost - find out what is at the other end of a socket */ +BOOL fromhost(int sock,struct from_host *f) +{ + static struct sockaddr sa; + struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); + struct hostent *hp; + int length = sizeof(sa); + static char addr_buf[FROM_ADDRLEN]; + static char name_buf[MAXHOSTNAMELEN]; + BOOL takeAddressAsHostname = False; + + if (getpeername(sock, &sa, &length) < 0) + { + DEBUG(0,("getpeername failed\n")); + return(False); + } + + f->sin = sockin; + f->addr = strcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr)); + + /* Look up the remote host name. */ + if ((hp = gethostbyaddr((char *) &sockin->sin_addr, + sizeof(sockin->sin_addr), + AF_INET)) == 0) { + DEBUG(1,("Gethostbyaddr failed for %s\n",addr_buf)); +#ifdef ALLOW_PURE_ADDRESSES + takeAddressAsHostname = True; +#else + return(False); +#endif + } + + /* Save the host name. A later gethostbyxxx() call may clobber it. */ + f->name = StrnCpy(name_buf, + takeAddressAsHostname? f->addr : hp->h_name, + sizeof(name_buf) - 1); + + /* + * Verify that the host name does not belong to someone else. If host + * name verification fails, pretend that the host name lookup failed. + */ + if (!takeAddressAsHostname && !matchname(f->name, sockin->sin_addr)) + { + DEBUG(0,("Matchname failed\n")); + return(False); + } + + return(True); +} + +/* matchname - determine if host name matches IP address */ +static int matchname(char *remotehost,struct in_addr addr) +{ + struct hostent *hp; + int i; + + if ((hp = Get_Hostbyname(remotehost)) == 0) { + DEBUG(0,("Get_Hostbyname(%s): lookup failure", remotehost)); + return (Bad); + } + + /* + * Make sure that gethostbyname() returns the "correct" host name. + * Unfortunately, gethostbyname("localhost") sometimes yields + * "localhost.domain". Since the latter host name comes from the + * local DNS, we just have to trust it (all bets are off if the local + * DNS is perverted). We always check the address list, though. + */ + + if (strcasecmp(remotehost, hp->h_name) + && strcasecmp(remotehost, "localhost")) { + DEBUG(0,("host name/name mismatch: %s != %s", + remotehost, hp->h_name)); + return (Bad); + } + + /* Look up the host address in the address list we just got. */ + for (i = 0; hp->h_addr_list[i]; i++) { + if (memcmp(hp->h_addr_list[i], (caddr_t) & addr, sizeof(addr)) == 0) + return (Good); + } + + /* + * The host name does not map to the original host address. Perhaps + * someone has compromised a name server. More likely someone botched + * it, but that could be dangerous, too. + */ + + DEBUG(0,("host name/address mismatch: %s != %s", + inet_ntoa(addr), hp->h_name)); + return (Bad); +} + + diff --git a/source3/lib/charcnv.c b/source3/lib/charcnv.c new file mode 100644 index 0000000000..049390f2a4 --- /dev/null +++ b/source3/lib/charcnv.c @@ -0,0 +1,126 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Character set conversion Extensions + Copyright (C) Andrew Tridgell 1992-1994 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ +#include "includes.h" +extern int DEBUGLEVEL; + +static char cvtbuf[1024]; + +static mapsinited = 0; + +static char unix2dos[256]; +static char dos2unix[256]; + +static void initmaps() { + int k; + + for (k = 0; k < 256; k++) unix2dos[k] = k; + for (k = 0; k < 256; k++) dos2unix[k] = k; + + mapsinited = 1; +} + +static void update_map(char * str) { + char *p; + + for (p = str; *p; p++) { + if (p[1]) { + unix2dos[(unsigned char)*p] = p[1]; + dos2unix[(unsigned char)p[1]] = *p; + p++; + } + } +} + +static void initiso() { + + if (!mapsinited) initmaps(); + + update_map("\241\255\242\233\243\234\244\236\245\235\246\272\247\025\250\251"); + update_map("\251\273\252\246\253\256\254\252\255\274\256\310\257\257\260\370"); + update_map("\261\361\262\375\263\264\264\265\265\266\266\024\267\371\270\267"); + update_map("\271\270\272\247\273\275\274\254\275\253\276\276\277\250\200\277"); + update_map("\301\300\302\301\303\302\304\216\305\217\306\222\307\200\310\303"); + update_map("\311\220\312\305\313\306\314\307\315\315\316\317\317\320\320\311"); + update_map("\321\245\322\321\323\322\324\323\325\324\326\231\327\312\330\325"); + update_map("\331\326\332\327\333\330\334\232\335\313\336\314\337\341\340\205"); + update_map("\341\240\342\203\343\331\344\204\345\206\346\221\347\207\350\212"); + update_map("\351\202\352\210\353\211\354\215\355\241\356\214\357\213\360\316"); + update_map("\361\244\362\225\363\242\364\223\365\332\366\224\367\366\370\362"); + update_map("\371\227\372\243\373\226\374\201\375\304\376\263\377\230"); +} + +/* + * Convert unix to dos + */ +char * +unix2dos_format(char *str,BOOL overwrite) +{ + char *p; + char *dp; + + if (!mapsinited) initmaps(); + if (overwrite) { + for (p = str; *p; p++) *p = unix2dos[(unsigned char)*p]; + return str; + } else { + for (p = str, dp = cvtbuf; *p; p++,dp++) *dp = unix2dos[(unsigned char)*p]; + *dp = 0; + return cvtbuf; + } +} + +/* + * Convert dos to unix + */ +char * +dos2unix_format (char *str, BOOL overwrite) +{ + char *p; + char *dp; + + if (!mapsinited) initmaps(); + if (overwrite) { + for (p = str; *p; p++) *p = dos2unix[(unsigned char)*p]; + return str; + } else { + for (p = str, dp = cvtbuf; *p; p++,dp++) *dp = dos2unix[(unsigned char)*p]; + *dp = 0; + return cvtbuf; + } +} + + +/* + * Interpret character set. + */ +int +interpret_character_set (char *str, int def) +{ + + if (strequal (str, "iso8859-1")) { + initiso(); + return def; + } else { + DEBUG(0,("unrecognized character set\n")); + } + return def; +} diff --git a/source3/lib/charset.c b/source3/lib/charset.c new file mode 100644 index 0000000000..ada3ef790a --- /dev/null +++ b/source3/lib/charset.c @@ -0,0 +1,111 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Character set handling + Copyright (C) Andrew Tridgell 1992-1995 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define CHARSET_C +#include "includes.h" + +extern int DEBUGLEVEL; + +char xx_dos_char_map[256]; +char xx_upper_char_map[256]; +char xx_lower_char_map[256]; + +char *dos_char_map = NULL; +char *upper_char_map = NULL; +char *lower_char_map = NULL; + +static void add_dos_char(int lower, int upper) +{ + DEBUG(6,("Adding chars 0%o 0%o\n",lower,upper)); + if (lower) dos_char_map[(char)lower] = 1; + if (upper) dos_char_map[(char)upper] = 1; + if (lower && upper) { + lower_char_map[(char)upper] = (char)lower; + upper_char_map[(char)lower] = (char)upper; + } +} + +/**************************************************************************** +initialise the charset arrays +****************************************************************************/ +void charset_initialise(void) +{ + int i; + + dos_char_map = &xx_dos_char_map[128]; + upper_char_map = &xx_upper_char_map[128]; + lower_char_map = &xx_lower_char_map[128]; + + for (i= -128;i<=127;i++) { + dos_char_map[(char)i] = 0; + } + + for (i=0;i<=127;i++) { + if (isalnum((char)i) || strchr("._^$~!#%&-{}()@'`",(char)i)) + add_dos_char(i,0); + } + + for (i= -128;i<=127;i++) { + char c = (char)i; + upper_char_map[i] = lower_char_map[i] = c; + if (isupper(c)) lower_char_map[c] = tolower(c); + if (islower(c)) upper_char_map[c] = toupper(c); + } + + /* valid for all DOS PC */ + add_dos_char(142,0); /* A trema */ + add_dos_char(143,0); /* A o */ + add_dos_char(144,0); /* E ' */ + add_dos_char(146,0); /* AE */ + add_dos_char(153,0); /* O trema */ + add_dos_char(154,0); /* U trema */ + add_dos_char(165,0); /* N tilda */ + add_dos_char(128,0); /* C cedille */ + add_dos_char(156,0); /* Pound */ + add_dos_char(183,0); /* A ` (WIN)*/ + add_dos_char(157,0); /* Phi (WIN)*/ + add_dos_char(212,0); /* E` (WIN)*/ +} + + +/******************************************************************* +add characters depending on a string passed by the user +********************************************************************/ +void add_char_string(char *s) +{ + char *extra_chars = (char *)strdup(s); + char *t; + if (!extra_chars) return; + + for (t=strtok(extra_chars," \t\r\n"); t; t=strtok(NULL," \t\r\n")) { + char c1=0,c2=0; + int i1=0,i2=0; + if (isdigit(*t) || (*t)=='-') { + sscanf(t,"%i:%i",&i1,&i2); + add_dos_char(i1,i2); + } else { + sscanf(t,"%c:%c",&c1,&c2); + add_dos_char(c1,c2); + } + } + + free(extra_chars); +} diff --git a/source3/lib/fault.c b/source3/lib/fault.c new file mode 100644 index 0000000000..20c75f7876 --- /dev/null +++ b/source3/lib/fault.c @@ -0,0 +1,86 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Critical Fault handling + Copyright (C) Andrew Tridgell 1992-1995 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef LINUX +#define __KERNEL__ +#endif + +#include "includes.h" +extern int DEBUGLEVEL; + + +static void (*cont_fn)(); + + +/******************************************************************* +report a fault +********************************************************************/ +static void fault_report(int sig) +{ + DEBUG(0,("===============================================================\n")); + DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)getpid(),VERSION)); + DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n")); + DEBUG(0,("===============================================================\n")); + +#if AJT + ajt_panic(); +#endif + + if (cont_fn) + { + fault_setup(cont_fn); + cont_fn(NULL); +#ifdef SIGSEGV + signal(SIGSEGV,SIGNAL_CAST SIG_DFL); +#endif +#ifdef SIGBUS + signal(SIGBUS,SIGNAL_CAST SIG_DFL); +#endif + return; /* this should cause a core dump */ + } + exit(1); +} + +/**************************************************************************** +catch serious errors +****************************************************************************/ +static void sig_fault(int sig) +{ + fault_report(sig); +} + +/******************************************************************* +setup our fault handlers +********************************************************************/ +void fault_setup(void (*fn)()) +{ + cont_fn = fn; + +#ifdef SIGSEGV + signal(SIGSEGV,SIGNAL_CAST sig_fault); +#endif +#ifdef SIGBUS + signal(SIGBUS,SIGNAL_CAST sig_fault); +#endif +} + + + diff --git a/source3/lib/getsmbpass.c b/source3/lib/getsmbpass.c new file mode 100644 index 0000000000..07a7dbfd9b --- /dev/null +++ b/source3/lib/getsmbpass.c @@ -0,0 +1,166 @@ +/* Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* Modified to use with samba by Jeremy Allison, 8th July 1995. */ + +#include "includes.h" + +#ifdef REPLACE_GETPASS + +#ifdef SYSV_TERMIO + +/* SYSTEM V TERMIO HANDLING */ + +static struct termio t; + +#define ECHO_IS_ON(t) ((t).c_lflag & ECHO) +#define TURN_ECHO_OFF(t) ((t).c_lflag &= ~ECHO) +#define TURN_ECHO_ON(t) ((t).c_lflag |= ECHO) + +#ifndef TCSAFLUSH +#define TCSAFLUSH 1 +#endif + +#ifndef TCSANOW +#define TCSANOW 0 +#endif + +int tcgetattr(int fd, struct termio *t) +{ + return ioctl(fd, TCGETA, t); +} + +int tcsetattr(int fd, int flags, const struct termio *t) +{ + if(flags & TCSAFLUSH) + ioctl(fd, TCFLSH, TCIOFLUSH); + return ioctl(fd, TCSETS, t); +} + +#else /* SYSV_TERMIO */ +#ifdef BSD_TERMIO + +/* BSD TERMIO HANDLING */ + +static struct sgttyb t; + +#define ECHO_IS_ON(t) ((t).sg_flags & ECHO) +#define TURN_ECHO_OFF(t) ((t).sg_flags &= ~ECHO) +#define TURN_ECHO_ON(t) ((t).sg_flags |= ECHO) + +#ifndef TCSAFLUSH +#define TCSAFLUSH 1 +#endif + +#ifndef TCSANOW +#define TCSANOW 0 +#endif + +int tcgetattr(int fd, struct sgttyb *t) +{ + return ioctl(fd, TIOCGETP, (char *)t); +} + +int tcsetattr(int fd, int flags, const struct sgttyb *t) +{ + return ioctl(fd, TIOCSETP, (char *)t); +} + +#else /* BSD_TERMIO */ + +/* POSIX TERMIO HANDLING */ +#define ECHO_IS_ON(t) ((t).c_lflag & ECHO) +#define TURN_ECHO_OFF(t) ((t).c_lflag &= ~ECHO) +#define TURN_ECHO_ON(t) ((t).c_lflag |= ECHO) + +static struct termios t; +#endif /* BSD_TERMIO */ +#endif /* SYSV_TERMIO */ + +char * +getsmbpass(char *prompt) +{ + FILE *in, *out; + int echo_off; + static char buf[256]; + static size_t bufsize = sizeof(buf); + size_t nread; + + /* Catch problematic signals */ + signal(SIGINT, SIGNAL_CAST SIG_IGN); + + /* Try to write to and read from the terminal if we can. + If we can't open the terminal, use stderr and stdin. */ + + in = fopen ("/dev/tty", "w+"); + if (in == NULL) + { + in = stdin; + out = stderr; + } + else + out = in; + + setvbuf(in, NULL, _IONBF, 0); + + /* Turn echoing off if it is on now. */ + + if (tcgetattr (fileno (in), &t) == 0) + { + if (ECHO_IS_ON(t)) + { + TURN_ECHO_OFF(t); + echo_off = tcsetattr (fileno (in), TCSAFLUSH, &t) == 0; + TURN_ECHO_ON(t); + } + else + echo_off = 0; + } + else + echo_off = 0; + + /* Write the prompt. */ + fputs (prompt, out); + fflush (out); + + /* Read the password. */ + buf[0] = 0; + fgets(buf, bufsize, in); + nread = strlen(buf); + if (buf[nread - 1] == '\n') + buf[nread - 1] = '\0'; + + /* Restore echoing. */ + if (echo_off) + (void) tcsetattr (fileno (in), TCSANOW, &t); + + if (in != stdin) + /* We opened the terminal; now close it. */ + fclose (in); + + /* Catch problematic signals */ + signal(SIGINT, SIGNAL_CAST SIG_DFL); + + printf("\n"); + return buf; +} + +#else + +void getsmbpasswd_dummy() {;} +#endif diff --git a/source3/lib/kanji.c b/source3/lib/kanji.c new file mode 100644 index 0000000000..0af476eb15 --- /dev/null +++ b/source3/lib/kanji.c @@ -0,0 +1,895 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Kanji Extensions + Copyright (C) Andrew Tridgell 1992-1994 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + Adding for Japanese language by <fujita@ainix.isac.co.jp> 1994.9.5 + and extend coding system to EUC/SJIS/JIS/HEX at 1994.10.11 + and add all jis codes sequence type at 1995.8.16 + Notes: Hexadecimal code by <ohki@gssm.otuka.tsukuba.ac.jp> +*/ +#ifdef KANJI + +#define _KANJI_C_ +#include "includes.h" + +/* coding system keep in */ +int coding_system = SJIS_CODE; + +/* jis si/so sequence */ +char jis_kso = JIS_KSO; +char jis_ksi = JIS_KSI; +char hex_tag = HEXTAG; + +/******************************************************************* + SHIFT JIS functions +********************************************************************/ +/******************************************************************* + search token from S1 separated any char of S2 + S1 contain SHIFT JIS chars. +********************************************************************/ +char * +sj_strtok (char *s1, const char *s2) +{ + static char *s = NULL; + char *q; + if (!s1) { + if (!s) { + return NULL; + } + s1 = s; + } + for (q = s1; *s1; ) { + if (is_shift_jis (*s1)) { + s1 += 2; + } else if (is_kana (*s1)) { + s1++; + } else { + char *p = strchr (s2, *s1); + if (p) { + if (s1 != q) { + s = s1 + 1; + *s1 = '\0'; + return q; + } + q = s1 + 1; + } + s1++; + } + } + s = NULL; + if (*q) { + return q; + } + return NULL; +} + +/******************************************************************* + search string S2 from S1 + S1 contain SHIFT JIS chars. +********************************************************************/ +char * +sj_strstr (const char *s1, const char *s2) +{ + register int len = strlen ((char *) s2); + if (!*s2) + return (char *) s1; + for (;*s1;) { + if (*s1 == *s2) { + if (strncmp (s1, s2, len) == 0) + return (char *) s1; + } + if (is_shift_jis (*s1)) { + s1 += 2; + } else { + s1++; + } + } + return 0; +} + +/******************************************************************* + Search char C from beginning of S. + S contain SHIFT JIS chars. +********************************************************************/ +char * +sj_strchr (const char *s, int c) +{ + for (; *s; ) { + if (*s == c) + return (char *) s; + if (is_shift_jis (*s)) { + s += 2; + } else { + s++; + } + } + return 0; +} + +/******************************************************************* + Search char C end of S. + S contain SHIFT JIS chars. +********************************************************************/ +char * +sj_strrchr (const char *s, int c) +{ + register char *q; + + for (q = 0; *s; ) { + if (*s == c) { + q = (char *) s; + } + if (is_shift_jis (*s)) { + s += 2; + } else { + s++; + } + } + return q; +} + +/******************************************************************* + Code conversion +********************************************************************/ +/* convesion buffer */ +static char cvtbuf[1024]; + +/******************************************************************* + EUC <-> SJIS +********************************************************************/ +static int +euc2sjis (register int hi, register int lo) +{ + if (hi & 1) + return ((hi / 2 + (hi < 0xdf ? 0x31 : 0x71)) << 8) | + (lo - (lo >= 0xe0 ? 0x60 : 0x61)); + else + return ((hi / 2 + (hi < 0xdf ? 0x30 : 0x70)) << 8) | (lo - 2); +} + +static int +sjis2euc (register int hi, register int lo) +{ + if (lo >= 0x9f) + return ((hi * 2 - (hi >= 0xe0 ? 0xe0 : 0x60)) << 8) | (lo + 2); + else + return ((hi * 2 - (hi >= 0xe0 ? 0xe1 : 0x61)) << 8) | + (lo + (lo >= 0x7f ? 0x60 : 0x61)); +} + +/******************************************************************* + Convert FROM contain SHIFT JIS codes to EUC codes + return converted buffer +********************************************************************/ +static char * +sj_to_euc (const char *from, BOOL overwrite) +{ + register char *out; + char *save; + + save = (char *) from; + for (out = cvtbuf; *from;) { + if (is_shift_jis (*from)) { + int code = sjis2euc ((int) from[0] & 0xff, (int) from[1] & 0xff); + *out++ = (code >> 8) & 0xff; + *out++ = code; + from += 2; + } else if (is_kana (*from)) { + *out++ = euc_kana; + *out++ = *from++; + } else { + *out++ = *from++; + } + } + *out = 0; + if (overwrite) { + strcpy((char *) save, (char *) cvtbuf); + return (char *) save; + } else { + return cvtbuf; + } +} + +/******************************************************************* + Convert FROM contain EUC codes to SHIFT JIS codes + return converted buffer +********************************************************************/ +static char * +euc_to_sj (const char *from, BOOL overwrite) +{ + register char *out; + char *save; + + save = (char *) from; + for (out = cvtbuf; *from; ) { + if (is_euc (*from)) { + int code = euc2sjis ((int) from[0] & 0xff, (int) from[1] & 0xff); + *out++ = (code >> 8) & 0xff; + *out++ = code; + from += 2; + } else if (is_euc_kana (*from)) { + *out++ = from[1]; + from += 2; + } else { + *out++ = *from++; + } + } + *out = 0; + if (overwrite) { + strcpy(save, (char *) cvtbuf); + return save; + } else { + return cvtbuf; + } +} + +/******************************************************************* + JIS7,JIS8,JUNET <-> SJIS +********************************************************************/ +static int +sjis2jis (register int hi, register int lo) +{ + if (lo >= 0x9f) + return ((hi * 2 - (hi >= 0xe0 ? 0x160 : 0xe0)) << 8) | (lo - 0x7e); + else + return ((hi * 2 - (hi >= 0xe0 ? 0x161 : 0xe1)) << 8) | + (lo - (lo >= 0x7f ? 0x20 : 0x1f)); +} + +static int +jis2sjis (register int hi, register int lo) +{ + if (hi & 1) + return ((hi / 2 + (hi < 0x5f ? 0x71 : 0xb1)) << 8) | + (lo + (lo >= 0x60 ? 0x20 : 0x1f)); + else + return ((hi / 2 + (hi < 0x5f ? 0x70 : 0xb0)) << 8) | (lo + 0x7e); +} + +/******************************************************************* + Convert FROM contain JIS codes to SHIFT JIS codes + return converted buffer +********************************************************************/ +static char * +jis8_to_sj (const char *from, BOOL overwrite) +{ + register char *out; + register int shifted; + char *save; + + shifted = _KJ_ROMAN; + save = (char *) from; + for (out = cvtbuf; *from;) { + if (is_esc (*from)) { + if (is_so1 (from[1]) && is_so2 (from[2])) { + shifted = _KJ_KANJI; + from += 3; + } else if (is_si1 (from[1]) && is_si2 (from[2])) { + shifted = _KJ_ROMAN; + from += 3; + } else { /* sequence error */ + goto normal; + } + } else { + normal: + switch (shifted) { + default: + case _KJ_ROMAN: + *out++ = *from++; + break; + case _KJ_KANJI: + { + int code = jis2sjis ((int) from[0] & 0xff, (int) from[1] & 0xff); + *out++ = (code >> 8) & 0xff; + *out++ = code; + from += 2; + } + break; + } + } + } + *out = 0; + if (overwrite) { + strcpy (save, (char *) cvtbuf); + return save; + } else { + return cvtbuf; + } +} + +/******************************************************************* + Convert FROM contain SHIFT JIS codes to JIS codes + return converted buffer +********************************************************************/ +static char * +sj_to_jis8 (const char *from, BOOL overwrite) +{ + register char *out; + register int shifted; + char *save; + + shifted = _KJ_ROMAN; + save = (char *) from; + for (out = cvtbuf; *from; ) { + if (is_shift_jis (*from)) { + int code; + switch (shifted) { + case _KJ_ROMAN: /* to KANJI */ + *out++ = jis_esc; + *out++ = jis_so1; + *out++ = jis_kso; + shifted = _KJ_KANJI; + break; + } + code = sjis2jis ((int) from[0] & 0xff, (int) from[1] & 0xff); + *out++ = (code >> 8) & 0xff; + *out++ = code; + from += 2; + } else { + switch (shifted) { + case _KJ_KANJI: /* to ROMAN/KANA */ + *out++ = jis_esc; + *out++ = jis_si1; + *out++ = jis_ksi; + shifted = _KJ_ROMAN; + break; + } + *out++ = *from++; + } + } + switch (shifted) { + case _KJ_KANJI: /* to ROMAN/KANA */ + *out++ = jis_esc; + *out++ = jis_si1; + *out++ = jis_ksi; + shifted = _KJ_ROMAN; + break; + } + *out = 0; + if (overwrite) { + strcpy (save, (char *) cvtbuf); + return save; + } else { + return cvtbuf; + } +} + +/******************************************************************* + Convert FROM contain 7 bits JIS codes to SHIFT JIS codes + return converted buffer +********************************************************************/ +static char * +jis7_to_sj (const char *from, BOOL overwrite) +{ + register char *out; + register int shifted; + char *save; + + shifted = _KJ_ROMAN; + save = (char *) from; + for (out = cvtbuf; *from;) { + if (is_esc (*from)) { + if (is_so1 (from[1]) && is_so2 (from[2])) { + shifted = _KJ_KANJI; + from += 3; + } else if (is_si1 (from[1]) && is_si2 (from[2])) { + shifted = _KJ_ROMAN; + from += 3; + } else { /* sequence error */ + goto normal; + } + } else if (is_so (*from)) { + shifted = _KJ_KANA; /* to KANA */ + from++; + } else if (is_si (*from)) { + shifted = _KJ_ROMAN; /* to ROMAN */ + from++; + } else { + normal: + switch (shifted) { + default: + case _KJ_ROMAN: + *out++ = *from++; + break; + case _KJ_KANJI: + { + int code = jis2sjis ((int) from[0] & 0xff, (int) from[1] & 0xff); + *out++ = (code >> 8) & 0xff; + *out++ = code; + from += 2; + } + break; + case _KJ_KANA: + *out++ = ((int) from[0]) + 0x80; + break; + } + } + } + *out = 0; + if (overwrite) { + strcpy (save, (char *) cvtbuf); + return save; + } else { + return cvtbuf; + } +} + +/******************************************************************* + Convert FROM contain SHIFT JIS codes to 7 bits JIS codes + return converted buffer +********************************************************************/ +static char * +sj_to_jis7 (const char *from, BOOL overwrite) +{ + register char *out; + register int shifted; + char *save; + + shifted = _KJ_ROMAN; + save = (char *) from; + for (out = cvtbuf; *from; ) { + if (is_shift_jis (*from)) { + int code; + switch (shifted) { + case _KJ_KANA: + *out++ = jis_si; /* to ROMAN and through down */ + case _KJ_ROMAN: /* to KANJI */ + *out++ = jis_esc; + *out++ = jis_so1; + *out++ = jis_kso; + shifted = _KJ_KANJI; + break; + } + code = sjis2jis ((int) from[0] & 0xff, (int) from[1] & 0xff); + *out++ = (code >> 8) & 0xff; + *out++ = code; + from += 2; + } else if (is_kana (from[0])) { + switch (shifted) { + case _KJ_KANJI: /* to ROMAN */ + *out++ = jis_esc; + *out++ = jis_si1; + *out++ = jis_ksi; + case _KJ_ROMAN: /* to KANA */ + *out++ = jis_so; + shifted = _KJ_KANA; + break; + } + *out++ = ((int) *from++) - 0x80; + } else { + switch (shifted) { + case _KJ_KANA: + *out++ = jis_si; /* to ROMAN */ + shifted = _KJ_ROMAN; + break; + case _KJ_KANJI: /* to ROMAN */ + *out++ = jis_esc; + *out++ = jis_si1; + *out++ = jis_ksi; + shifted = _KJ_ROMAN; + break; + } + *out++ = *from++; + } + } + switch (shifted) { + case _KJ_KANA: + *out++ = jis_si; /* to ROMAN */ + break; + case _KJ_KANJI: /* to ROMAN */ + *out++ = jis_esc; + *out++ = jis_si1; + *out++ = jis_ksi; + break; + } + *out = 0; + if (overwrite) { + strcpy (save, (char *) cvtbuf); + return save; + } else { + return cvtbuf; + } +} + +/******************************************************************* + Convert FROM contain 7 bits JIS(junet) codes to SHIFT JIS codes + return converted buffer +********************************************************************/ +static char * +junet_to_sj (const char *from, BOOL overwrite) +{ + register char *out; + register int shifted; + char *save; + + shifted = _KJ_ROMAN; + save = (char *) from; + for (out = cvtbuf; *from;) { + if (is_esc (*from)) { + if (is_so1 (from[1]) && is_so2 (from[2])) { + shifted = _KJ_KANJI; + from += 3; + } else if (is_si1 (from[1]) && is_si2 (from[2])) { + shifted = _KJ_ROMAN; + from += 3; + } else if (is_juk1(from[1]) && is_juk2 (from[2])) { + shifted = _KJ_KANA; + from += 3; + } else { /* sequence error */ + goto normal; + } + } else { + normal: + switch (shifted) { + default: + case _KJ_ROMAN: + *out++ = *from++; + break; + case _KJ_KANJI: + { + int code = jis2sjis ((int) from[0] & 0xff, (int) from[1] & 0xff); + *out++ = (code >> 8) & 0xff; + *out++ = code; + from += 2; + } + break; + case _KJ_KANA: + *out++ = ((int) from[0]) + 0x80; + break; + } + } + } + *out = 0; + if (overwrite) { + strcpy (save, (char *) cvtbuf); + return save; + } else { + return cvtbuf; + } +} + +/******************************************************************* + Convert FROM contain SHIFT JIS codes to 7 bits JIS(junet) codes + return converted buffer +********************************************************************/ +static char * +sj_to_junet (const char *from, BOOL overwrite) +{ + register char *out; + register int shifted; + char *save; + + shifted = _KJ_ROMAN; + save = (char *) from; + for (out = cvtbuf; *from; ) { + if (is_shift_jis (*from)) { + int code; + switch (shifted) { + case _KJ_KANA: + case _KJ_ROMAN: /* to KANJI */ + *out++ = jis_esc; + *out++ = jis_so1; + *out++ = jis_so2; + shifted = _KJ_KANJI; + break; + } + code = sjis2jis ((int) from[0] & 0xff, (int) from[1] & 0xff); + *out++ = (code >> 8) & 0xff; + *out++ = code; + from += 2; + } else if (is_kana (from[0])) { + switch (shifted) { + case _KJ_KANJI: /* to ROMAN */ + case _KJ_ROMAN: /* to KANA */ + *out++ = jis_esc; + *out++ = junet_kana1; + *out++ = junet_kana2; + shifted = _KJ_KANA; + break; + } + *out++ = ((int) *from++) - 0x80; + } else { + switch (shifted) { + case _KJ_KANA: + case _KJ_KANJI: /* to ROMAN */ + *out++ = jis_esc; + *out++ = jis_si1; + *out++ = jis_si2; + shifted = _KJ_ROMAN; + break; + } + *out++ = *from++; + } + } + switch (shifted) { + case _KJ_KANA: + case _KJ_KANJI: /* to ROMAN */ + *out++ = jis_esc; + *out++ = jis_si1; + *out++ = jis_si2; + break; + } + *out = 0; + if (overwrite) { + strcpy (save, (char *) cvtbuf); + return save; + } else { + return cvtbuf; + } +} + +/******************************************************************* + HEX <-> SJIS +********************************************************************/ +/* ":xx" -> a byte */ +static char * +hex_to_sj (const char *from, BOOL overwrite) +{ + char *sp, *dp; + + sp = (char *) from; + dp = cvtbuf; + while (*sp) { + if (*sp == hex_tag && isxdigit (sp[1]) && isxdigit (sp[2])) { + *dp++ = (hex2bin (sp[1])<<4) | (hex2bin (sp[2])); + sp += 3; + } else + *dp++ = *sp++; + } + *dp = '\0'; + if (overwrite) { + strcpy ((char *) from, (char *) cvtbuf); + return (char *) from; + } else { + return cvtbuf; + } +} + +/******************************************************************* + kanji/kana -> ":xx" +********************************************************************/ +static char * +sj_to_hex (const char *from, BOOL overwrite) +{ + unsigned char *sp, *dp; + + sp = (unsigned char*) from; + dp = (unsigned char*) cvtbuf; + while (*sp) { + if (is_kana(*sp)) { + *dp++ = hex_tag; + *dp++ = bin2hex (((*sp)>>4)&0x0f); + *dp++ = bin2hex ((*sp)&0x0f); + sp++; + } else if (is_shift_jis (*sp) && is_shift_jis2 (sp[1])) { + *dp++ = hex_tag; + *dp++ = bin2hex (((*sp)>>4)&0x0f); + *dp++ = bin2hex ((*sp)&0x0f); + sp++; + *dp++ = hex_tag; + *dp++ = bin2hex (((*sp)>>4)&0x0f); + *dp++ = bin2hex ((*sp)&0x0f); + sp++; + } else + *dp++ = *sp++; + } + *dp = '\0'; + if (overwrite) { + strcpy ((char *) from, (char *) cvtbuf); + return (char *) from; + } else { + return cvtbuf; + } +} + +/******************************************************************* + kanji/kana -> ":xx" +********************************************************************/ +static char * +sj_to_cap (const char *from, BOOL overwrite) +{ + unsigned char *sp, *dp; + + sp = (unsigned char*) from; + dp = (unsigned char*) cvtbuf; + while (*sp) { + if (*sp >= 0x80) { + *dp++ = hex_tag; + *dp++ = bin2hex (((*sp)>>4)&0x0f); + *dp++ = bin2hex ((*sp)&0x0f); + sp++; + } else { + *dp++ = *sp++; + } + } + *dp = '\0'; + if (overwrite) { + strcpy ((char *) from, (char *) cvtbuf); + return (char *) from; + } else { + return cvtbuf; + } +} + +/******************************************************************* + sj to sj +********************************************************************/ +static char * +sj_to_sj (const char *from, BOOL overwrite) +{ + if (!overwrite) { + strcpy (cvtbuf, (char *) from); + return cvtbuf; + } else { + return (char *) from; + } +} + +/************************************************************************ + conversion: + _dos_to_unix _unix_to_dos +************************************************************************/ + +char* (*_dos_to_unix) (const char *str, BOOL overwrite) = sj_to_sj; +char* (*_unix_to_dos) (const char *str, BOOL overwrite) = sj_to_sj; + +static int +setup_string_function (int codes) +{ + switch (codes) { + default: + case SJIS_CODE: + _dos_to_unix = sj_to_sj; + _unix_to_dos = sj_to_sj; + + break; + + case EUC_CODE: + _dos_to_unix = sj_to_euc; + _unix_to_dos = euc_to_sj; + break; + + case JIS7_CODE: + _dos_to_unix = sj_to_jis7; + _unix_to_dos = jis7_to_sj; + break; + + case JIS8_CODE: + _dos_to_unix = sj_to_jis8; + _unix_to_dos = jis8_to_sj; + break; + + case JUNET_CODE: + _dos_to_unix = sj_to_junet; + _unix_to_dos = junet_to_sj; + break; + + case HEX_CODE: + _dos_to_unix = sj_to_hex; + _unix_to_dos = hex_to_sj; + break; + + case CAP_CODE: + _dos_to_unix = sj_to_cap; + _unix_to_dos = hex_to_sj; + break; + } + return codes; +} + +/* + * Interpret coding system. + */ +int +interpret_coding_system (char *str, int def) +{ + int codes = def; + + if (strequal (str, "sjis")) { + codes = SJIS_CODE; + } else if (strequal (str, "euc")) { + codes = EUC_CODE; + } else if (strequal (str, "cap")) { + codes = CAP_CODE; + hex_tag = HEXTAG; + } else if (strequal (str, "hex")) { + codes = HEX_CODE; + hex_tag = HEXTAG; + } else if (strncasecmp (str, "hex", 3)) { + codes = HEX_CODE; + hex_tag = (str[3] ? str[3] : HEXTAG); + } else if (strequal (str, "j8bb")) { + codes = JIS8_CODE; + jis_kso = 'B'; + jis_ksi = 'B'; + } else if (strequal (str, "j8bj") || strequal (str, "jis8")) { + codes = JIS8_CODE; + jis_kso = 'B'; + jis_ksi = 'J'; + } else if (strequal (str, "j8bh")) { + codes = JIS8_CODE; + jis_kso = 'B'; + jis_ksi = 'H'; + } else if (strequal (str, "j8@b")) { + codes = JIS8_CODE; + jis_kso = '@'; + jis_ksi = 'B'; + } else if (strequal (str, "j8@j")) { + codes = JIS8_CODE; + jis_kso = '@'; + jis_ksi = 'J'; + } else if (strequal (str, "j8@h")) { + codes = JIS8_CODE; + jis_kso = '@'; + jis_ksi = 'H'; + } else if (strequal (str, "j7bb")) { + codes = JIS7_CODE; + jis_kso = 'B'; + jis_ksi = 'B'; + } else if (strequal (str, "j7bj") || strequal (str, "jis7")) { + codes = JIS7_CODE; + jis_kso = 'B'; + jis_ksi = 'J'; + } else if (strequal (str, "j7bh")) { + codes = JIS7_CODE; + jis_kso = 'B'; + jis_ksi = 'H'; + } else if (strequal (str, "j7@b")) { + codes = JIS7_CODE; + jis_kso = '@'; + jis_ksi = 'B'; + } else if (strequal (str, "j7@j")) { + codes = JIS7_CODE; + jis_kso = '@'; + jis_ksi = 'J'; + } else if (strequal (str, "j7@h")) { + codes = JIS7_CODE; + jis_kso = '@'; + jis_ksi = 'H'; + } else if (strequal (str, "jubb")) { + codes = JUNET_CODE; + jis_kso = 'B'; + jis_ksi = 'B'; + } else if (strequal (str, "jubj") || strequal (str, "junet")) { + codes = JUNET_CODE; + jis_kso = 'B'; + jis_ksi = 'J'; + } else if (strequal (str, "jubh")) { + codes = JUNET_CODE; + jis_kso = 'B'; + jis_ksi = 'H'; + } else if (strequal (str, "ju@b")) { + codes = JUNET_CODE; + jis_kso = '@'; + jis_ksi = 'B'; + } else if (strequal (str, "ju@j")) { + codes = JUNET_CODE; + jis_kso = '@'; + jis_ksi = 'J'; + } else if (strequal (str, "ju@h")) { + codes = JUNET_CODE; + jis_kso = '@'; + jis_ksi = 'H'; + } + return setup_string_function (codes); +} +#else +int kanji_dummy_procedure(void) +{return 0;} +#endif /* KANJI */ diff --git a/source3/lib/md4.c b/source3/lib/md4.c new file mode 100644 index 0000000000..485e231a78 --- /dev/null +++ b/source3/lib/md4.c @@ -0,0 +1,299 @@ +#ifdef SMB_PASSWD +/* + This code is from rfc1186. +*/ + + /* + ** ******************************************************************** + ** md4.c -- Implementation of MD4 Message Digest Algorithm ** + ** Updated: 2/16/90 by Ronald L. Rivest ** + ** (C) 1990 RSA Data Security, Inc. ** + ** ******************************************************************** + */ + + /* + ** To use MD4: + ** -- Include md4.h in your program + ** -- Declare an MDstruct MD to hold the state of the digest + ** computation. + ** -- Initialize MD using MDbegin(&MD) + ** -- For each full block (64 bytes) X you wish to process, call + ** MDupdate(&MD,X,512) + ** (512 is the number of bits in a full block.) + ** -- For the last block (less than 64 bytes) you wish to process, + ** MDupdate(&MD,X,n) + ** where n is the number of bits in the partial block. A partial + ** block terminates the computation, so every MD computation + ** should terminate by processing a partial block, even if it + ** has n = 0. + ** -- The message digest is available in MD.buffer[0] ... + ** MD.buffer[3]. (Least-significant byte of each word + ** should be output first.) + ** -- You can print out the digest using MDprint(&MD) + */ + + /* Implementation notes: + ** This implementation assumes that ints are 32-bit quantities. + ** If the machine stores the least-significant byte of an int in the + ** least-addressed byte (e.g., VAX and 8086), then LOWBYTEFIRST + ** should be set to TRUE. Otherwise (e.g., SUNS), LOWBYTEFIRST + ** should be set to FALSE. Note that on machines with LOWBYTEFIRST + ** FALSE the routine MDupdate modifies has a side-effect on its input + ** array (the order of bytes in each word are reversed). If this is + ** undesired a call to MDreverse(X) can reverse the bytes of X back + ** into order after each call to MDupdate. + */ + +#define TRUE 1 +#define FALSE 0 + + /* Compile-time includes + */ + +#include <stdio.h> +#include "md4.h" + +#define uchar unsigned char +#define int16 unsigned short +#define uint32 unsigned int + +#include "byteorder.h" + + /* Compile-time declarations of MD4 "magic constants". + */ +#define I0 0x67452301 /* Initial values for MD buffer */ +#define I1 0xefcdab89 +#define I2 0x98badcfe +#define I3 0x10325476 +#define C2 013240474631 /* round 2 constant = sqrt(2) in octal */ +#define C3 015666365641 /* round 3 constant = sqrt(3) in octal */ + /* C2 and C3 are from Knuth, The Art of Programming, Volume 2 + ** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley. + ** Table 2, page 660. + */ + +#define fs1 3 /* round 1 shift amounts */ +#define fs2 7 +#define fs3 11 +#define fs4 19 +#define gs1 3 /* round 2 shift amounts */ +#define gs2 5 +#define gs3 9 +#define gs4 13 +#define hs1 3 /* round 3 shift amounts */ +#define hs2 9 +#define hs3 11 +#define hs4 15 + + /* Compile-time macro declarations for MD4. + ** Note: The "rot" operator uses the variable "tmp". + ** It assumes tmp is declared as unsigned int, so that the >> + ** operator will shift in zeros rather than extending the sign bit. + */ +#define f(X,Y,Z) ((X&Y) | ((~X)&Z)) +#define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z)) +#define h(X,Y,Z) (X^Y^Z) +#define rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S))) +#define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s) +#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s) +#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s) + + /* MDprint(MDp) + ** Print message digest buffer MDp as 32 hexadecimal digits. + ** Order is from low-order byte of buffer[0] to high-order byte of + ** buffer[3]. + ** Each byte is printed with high-order hexadecimal digit first. + ** This is a user-callable routine. + */ + void + MDprint(MDp) + MDptr MDp; + { int i,j; + for (i=0;i<4;i++) + for (j=0;j<32;j=j+8) + printf("%02x",(MDp->buffer[i]>>j) & 0xFF); + } + + /* MDbegin(MDp) + ** Initialize message digest buffer MDp. + ** This is a user-callable routine. + */ + void + MDbegin(MDp) + MDptr MDp; + { int i; + MDp->buffer[0] = I0; + MDp->buffer[1] = I1; + MDp->buffer[2] = I2; + MDp->buffer[3] = I3; + for (i=0;i<8;i++) MDp->count[i] = 0; + MDp->done = 0; + } + + /* MDreverse(X) + ** Reverse the byte-ordering of every int in X. + ** Assumes X is an array of 16 ints. + ** The macro revx reverses the byte-ordering of the next word of X. + */ + void MDreverse(X) + unsigned int *X; + { register unsigned int t; + register unsigned int i; + + for(i = 0; i < 16; i++) { + t = X[i]; + SIVAL(X,i*4,t); + } + } + + /* MDblock(MDp,X) + ** Update message digest buffer MDp->buffer using 16-word data block X. + ** Assumes all 16 words of X are full of data. + ** Does not update MDp->count. + ** This routine is not user-callable. + */ + static void + MDblock(MDp,X) + MDptr MDp; + unsigned int *X; + { + register unsigned int tmp, A, B, C, D; + MDreverse(X); + A = MDp->buffer[0]; + B = MDp->buffer[1]; + C = MDp->buffer[2]; + D = MDp->buffer[3]; + /* Update the message digest buffer */ + ff(A , B , C , D , 0 , fs1); /* Round 1 */ + ff(D , A , B , C , 1 , fs2); + ff(C , D , A , B , 2 , fs3); + ff(B , C , D , A , 3 , fs4); + ff(A , B , C , D , 4 , fs1); + ff(D , A , B , C , 5 , fs2); + ff(C , D , A , B , 6 , fs3); + ff(B , C , D , A , 7 , fs4); + ff(A , B , C , D , 8 , fs1); + ff(D , A , B , C , 9 , fs2); + ff(C , D , A , B , 10 , fs3); + ff(B , C , D , A , 11 , fs4); + ff(A , B , C , D , 12 , fs1); + ff(D , A , B , C , 13 , fs2); + ff(C , D , A , B , 14 , fs3); + ff(B , C , D , A , 15 , fs4); + gg(A , B , C , D , 0 , gs1); /* Round 2 */ + gg(D , A , B , C , 4 , gs2); + gg(C , D , A , B , 8 , gs3); + gg(B , C , D , A , 12 , gs4); + gg(A , B , C , D , 1 , gs1); + gg(D , A , B , C , 5 , gs2); + gg(C , D , A , B , 9 , gs3); + gg(B , C , D , A , 13 , gs4); + gg(A , B , C , D , 2 , gs1); + gg(D , A , B , C , 6 , gs2); + gg(C , D , A , B , 10 , gs3); + gg(B , C , D , A , 14 , gs4); + gg(A , B , C , D , 3 , gs1); + gg(D , A , B , C , 7 , gs2); + gg(C , D , A , B , 11 , gs3); + gg(B , C , D , A , 15 , gs4); + hh(A , B , C , D , 0 , hs1); /* Round 3 */ + hh(D , A , B , C , 8 , hs2); + hh(C , D , A , B , 4 , hs3); + hh(B , C , D , A , 12 , hs4); + hh(A , B , C , D , 2 , hs1); + hh(D , A , B , C , 10 , hs2); + hh(C , D , A , B , 6 , hs3); + hh(B , C , D , A , 14 , hs4); + hh(A , B , C , D , 1 , hs1); + hh(D , A , B , C , 9 , hs2); + hh(C , D , A , B , 5 , hs3); + hh(B , C , D , A , 13 , hs4); + hh(A , B , C , D , 3 , hs1); + hh(D , A , B , C , 11 , hs2); + hh(C , D , A , B , 7 , hs3); + hh(B , C , D , A , 15 , hs4); + MDp->buffer[0] += A; + MDp->buffer[1] += B; + MDp->buffer[2] += C; + MDp->buffer[3] += D; + } + + /* MDupdate(MDp,X,count) + ** Input: MDp -- an MDptr + ** X -- a pointer to an array of unsigned characters. + ** count -- the number of bits of X to use. + ** (if not a multiple of 8, uses high bits of last byte.) + ** Update MDp using the number of bits of X given by count. + ** This is the basic input routine for an MD4 user. + ** The routine completes the MD computation when count < 512, so + ** every MD computation should end with one call to MDupdate with a + ** count less than 512. A call with count 0 will be ignored if the + ** MD has already been terminated (done != 0), so an extra call with + ** count 0 can be given as a "courtesy close" to force termination + ** if desired. + */ + void + MDupdate(MDp,X,count) + MDptr MDp; + unsigned char *X; + unsigned int count; + { unsigned int i, tmp, bit, byte, mask; + unsigned char XX[64]; + unsigned char *p; + /* return with no error if this is a courtesy close with count + ** zero and MDp->done is true. + */ + if (count == 0 && MDp->done) return; + /* check to see if MD is already done and report error */ + if (MDp->done) + { printf("\nError: MDupdate MD already done."); return; } + /* Add count to MDp->count */ + tmp = count; + p = MDp->count; + while (tmp) + { tmp += *p; + *p++ = tmp; + tmp = tmp >> 8; + } + /* Process data */ + if (count == 512) + { /* Full block of data to handle */ + MDblock(MDp,(unsigned int *)X); + } + else if (count > 512) /* Check for count too large */ + { printf("\nError: MDupdate called with illegal count value %d." + ,count); + return; + } + else /* partial block -- must be last block so finish up */ + { /* Find out how many bytes and residual bits there are */ + byte = count >> 3; + bit = count & 7; + /* Copy X into XX since we need to modify it */ + for (i=0;i<=byte;i++) XX[i] = X[i]; + for (i=byte+1;i<64;i++) XX[i] = 0; + /* Add padding '1' bit and low-order zeros in last byte */ + mask = 1 << (7 - bit); + XX[byte] = (XX[byte] | mask) & ~( mask - 1); + /* If room for bit count, finish up with this block */ + if (byte <= 55) + { for (i=0;i<8;i++) XX[56+i] = MDp->count[i]; + MDblock(MDp,(unsigned int *)XX); + } + else /* need to do two blocks to finish up */ + { MDblock(MDp,(unsigned int *)XX); + for (i=0;i<56;i++) XX[i] = 0; + for (i=0;i<8;i++) XX[56+i] = MDp->count[i]; + MDblock(MDp,(unsigned int *)XX); + } + /* Set flag saying we're done with MD computation */ + MDp->done = 1; + } + } + + /* + ** End of md4.c + */ +#else +void md4_dummy() {;} +#endif diff --git a/source3/lib/system.c b/source3/lib/system.c new file mode 100644 index 0000000000..938746e9c9 --- /dev/null +++ b/source3/lib/system.c @@ -0,0 +1,222 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Samba system utilities + Copyright (C) Andrew Tridgell 1992-1995 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +extern int DEBUGLEVEL; + +/* + The idea is that this file will eventually have wrappers around all + important system calls in samba. The aim is twofold: + + - to enable easier porting by putting OS dependent stuff in here + + - to allow for hooks into other "pseudo-filesystems" + + - to allow easier integration of things like the japanese extensions +*/ + + +/******************************************************************* +this replaces the normal select() system call +return if some data has arrived on one of the file descriptors +return -1 means error +********************************************************************/ +#ifdef NO_SELECT +static int pollfd(int fd) +{ + int r=0; + +#ifdef HAS_RDCHK + r = rdchk(fd); +#elif defined(TCRDCHK) + (void)ioctl(fd, TCRDCHK, &r); +#else + (void)ioctl(fd, FIONREAD, &r); +#endif + + return(r); +} + +int sys_select(fd_set *fds,struct timeval *tval) +{ + fd_set fds2; + int counter=0; + int found=0; + + FD_ZERO(&fds2); + + while (1) + { + int i; + for (i=0;i<255;i++) { + if (FD_ISSET(i,fds) && pollfd(i)>0) { + found++; + FD_SET(i,&fds2); + } + } + + if (found) { + memcpy((void *)fds,(void *)&fds2,sizeof(fds2)); + return(found); + } + + if (tval && tval.tv_sec < counter) return(0); + sleep(1); + counter++; + } +} + +#else +int sys_select(fd_set *fds,struct timeval *tval) +{ + struct timeval t2; + int selrtn; + + do { + if (tval) memcpy((void *)&t2,(void *)tval,sizeof(t2)); + errno = 0; + selrtn = select(16,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL); + } while (selrtn<0 && errno == EINTR); + + return(selrtn); +} +#endif + + +/******************************************************************* +just a unlink wrapper +********************************************************************/ +int sys_unlink(char *fname) +{ + return(unlink(dos_to_unix(fname,False))); +} + + +/******************************************************************* +a simple open() wrapper +********************************************************************/ +int sys_open(char *fname,int flags,int mode) +{ + return(open(dos_to_unix(fname,False),flags,mode)); +} + + +/******************************************************************* +a simple opendir() wrapper +********************************************************************/ +DIR *sys_opendir(char *dname) +{ + return(opendir(dos_to_unix(dname,False))); +} + + +/******************************************************************* +and a stat() wrapper +********************************************************************/ +int sys_stat(char *fname,struct stat *sbuf) +{ + return(stat(dos_to_unix(fname,False),sbuf)); +} + +/******************************************************************* +don't forget lstat() +********************************************************************/ +int sys_lstat(char *fname,struct stat *sbuf) +{ + return(lstat(dos_to_unix(fname,False),sbuf)); +} + + +/******************************************************************* +mkdir() gets a wrapper +********************************************************************/ +int sys_mkdir(char *dname,int mode) +{ + return(mkdir(dos_to_unix(dname,False),mode)); +} + + +/******************************************************************* +do does rmdir() +********************************************************************/ +int sys_rmdir(char *dname) +{ + return(rmdir(dos_to_unix(dname,False))); +} + + +/******************************************************************* +I almost forgot chdir() +********************************************************************/ +int sys_chdir(char *dname) +{ + return(chdir(dos_to_unix(dname,False))); +} + + +/******************************************************************* +now for utime() +********************************************************************/ +int sys_utime(char *fname,struct utimbuf *times) +{ + return(utime(dos_to_unix(fname,False),times)); +} + +/******************************************************************* +for rename() +********************************************************************/ +int sys_rename(char *from, char *to) +{ +#ifdef KANJI + pstring zfrom, zto; + strcpy (zfrom, dos_to_unix (from, False)); + strcpy (zto, dos_to_unix (to, False)); + return rename (zfrom, zto); +#else + return rename (from, to); +#endif /* KANJI */ +} + + +/******************************************************************* +chown isn't used much but OS/2 doesn't have it +********************************************************************/ +int sys_chown(char *fname,int uid,int gid) +{ +#ifdef NO_CHOWN + DEBUG(1,("Warning - chown(%s,%d,%d) not done\n",fname,uid,gid)); +#else + return(chown(fname,uid,gid)); +#endif +} + +/******************************************************************* +os/2 also doesn't have chroot +********************************************************************/ +int sys_chroot(char *dname) +{ +#ifdef NO_CHROOT + DEBUG(1,("Warning - chroot(%s) not done\n",dname)); +#else + return(chroot(dname)); +#endif +} diff --git a/source3/lib/ufc.c b/source3/lib/ufc.c new file mode 100644 index 0000000000..8417285821 --- /dev/null +++ b/source3/lib/ufc.c @@ -0,0 +1,782 @@ +/* + This bit of code was derived from the UFC-crypt package which + carries the following copyright + + Modified for use by Samba by Andrew Tridgell, October 1994 + + Note that this routine is only faster on some machines. Under Linux 1.1.51 + libc 4.5.26 I actually found this routine to be slightly slower. + + Under SunOS I found a huge speedup by using these routines + (a factor of 20 or so) + + Warning: I've had a report from Steve Kennedy <steve@gbnet.org> + that this crypt routine may sometimes get the wrong answer. Only + use UFC_CRYT if you really need it. + +*/ + +#ifdef UFC_CRYPT + +/* + * UFC-crypt: ultra fast crypt(3) implementation + * + * Copyright (C) 1991, 1992, Free Software Foundation, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * @(#)crypt_util.c 2.31 02/08/92 + * + * Support routines + * + */ +#include "includes.h" + + +#ifndef long32 +#define long32 int32 +#endif + +#ifndef long64 +#define long64 int64 +#endif + +#ifndef ufc_long +#define ufc_long unsigned +#endif + +#ifndef _UFC_64_ +#define _UFC_32_ +#endif + +/* + * Permutation done once on the 56 bit + * key derived from the original 8 byte ASCII key. + */ +static int pc1[56] = { + 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 +}; + +/* + * How much to rotate each 28 bit half of the pc1 permutated + * 56 bit key before using pc2 to give the i' key + */ +static int rots[16] = { + 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 +}; + +/* + * Permutation giving the key + * of the i' DES round + */ +static int pc2[48] = { + 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 +}; + +/* + * The E expansion table which selects + * bits from the 32 bit intermediate result. + */ +static int esel[48] = { + 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1 +}; +static int e_inverse[64]; + +/* + * Permutation done on the + * result of sbox lookups + */ +static int perm32[32] = { + 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, + 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 +}; + +/* + * The sboxes + */ +static int sbox[8][4][16]= { + { { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 }, + { 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 }, + { 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0 }, + { 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 } + }, + + { { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 }, + { 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 }, + { 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15 }, + { 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 } + }, + + { { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 }, + { 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 }, + { 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7 }, + { 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 } + }, + + { { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 }, + { 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 }, + { 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4 }, + { 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 } + }, + + { { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 }, + { 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 }, + { 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14 }, + { 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 } + }, + + { { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 }, + { 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 }, + { 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6 }, + { 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 } + }, + + { { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 }, + { 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 }, + { 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2 }, + { 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 } + }, + + { { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 }, + { 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 }, + { 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 }, + { 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 } + } +}; + +/* + * This is the final + * permutation matrix + */ +static int final_perm[64] = { + 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25 +}; + +/* + * The 16 DES keys in BITMASK format + */ +#ifdef _UFC_32_ +long32 _ufc_keytab[16][2]; +#endif + +#ifdef _UFC_64_ +long64 _ufc_keytab[16]; +#endif + + +#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.') +#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') + +/* Macro to set a bit (0..23) */ +#define BITMASK(i) ( (1<<(11-(i)%12+3)) << ((i)<12?16:0) ) + +/* + * sb arrays: + * + * Workhorses of the inner loop of the DES implementation. + * They do sbox lookup, shifting of this value, 32 bit + * permutation and E permutation for the next round. + * + * Kept in 'BITMASK' format. + */ + +#ifdef _UFC_32_ +long32 _ufc_sb0[8192], _ufc_sb1[8192], _ufc_sb2[8192], _ufc_sb3[8192]; +static long32 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3}; +#endif + +#ifdef _UFC_64_ +long64 _ufc_sb0[4096], _ufc_sb1[4096], _ufc_sb2[4096], _ufc_sb3[4096]; +static long64 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3}; +#endif + +/* + * eperm32tab: do 32 bit permutation and E selection + * + * The first index is the byte number in the 32 bit value to be permuted + * - second - is the value of this byte + * - third - selects the two 32 bit values + * + * The table is used and generated internally in init_des to speed it up + */ +static ufc_long eperm32tab[4][256][2]; + +/* + * do_pc1: permform pc1 permutation in the key schedule generation. + * + * The first index is the byte number in the 8 byte ASCII key + * - second - - the two 28 bits halfs of the result + * - third - selects the 7 bits actually used of each byte + * + * The result is kept with 28 bit per 32 bit with the 4 most significant + * bits zero. + */ +static ufc_long do_pc1[8][2][128]; + +/* + * do_pc2: permform pc2 permutation in the key schedule generation. + * + * The first index is the septet number in the two 28 bit intermediate values + * - second - - - septet values + * + * Knowledge of the structure of the pc2 permutation is used. + * + * The result is kept with 28 bit per 32 bit with the 4 most significant + * bits zero. + */ +static ufc_long do_pc2[8][128]; + +/* + * efp: undo an extra e selection and do final + * permutation giving the DES result. + * + * Invoked 6 bit a time on two 48 bit values + * giving two 32 bit longs. + */ +static ufc_long efp[16][64][2]; + +static unsigned char bytemask[8] = { + 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 +}; + +static ufc_long longmask[32] = { + 0x80000000, 0x40000000, 0x20000000, 0x10000000, + 0x08000000, 0x04000000, 0x02000000, 0x01000000, + 0x00800000, 0x00400000, 0x00200000, 0x00100000, + 0x00080000, 0x00040000, 0x00020000, 0x00010000, + 0x00008000, 0x00004000, 0x00002000, 0x00001000, + 0x00000800, 0x00000400, 0x00000200, 0x00000100, + 0x00000080, 0x00000040, 0x00000020, 0x00000010, + 0x00000008, 0x00000004, 0x00000002, 0x00000001 +}; + + +/* + * Silly rewrite of 'bzero'. I do so + * because some machines don't have + * bzero and some don't have memset. + */ + +static void clearmem(start, cnt) + char *start; + int cnt; + { while(cnt--) + *start++ = '\0'; + } + +static int initialized = 0; + +/* lookup a 6 bit value in sbox */ + +#define s_lookup(i,s) sbox[(i)][(((s)>>4) & 0x2)|((s) & 0x1)][((s)>>1) & 0xf]; + +/* + * Initialize unit - may be invoked directly + * by fcrypt users. + */ + +static void ufc_init_des() + { int comes_from_bit; + int bit, sg; + ufc_long j; + ufc_long mask1, mask2; + + /* + * Create the do_pc1 table used + * to affect pc1 permutation + * when generating keys + */ + for(bit = 0; bit < 56; bit++) { + comes_from_bit = pc1[bit] - 1; + mask1 = bytemask[comes_from_bit % 8 + 1]; + mask2 = longmask[bit % 28 + 4]; + for(j = 0; j < 128; j++) { + if(j & mask1) + do_pc1[comes_from_bit / 8][bit / 28][j] |= mask2; + } + } + + /* + * Create the do_pc2 table used + * to affect pc2 permutation when + * generating keys + */ + for(bit = 0; bit < 48; bit++) { + comes_from_bit = pc2[bit] - 1; + mask1 = bytemask[comes_from_bit % 7 + 1]; + mask2 = BITMASK(bit % 24); + for(j = 0; j < 128; j++) { + if(j & mask1) + do_pc2[comes_from_bit / 7][j] |= mask2; + } + } + + /* + * Now generate the table used to do combined + * 32 bit permutation and e expansion + * + * We use it because we have to permute 16384 32 bit + * longs into 48 bit in order to initialize sb. + * + * Looping 48 rounds per permutation becomes + * just too slow... + * + */ + + clearmem((char*)eperm32tab, sizeof(eperm32tab)); + + for(bit = 0; bit < 48; bit++) { + ufc_long mask1,comes_from; + + comes_from = perm32[esel[bit]-1]-1; + mask1 = bytemask[comes_from % 8]; + + for(j = 256; j--;) { + if(j & mask1) + eperm32tab[comes_from / 8][j][bit / 24] |= BITMASK(bit % 24); + } + } + + /* + * Create the sb tables: + * + * For each 12 bit segment of an 48 bit intermediate + * result, the sb table precomputes the two 4 bit + * values of the sbox lookups done with the two 6 + * bit halves, shifts them to their proper place, + * sends them through perm32 and finally E expands + * them so that they are ready for the next + * DES round. + * + */ + for(sg = 0; sg < 4; sg++) { + int j1, j2; + int s1, s2; + + for(j1 = 0; j1 < 64; j1++) { + s1 = s_lookup(2 * sg, j1); + for(j2 = 0; j2 < 64; j2++) { + ufc_long to_permute, inx; + + s2 = s_lookup(2 * sg + 1, j2); + to_permute = ((s1 << 4) | s2) << (24 - 8 * sg); + +#ifdef _UFC_32_ + inx = ((j1 << 6) | j2) << 1; + sb[sg][inx ] = eperm32tab[0][(to_permute >> 24) & 0xff][0]; + sb[sg][inx+1] = eperm32tab[0][(to_permute >> 24) & 0xff][1]; + sb[sg][inx ] |= eperm32tab[1][(to_permute >> 16) & 0xff][0]; + sb[sg][inx+1] |= eperm32tab[1][(to_permute >> 16) & 0xff][1]; + sb[sg][inx ] |= eperm32tab[2][(to_permute >> 8) & 0xff][0]; + sb[sg][inx+1] |= eperm32tab[2][(to_permute >> 8) & 0xff][1]; + sb[sg][inx ] |= eperm32tab[3][(to_permute) & 0xff][0]; + sb[sg][inx+1] |= eperm32tab[3][(to_permute) & 0xff][1]; +#endif +#ifdef _UFC_64_ + inx = ((j1 << 6) | j2); + sb[sg][inx] = + ((long64)eperm32tab[0][(to_permute >> 24) & 0xff][0] << 32) | + (long64)eperm32tab[0][(to_permute >> 24) & 0xff][1]; + sb[sg][inx] |= + ((long64)eperm32tab[1][(to_permute >> 16) & 0xff][0] << 32) | + (long64)eperm32tab[1][(to_permute >> 16) & 0xff][1]; + sb[sg][inx] |= + ((long64)eperm32tab[2][(to_permute >> 8) & 0xff][0] << 32) | + (long64)eperm32tab[2][(to_permute >> 8) & 0xff][1]; + sb[sg][inx] |= + ((long64)eperm32tab[3][(to_permute) & 0xff][0] << 32) | + (long64)eperm32tab[3][(to_permute) & 0xff][1]; +#endif + } + } + } + + /* + * Create an inverse matrix for esel telling + * where to plug out bits if undoing it + */ + for(bit=48; bit--;) { + e_inverse[esel[bit] - 1 ] = bit; + e_inverse[esel[bit] - 1 + 32] = bit + 48; + } + + /* + * create efp: the matrix used to + * undo the E expansion and effect final permutation + */ + clearmem((char*)efp, sizeof efp); + for(bit = 0; bit < 64; bit++) { + int o_bit, o_long; + ufc_long word_value, mask1, mask2; + int comes_from_f_bit, comes_from_e_bit; + int comes_from_word, bit_within_word; + + /* See where bit i belongs in the two 32 bit long's */ + o_long = bit / 32; /* 0..1 */ + o_bit = bit % 32; /* 0..31 */ + + /* + * And find a bit in the e permutated value setting this bit. + * + * Note: the e selection may have selected the same bit several + * times. By the initialization of e_inverse, we only look + * for one specific instance. + */ + comes_from_f_bit = final_perm[bit] - 1; /* 0..63 */ + comes_from_e_bit = e_inverse[comes_from_f_bit]; /* 0..95 */ + comes_from_word = comes_from_e_bit / 6; /* 0..15 */ + bit_within_word = comes_from_e_bit % 6; /* 0..5 */ + + mask1 = longmask[bit_within_word + 26]; + mask2 = longmask[o_bit]; + + for(word_value = 64; word_value--;) { + if(word_value & mask1) + efp[comes_from_word][word_value][o_long] |= mask2; + } + } + initialized++; + } + +/* + * Process the elements of the sb table permuting the + * bits swapped in the expansion by the current salt. + */ + +#ifdef _UFC_32_ +static void shuffle_sb(k, saltbits) + long32 *k; + ufc_long saltbits; + { ufc_long j; + long32 x; + for(j=4096; j--;) { + x = (k[0] ^ k[1]) & (long32)saltbits; + *k++ ^= x; + *k++ ^= x; + } + } +#endif + +#ifdef _UFC_64_ +static void shuffle_sb(k, saltbits) + long64 *k; + ufc_long saltbits; + { ufc_long j; + long64 x; + for(j=4096; j--;) { + x = ((*k >> 32) ^ *k) & (long64)saltbits; + *k++ ^= (x << 32) | x; + } + } +#endif + +/* + * Setup the unit for a new salt + * Hopefully we'll not see a new salt in each crypt call. + */ + +static unsigned char current_salt[3] = "&&"; /* invalid value */ +static ufc_long current_saltbits = 0; +static int direction = 0; + +static void setup_salt(char *s1) + { ufc_long i, j, saltbits; + unsigned char *s2 = (unsigned char *)s1; + + if(!initialized) + ufc_init_des(); + + if(s2[0] == current_salt[0] && s2[1] == current_salt[1]) + return; + current_salt[0] = s2[0]; current_salt[1] = s2[1]; + + /* + * This is the only crypt change to DES: + * entries are swapped in the expansion table + * according to the bits set in the salt. + */ + saltbits = 0; + for(i = 0; i < 2; i++) { + long c=ascii_to_bin(s2[i]); + if(c < 0 || c > 63) + c = 0; + for(j = 0; j < 6; j++) { + if((c >> j) & 0x1) + saltbits |= BITMASK(6 * i + j); + } + } + + /* + * Permute the sb table values + * to reflect the changed e + * selection table + */ + shuffle_sb(_ufc_sb0, current_saltbits ^ saltbits); + shuffle_sb(_ufc_sb1, current_saltbits ^ saltbits); + shuffle_sb(_ufc_sb2, current_saltbits ^ saltbits); + shuffle_sb(_ufc_sb3, current_saltbits ^ saltbits); + + current_saltbits = saltbits; + } + +static void ufc_mk_keytab(key) + char *key; + { ufc_long v1, v2, *k1; + int i; +#ifdef _UFC_32_ + long32 v, *k2 = &_ufc_keytab[0][0]; +#endif +#ifdef _UFC_64_ + long64 v, *k2 = &_ufc_keytab[0]; +#endif + + v1 = v2 = 0; k1 = &do_pc1[0][0][0]; + for(i = 8; i--;) { + v1 |= k1[*key & 0x7f]; k1 += 128; + v2 |= k1[*key++ & 0x7f]; k1 += 128; + } + + for(i = 0; i < 16; i++) { + k1 = &do_pc2[0][0]; + + v1 = (v1 << rots[i]) | (v1 >> (28 - rots[i])); + v = k1[(v1 >> 21) & 0x7f]; k1 += 128; + v |= k1[(v1 >> 14) & 0x7f]; k1 += 128; + v |= k1[(v1 >> 7) & 0x7f]; k1 += 128; + v |= k1[(v1 ) & 0x7f]; k1 += 128; + +#ifdef _UFC_32_ + *k2++ = v; + v = 0; +#endif +#ifdef _UFC_64_ + v <<= 32; +#endif + + v2 = (v2 << rots[i]) | (v2 >> (28 - rots[i])); + v |= k1[(v2 >> 21) & 0x7f]; k1 += 128; + v |= k1[(v2 >> 14) & 0x7f]; k1 += 128; + v |= k1[(v2 >> 7) & 0x7f]; k1 += 128; + v |= k1[(v2 ) & 0x7f]; + + *k2++ = v; + } + + direction = 0; + } + +/* + * Undo an extra E selection and do final permutations + */ + +ufc_long *_ufc_dofinalperm(l1, l2, r1, r2) + ufc_long l1,l2,r1,r2; + { ufc_long v1, v2, x; + static ufc_long ary[2]; + + x = (l1 ^ l2) & current_saltbits; l1 ^= x; l2 ^= x; + x = (r1 ^ r2) & current_saltbits; r1 ^= x; r2 ^= x; + + v1=v2=0; l1 >>= 3; l2 >>= 3; r1 >>= 3; r2 >>= 3; + + v1 |= efp[15][ r2 & 0x3f][0]; v2 |= efp[15][ r2 & 0x3f][1]; + v1 |= efp[14][(r2 >>= 6) & 0x3f][0]; v2 |= efp[14][ r2 & 0x3f][1]; + v1 |= efp[13][(r2 >>= 10) & 0x3f][0]; v2 |= efp[13][ r2 & 0x3f][1]; + v1 |= efp[12][(r2 >>= 6) & 0x3f][0]; v2 |= efp[12][ r2 & 0x3f][1]; + + v1 |= efp[11][ r1 & 0x3f][0]; v2 |= efp[11][ r1 & 0x3f][1]; + v1 |= efp[10][(r1 >>= 6) & 0x3f][0]; v2 |= efp[10][ r1 & 0x3f][1]; + v1 |= efp[ 9][(r1 >>= 10) & 0x3f][0]; v2 |= efp[ 9][ r1 & 0x3f][1]; + v1 |= efp[ 8][(r1 >>= 6) & 0x3f][0]; v2 |= efp[ 8][ r1 & 0x3f][1]; + + v1 |= efp[ 7][ l2 & 0x3f][0]; v2 |= efp[ 7][ l2 & 0x3f][1]; + v1 |= efp[ 6][(l2 >>= 6) & 0x3f][0]; v2 |= efp[ 6][ l2 & 0x3f][1]; + v1 |= efp[ 5][(l2 >>= 10) & 0x3f][0]; v2 |= efp[ 5][ l2 & 0x3f][1]; + v1 |= efp[ 4][(l2 >>= 6) & 0x3f][0]; v2 |= efp[ 4][ l2 & 0x3f][1]; + + v1 |= efp[ 3][ l1 & 0x3f][0]; v2 |= efp[ 3][ l1 & 0x3f][1]; + v1 |= efp[ 2][(l1 >>= 6) & 0x3f][0]; v2 |= efp[ 2][ l1 & 0x3f][1]; + v1 |= efp[ 1][(l1 >>= 10) & 0x3f][0]; v2 |= efp[ 1][ l1 & 0x3f][1]; + v1 |= efp[ 0][(l1 >>= 6) & 0x3f][0]; v2 |= efp[ 0][ l1 & 0x3f][1]; + + ary[0] = v1; ary[1] = v2; + return ary; + } + +/* + * crypt only: convert from 64 bit to 11 bit ASCII + * prefixing with the salt + */ + +static char *output_conversion(v1, v2, salt) + ufc_long v1, v2; + char *salt; + { static char outbuf[14]; + int i, s; + + outbuf[0] = salt[0]; + outbuf[1] = salt[1] ? salt[1] : salt[0]; + + for(i = 0; i < 5; i++) + outbuf[i + 2] = bin_to_ascii((v1 >> (26 - 6 * i)) & 0x3f); + + s = (v2 & 0xf) << 2; + v2 = (v2 >> 2) | ((v1 & 0x3) << 30); + + for(i = 5; i < 10; i++) + outbuf[i + 2] = bin_to_ascii((v2 >> (56 - 6 * i)) & 0x3f); + + outbuf[12] = bin_to_ascii(s); + outbuf[13] = 0; + + return outbuf; + } + +ufc_long *_ufc_doit(); + +/* + * UNIX crypt function + */ + +char *ufc_crypt(char *key,char *salt) + { ufc_long *s; + char ktab[9]; + + /* + * Hack DES tables according to salt + */ + setup_salt(salt); + + /* + * Setup key schedule + */ + clearmem(ktab, sizeof ktab); + StrnCpy(ktab, key, 8); + ufc_mk_keytab(ktab); + + /* + * Go for the 25 DES encryptions + */ + s = _ufc_doit((ufc_long)0, (ufc_long)0, + (ufc_long)0, (ufc_long)0, (ufc_long)25); + + /* + * And convert back to 6 bit ASCII + */ + return output_conversion(s[0], s[1], salt); + } + + +#ifdef _UFC_32_ + +/* + * 32 bit version + */ + +extern long32 _ufc_keytab[16][2]; +extern long32 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[]; + +#define SBA(sb, v) (*(long32*)((char*)(sb)+(v))) + +ufc_long *_ufc_doit(l1, l2, r1, r2, itr) + ufc_long l1, l2, r1, r2, itr; + { int i; + long32 s, *k; + + while(itr--) { + k = &_ufc_keytab[0][0]; + for(i=8; i--; ) { + s = *k++ ^ r1; + l1 ^= SBA(_ufc_sb1, s & 0xffff); l2 ^= SBA(_ufc_sb1, (s & 0xffff)+4); + l1 ^= SBA(_ufc_sb0, s >>= 16); l2 ^= SBA(_ufc_sb0, (s) +4); + s = *k++ ^ r2; + l1 ^= SBA(_ufc_sb3, s & 0xffff); l2 ^= SBA(_ufc_sb3, (s & 0xffff)+4); + l1 ^= SBA(_ufc_sb2, s >>= 16); l2 ^= SBA(_ufc_sb2, (s) +4); + + s = *k++ ^ l1; + r1 ^= SBA(_ufc_sb1, s & 0xffff); r2 ^= SBA(_ufc_sb1, (s & 0xffff)+4); + r1 ^= SBA(_ufc_sb0, s >>= 16); r2 ^= SBA(_ufc_sb0, (s) +4); + s = *k++ ^ l2; + r1 ^= SBA(_ufc_sb3, s & 0xffff); r2 ^= SBA(_ufc_sb3, (s & 0xffff)+4); + r1 ^= SBA(_ufc_sb2, s >>= 16); r2 ^= SBA(_ufc_sb2, (s) +4); + } + s=l1; l1=r1; r1=s; s=l2; l2=r2; r2=s; + } + return _ufc_dofinalperm(l1, l2, r1, r2); + } + +#endif + +#ifdef _UFC_64_ + +/* + * 64 bit version + */ + +extern long64 _ufc_keytab[16]; +extern long64 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[]; + +#define SBA(sb, v) (*(long64*)((char*)(sb)+(v))) + +ufc_long *_ufc_doit(l1, l2, r1, r2, itr) + ufc_long l1, l2, r1, r2, itr; + { int i; + long64 l, r, s, *k; + + l = (((long64)l1) << 32) | ((long64)l2); + r = (((long64)r1) << 32) | ((long64)r2); + + while(itr--) { + k = &_ufc_keytab[0]; + for(i=8; i--; ) { + s = *k++ ^ r; + l ^= SBA(_ufc_sb3, (s >> 0) & 0xffff); + l ^= SBA(_ufc_sb2, (s >> 16) & 0xffff); + l ^= SBA(_ufc_sb1, (s >> 32) & 0xffff); + l ^= SBA(_ufc_sb0, (s >> 48) & 0xffff); + + s = *k++ ^ l; + r ^= SBA(_ufc_sb3, (s >> 0) & 0xffff); + r ^= SBA(_ufc_sb2, (s >> 16) & 0xffff); + r ^= SBA(_ufc_sb1, (s >> 32) & 0xffff); + r ^= SBA(_ufc_sb0, (s >> 48) & 0xffff); + } + s=l; l=r; r=s; + } + + l1 = l >> 32; l2 = l & 0xffffffff; + r1 = r >> 32; r2 = r & 0xffffffff; + return _ufc_dofinalperm(l1, l2, r1, r2); + } + +#endif + + +#else +int ufc_dummy_procedure(void) +{return 0;} +#endif diff --git a/source3/lib/username.c b/source3/lib/username.c new file mode 100644 index 0000000000..3d214fbbda --- /dev/null +++ b/source3/lib/username.c @@ -0,0 +1,246 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Username handling + Copyright (C) Andrew Tridgell 1992-1995 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "loadparm.h" +extern int DEBUGLEVEL; + + +/**************************************************************************** +get a users home directory. tries as-is then lower case +****************************************************************************/ +char *get_home_dir(char *user) +{ + static struct passwd *pass; + + pass = Get_Pwnam(user,False); + + if (!pass) return(NULL); + return(pass->pw_dir); +} + + +/******************************************************************* +map a username from a dos name to a unix name by looking in the username +map +********************************************************************/ +void map_username(char *user) +{ + static int depth=0; + static BOOL initialised=False; + static fstring last_from,last_to; + FILE *f; + char *s; + char *mapfile = lp_username_map(); + if (!*mapfile || depth) return; + + if (!*user) return; + + if (!initialised) { + *last_from = *last_to = 0; + initialised = True; + } + + if (strequal(user,last_to)) return; + + if (strequal(user,last_from)) { + DEBUG(3,("Mapped user %s to %s\n",user,last_to)); + strcpy(user,last_to); + return; + } + + f = fopen(mapfile,"r"); + if (!f) { + DEBUG(0,("can't open username map %s\n",mapfile)); + return; + } + + DEBUG(4,("Scanning username map %s\n",mapfile)); + + depth++; + + for (; (s=fgets_slash(NULL,80,f)); free(s)) { + char *unixname = s; + char *dosname = strchr(unixname,'='); + + if (!dosname) continue; + *dosname++ = 0; + + while (isspace(*unixname)) unixname++; + if (!*unixname || strchr("#;",*unixname)) continue; + + { + int l = strlen(unixname); + while (l && isspace(unixname[l-1])) { + unixname[l-1] = 0; + l--; + } + } + + if (strchr(dosname,'*') || user_in_list(user,dosname)) { + DEBUG(3,("Mapped user %s to %s\n",user,unixname)); + StrnCpy(last_from,user,sizeof(last_from)-1); + sscanf(unixname,"%s",user); + StrnCpy(last_to,user,sizeof(last_to)-1); + } + } + + fclose(f); + + depth--; +} + +/**************************************************************************** +internals of Get_Pwnam wrapper +****************************************************************************/ +static struct passwd *_Get_Pwnam(char *s) +{ + struct passwd *ret; + + ret = getpwnam(s); + if (ret) + { +#ifdef GETPWANAM + struct passwd_adjunct *pwret; + pwret = getpwanam(s); + if (pwret) + { + free(ret->pw_passwd); + ret->pw_passwd = pwret->pwa_passwd; + } +#endif + + } + + return(ret); +} + + +/**************************************************************************** +a wrapper for getpwnam() that tries with all lower and all upper case +if the initial name fails. Also tried with first letter capitalised +Note that this changes user! +****************************************************************************/ +struct passwd *Get_Pwnam(char *user,BOOL allow_change) +{ + fstring user2; + + struct passwd *ret; + + if (!user || !(*user)) + return(NULL); + + StrnCpy(user2,user,sizeof(user2)-1); + + if (!allow_change) { + user = &user2[0]; + } + + map_username(user); + + ret = _Get_Pwnam(user); + if (ret) return(ret); + + strlower(user); + ret = _Get_Pwnam(user); + if (ret) return(ret); + + strupper(user); + ret = _Get_Pwnam(user); + if (ret) return(ret); + + /* try with first letter capitalised */ + if (strlen(user) > 1) + strlower(user+1); + ret = _Get_Pwnam(user); + if (ret) return(ret); + + if (allow_change) + strcpy(user,user2); + + return(NULL); +} + + +/**************************************************************************** +check if a user is in a user list +****************************************************************************/ +BOOL user_in_list(char *user,char *list) +{ + pstring tok; + char *p=list; + + while (next_token(&p,tok,LIST_SEP)) + { + if (strequal(user,tok)) + return(True); + +#ifdef NETGROUP + if (*tok == '@') + { + static char *mydomain = NULL; + if (mydomain == 0) + yp_get_default_domain(&mydomain); + + DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", + user, mydomain, &tok[1])); + DEBUG(5,("innetgr is %s\n", + innetgr(&tok[1], (char *) 0, user, mydomain) + ? "TRUE" : "FALSE")); + + if (innetgr(&tok[1], (char *)0, user, mydomain)) + return (True); + } +#endif + + +#if HAVE_GETGRNAM + if (*tok == '@') + { + struct group *gptr; + char **member; + struct passwd *pass = Get_Pwnam(user,False); + + if (pass) { + gptr = getgrgid(pass->pw_gid); + if (gptr && strequal(gptr->gr_name,&tok[1])) + return(True); + } + + gptr = (struct group *)getgrnam(&tok[1]); + + if (gptr) + { + member = gptr->gr_mem; + while (member && *member) + { + if (strequal(*member,user)) + return(True); + member++; + } + } + } +#endif + } + return(False); +} + + diff --git a/source3/lib/util.c b/source3/lib/util.c new file mode 100644 index 0000000000..7bd6298c4c --- /dev/null +++ b/source3/lib/util.c @@ -0,0 +1,4510 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Samba utility functions + Copyright (C) Andrew Tridgell 1992-1995 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "loadparm.h" + +pstring scope = ""; + +int DEBUGLEVEL = 1; + +BOOL passive = False; + +int Protocol = PROTOCOL_COREPLUS; + +int serverzone=0; + +/* a default finfo structure to ensure all fields are sensible */ +file_info def_finfo = {-1,0,0,0,0,0,0,""}; + +/* these are some file handles where debug info will be stored */ +FILE *dbf = NULL; + +/* the client file descriptor */ +int Client = -1; + +/* info on the client */ +struct from_host Client_info= +{"UNKNOWN","0.0.0.0",NULL}; + +/* the last IP received from */ +struct in_addr lastip; + +/* the last port received from */ +int lastport=0; + +/* my IP, the broadcast IP and the Netmask */ +struct in_addr myip; +struct in_addr bcast_ip; +struct in_addr Netmask; + +int trans_num = 0; + +/* + case handling on filenames +*/ +int case_default = CASE_LOWER; + + +/* size of reads during a direct file to file transfer */ +int ReadSize = 16*1024; + +pstring debugf = "/tmp/log.samba"; +int syslog_level; + +/* the following control case operations - they are put here so the + client can link easily */ +BOOL case_sensitive; +BOOL case_preserve; +BOOL use_mangled_map = False; +BOOL short_case_preserve; +BOOL case_mangle; + +fstring remote_machine=""; +fstring local_machine=""; +fstring remote_arch="UNKNOWN"; +fstring remote_proto="UNKNOWN"; +pstring myhostname=""; +pstring user_socket_options=""; +pstring sesssetup_user=""; + + +static char *filename_dos(char *path,char *buf); + +static BOOL stdout_logging = False; + + +/******************************************************************* + get ready for syslog stuff + ******************************************************************/ +void setup_logging(char *pname,BOOL interactive) +{ +#ifdef SYSLOG + if (!interactive) { + char *p = strrchr(pname,'/'); + if (p) pname = p+1; + openlog(pname, LOG_PID, LOG_DAEMON); + } +#endif + if (interactive) { + stdout_logging = True; + dbf = stdout; + } +} + + +BOOL append_log=False; + + +/**************************************************************************** +reopen the log files +****************************************************************************/ +void reopen_logs(void) +{ + extern FILE *dbf; + pstring fname; + + if (DEBUGLEVEL > 0) + { + strcpy(fname,debugf); + if (lp_loaded() && (*lp_logfile())) + strcpy(fname,lp_logfile()); + + if (!strcsequal(fname,debugf) || !dbf || !file_exist(debugf,NULL)) + { + strcpy(debugf,fname); + if (dbf) fclose(dbf); + if (append_log) + dbf = fopen(debugf,"a"); + else + dbf = fopen(debugf,"w"); + if (dbf) setbuf(dbf,NULL); + } + } + else + { + if (dbf) + { + fclose(dbf); + dbf = NULL; + } + } +} + + +/******************************************************************* +write an debug message on the debugfile. This is called by the DEBUG +macro +********************************************************************/ +#ifdef __STDC__ +int Debug1(char *format_str, ...) +{ +#else +int Debug1(va_alist) +va_dcl +{ + char *format_str; +#endif + va_list ap; + +#ifdef __STDC__ + va_start(ap, format_str); +#else + va_start(ap); + format_str = va_arg(ap,char *); +#endif + + if (stdout_logging) { + vfprintf(dbf,format_str,ap); + va_end(ap); + return(0); + } + + { + static int debug_count=0; + + debug_count++; + if (debug_count == 100) { + int maxlog = lp_max_log_size() * 1024; + if (dbf && maxlog > 0) + { + struct stat st; + + if (fstat(fileno(dbf),&st) == 0 && st.st_size > maxlog) { + fclose(dbf); dbf = NULL; + reopen_logs(); + if (dbf && file_size(debugf) > maxlog) { + pstring name; + fclose(dbf); dbf = NULL; + sprintf(name,"%s.old",debugf); + sys_rename(debugf,name); + reopen_logs(); + } + } + } + debug_count=0; + } + } + +#ifdef SYSLOG + if (!lp_syslog_only()) +#endif + { + if (!dbf) + { + dbf = fopen(debugf,"w"); + if (dbf) + setbuf(dbf,NULL); + else + return(0); + } + } + +#ifdef SYSLOG + if (syslog_level < lp_syslog()) + { + /* + * map debug levels to syslog() priorities + * note that not all DEBUG(0, ...) calls are + * necessarily errors + */ + static int priority_map[] = { + LOG_ERR, /* 0 */ + LOG_WARNING, /* 1 */ + LOG_NOTICE, /* 2 */ + LOG_INFO, /* 3 */ + }; + int priority; + pstring msgbuf; + + if (syslog_level >= sizeof(priority_map) / sizeof(priority_map[0]) || + syslog_level < 0) + priority = LOG_DEBUG; + else + priority = priority_map[syslog_level]; + + vsprintf(msgbuf, format_str, ap); + + msgbuf[255] = '\0'; + syslog(priority, "%s", msgbuf); + } +#endif + +#ifdef SYSLOG + if (!lp_syslog_only()) +#endif + { + vfprintf(dbf,format_str,ap); + fflush(dbf); + } + + va_end(ap); + return(0); +} + +/**************************************************************************** +routine to do file locking +****************************************************************************/ +BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type) +{ +#if HAVE_FCNTL_LOCK + struct flock lock; + int ret; + +#if 1 + uint32 mask = 0xC0000000; + + /* make sure the count is reasonable, we might kill the lockd otherwise */ + count &= ~mask; + + /* the offset is often strange - remove 2 of its bits if either of + the top two bits are set. Shift the top ones by two bits. This + still allows OLE2 apps to operate, but should stop lockd from + dieing */ + if ((offset & mask) != 0) + offset = (offset & ~mask) | ((offset & mask) >> 2); +#else + unsigned long mask = ((unsigned)1<<31); + + /* interpret negative counts as large numbers */ + if (count < 0) + count &= ~mask; + + /* no negative offsets */ + offset &= ~mask; + + /* count + offset must be in range */ + while ((offset < 0 || (offset + count < 0)) && mask) + { + offset &= ~mask; + mask = mask >> 1; + } +#endif + + + DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type)); + + lock.l_type = type; + lock.l_whence = SEEK_SET; + lock.l_start = (int)offset; + lock.l_len = (int)count; + lock.l_pid = 0; + + errno = 0; + + ret = fcntl(fd,op,&lock); + + if (errno != 0) + DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno))); + + /* a lock query */ + if (op == F_GETLK) + { + if ((ret != -1) && + (lock.l_type != F_UNLCK) && + (lock.l_pid != 0) && + (lock.l_pid != getpid())) + { + DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid)); + return(True); + } + + /* it must be not locked or locked by me */ + return(False); + } + + /* a lock set or unset */ + if (ret == -1) + { + DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n", + offset,count,op,type,strerror(errno))); + + /* perhaps it doesn't support this sort of locking?? */ + if (errno == EINVAL) + { + DEBUG(3,("locking not supported? returning True\n")); + return(True); + } + + return(False); + } + + /* everything went OK */ + DEBUG(5,("Lock call successful\n")); + + return(True); +#else + return(False); +#endif +} + +/******************************************************************* +lock a file - returning a open file descriptor or -1 on failure +The timeout is in seconds. 0 means no timeout +********************************************************************/ +int file_lock(char *name,int timeout) +{ + int fd = open(name,O_RDWR|O_CREAT,0666); + time_t t=0; + if (fd < 0) return(-1); + +#if HAVE_FCNTL_LOCK + if (timeout) t = time(NULL); + while (!timeout || (time(NULL)-t < timeout)) { + if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)) return(fd); + msleep(LOCK_RETRY_TIMEOUT); + } + return(-1); +#else + return(fd); +#endif +} + +/******************************************************************* +unlock a file locked by file_lock +********************************************************************/ +void file_unlock(int fd) +{ + if (fd<0) return; +#if HAVE_FCNTL_LOCK + fcntl_lock(fd,F_SETLK,0,1,F_UNLCK); +#endif + close(fd); +} + +/******************************************************************* +a gettimeofday wrapper +********************************************************************/ +void GetTimeOfDay(struct timeval *tval) +{ +#ifdef GETTIMEOFDAY1 + gettimeofday(tval); +#else + gettimeofday(tval,NULL); +#endif +} + +int extra_time_offset = 0; + +static int timediff = 0; + +/******************************************************************* +init the time differences +********************************************************************/ +void TimeInit(void) +{ + struct tm tm_utc,tm_local; + time_t t; + + t = time(NULL); + + tm_utc = *(gmtime(&t)); + tm_local = *(localtime(&t)); + +#ifdef HAVE_GMTOFF + timediff = -tm_local.tm_gmtoff; +#else + timediff = mktime(&tm_utc) - mktime(&tm_local); +#endif + + if (serverzone == 0) { + serverzone = timediff - DSTDiff(t); + DEBUG(4,("Serverzone is %d\n",serverzone)); + } +} + + +/******************************************************************* +return the DST offset for a particular time +We keep a table of DST offsets to prevent calling localtime() on each +call of this function. This saves a LOT of time on many unixes. +********************************************************************/ +int DSTDiff(time_t t) +{ + static struct dst_table {time_t start,end; BOOL is_dst;} *dst_table = NULL; + static int table_size = 0; + int i; + BOOL is_dst = False; + + if (t == 0) t = time(NULL); + +#ifndef NO_ISDST + for (i=0;i<table_size;i++) + if (t >= dst_table[i].start && t <= dst_table[i].end) break; + + if (i<table_size) { + is_dst = dst_table[i].is_dst; + } else { + time_t low,high; + + dst_table = (struct dst_table *)Realloc(dst_table, + sizeof(dst_table[0])*(i+1)); + if (!dst_table) { + table_size = 0; + return(0); + } + + table_size++; + + dst_table[i].is_dst = is_dst = (localtime(&t)->tm_isdst?True:False);; + dst_table[i].start = dst_table[i].end = t; + + /* no entry will cover more than 6 months */ + low = t - 3*30*24*60*60; + high = t + 3*30*24*60*60; + + /* widen the new entry using two bisection searches */ + while (low+60*60 < dst_table[i].start) { + t = low + (dst_table[i].start-low)/2; + if ((localtime(&t)->tm_isdst?True:False) == is_dst) + dst_table[i].start = t; + else + low = t; + } + + while (high-60*60 > dst_table[i].end) { + t = high + (high-dst_table[i].end)/2; + if ((localtime(&t)->tm_isdst?True:False) == is_dst) + dst_table[i].end = t; + else + high = t; + } + +/* + DEBUG(1,("Added DST entry from %s ", + asctime(localtime(&dst_table[i].start)))); + DEBUG(1,("to %s (%d)\n",asctime(localtime(&dst_table[i].end)), + dst_table[i].is_dst)); +*/ + } +#endif + + return((is_dst?60*60:0) - (extra_time_offset*60)); +} + +/**************************************************************************** +return the difference between local and GMT time +****************************************************************************/ +int TimeDiff(time_t t) +{ + static BOOL initialised = False; + if (!initialised) {initialised=True; TimeInit();} + return(timediff - DSTDiff(t)); +} + +/**************************************************************************** +try to optimise the localtime call, it can be quite expenive on some machines +timemul is normally LOCAL_TO_GMT, GMT_TO_LOCAL or 0 +****************************************************************************/ +struct tm *LocalTime(time_t *t,int timemul) +{ + time_t t2 = *t; + + if (timemul) + t2 += timemul * TimeDiff(t2); + + return(gmtime(&t2)); +} + + +/**************************************************************************** +determine if a file descriptor is in fact a socket +****************************************************************************/ +BOOL is_a_socket(int fd) +{ + int v,l; + l = sizeof(int); + return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0); +} + + +static char *last_ptr=NULL; + +/**************************************************************************** + Get the next token from a string, return False if none found + handles double-quotes. +Based on a routine by GJC@VILLAGE.COM. +Extensively modified by Andrew.Tridgell@anu.edu.au +****************************************************************************/ +BOOL next_token(char **ptr,char *buff,char *sep) +{ + char *s; + BOOL quoted; + + if (!ptr) ptr = &last_ptr; + if (!ptr) return(False); + + s = *ptr; + + /* default to simple separators */ + if (!sep) sep = " \t\n\r"; + + /* find the first non sep char */ + while(*s && strchr(sep,*s)) s++; + + /* nothing left? */ + if (! *s) return(False); + + /* copy over the token */ + for (quoted = False; *s && (quoted || !strchr(sep,*s)); s++) + { + if (*s == '\"') + quoted = !quoted; + else + *buff++ = *s; + } + + *ptr = (*s) ? s+1 : s; + *buff = 0; + last_ptr = *ptr; + + return(True); +} + +/**************************************************************************** +Convert list of tokens to array; dependent on above routine. +Uses last_ptr from above - bit of a hack. +****************************************************************************/ +char **toktocliplist(int *ctok, char *sep) +{ + char *s=last_ptr; + int ictok=0; + char **ret, **iret; + + if (!sep) sep = " \t\n\r"; + + while(*s && strchr(sep,*s)) s++; + + /* nothing left? */ + if (!*s) return(NULL); + + do { + ictok++; + while(*s && (!strchr(sep,*s))) s++; + while(*s && strchr(sep,*s)) *s++=0; + } while(*s); + + *ctok=ictok; + s=last_ptr; + + if (!(ret=iret=malloc(ictok*sizeof(char *)))) return NULL; + + while(ictok--) { + *iret++=s; + while(*s++); + while(!*s) s++; + } + + return ret; +} + +#ifndef HAVE_MEMMOVE +/******************************************************************* +safely copies memory, ensuring no overlap problems. +this is only used if the machine does not have it's own memmove(). +this is not the fastest algorithm in town, but it will do for our +needs. +********************************************************************/ +void *MemMove(void *dest,void *src,int size) +{ + unsigned long d,s; + int i; + if (dest==src || !size) return(dest); + + d = (unsigned long)dest; + s = (unsigned long)src; + + if ((d >= (s+size)) || (s >= (d+size))) { + /* no overlap */ + memcpy(dest,src,size); + return(dest); + } + + if (d < s) + { + /* we can forward copy */ + if (s-d >= sizeof(int) && + !(s%sizeof(int)) && !(d%sizeof(int)) && !(size%sizeof(int))) { + /* do it all as words */ + int *idest = (int *)dest; + int *isrc = (int *)src; + size /= sizeof(int); + for (i=0;i<size;i++) idest[i] = isrc[i]; + } else { + /* simplest */ + char *cdest = (char *)dest; + char *csrc = (char *)src; + for (i=0;i<size;i++) cdest[i] = csrc[i]; + } + } + else + { + /* must backward copy */ + if (d-s >= sizeof(int) && + !(s%sizeof(int)) && !(d%sizeof(int)) && !(size%sizeof(int))) { + /* do it all as words */ + int *idest = (int *)dest; + int *isrc = (int *)src; + size /= sizeof(int); + for (i=size-1;i>=0;i--) idest[i] = isrc[i]; + } else { + /* simplest */ + char *cdest = (char *)dest; + char *csrc = (char *)src; + for (i=size-1;i>=0;i--) cdest[i] = csrc[i]; + } + } + return(dest); +} +#endif + + +/**************************************************************************** +prompte a dptr (to make it recently used) +****************************************************************************/ +void array_promote(char *array,int elsize,int element) +{ + char *p; + if (element == 0) + return; + + p = (char *)malloc(elsize); + + if (!p) + { + DEBUG(5,("Ahh! Can't malloc\n")); + return; + } + memcpy(p,array + element * elsize, elsize); + memmove(array + elsize,array,elsize*element); + memcpy(array,p,elsize); + free(p); +} + +enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON}; + +struct +{ + char *name; + int level; + int option; + int value; + int opttype; +} socket_options[] = { + {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL}, + {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL}, + {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL}, +#ifdef TCP_NODELAY + {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL}, +#endif +#ifdef IPTOS_LOWDELAY + {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON}, +#endif +#ifdef IPTOS_THROUGHPUT + {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON}, +#endif +#ifdef SO_SNDBUF + {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT}, +#endif +#ifdef SO_RCVBUF + {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT}, +#endif +#ifdef SO_SNDLOWAT + {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT}, +#endif +#ifdef SO_RCVLOWAT + {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT}, +#endif + {NULL,0,0,0,0}}; + + + +/**************************************************************************** +set user socket options +****************************************************************************/ +void set_socket_options(int fd, char *options) +{ + string tok; + + while (next_token(&options,tok," \t,")) + { + int ret=0,i; + int value = 1; + char *p; + BOOL got_value = False; + + if ((p = strchr(tok,'='))) + { + *p = 0; + value = atoi(p+1); + got_value = True; + } + + for (i=0;socket_options[i].name;i++) + if (strequal(socket_options[i].name,tok)) + break; + + if (!socket_options[i].name) + { + DEBUG(0,("Unknown socket option %s\n",tok)); + continue; + } + + switch (socket_options[i].opttype) + { + case OPT_BOOL: + case OPT_INT: + ret = setsockopt(fd,socket_options[i].level, + socket_options[i].option,(char *)&value,sizeof(int)); + break; + + case OPT_ON: + if (got_value) + DEBUG(0,("syntax error - %s does not take a value\n",tok)); + + { + int on = socket_options[i].value; + ret = setsockopt(fd,socket_options[i].level, + socket_options[i].option,(char *)&on,sizeof(int)); + } + break; + } + + if (ret != 0) + DEBUG(0,("Failed to set socket option %s\n",tok)); + } +} + + + +/**************************************************************************** + close the socket communication +****************************************************************************/ +void close_sockets(void ) +{ + close(Client); + Client = 0; +} + +/**************************************************************************** + return the date and time as a string +****************************************************************************/ +char *timestring(void ) +{ + static char TimeBuf[100]; + time_t t; + t = time(NULL); +#ifdef NO_STRFTIME + strcpy(TimeBuf, asctime(LocalTime(&t,GMT_TO_LOCAL))); +#elif defined(CLIX) || defined(CONVEX) + strftime(TimeBuf,100,"%m/%d/%y %I:%M:%S %p",LocalTime(&t,GMT_TO_LOCAL)); +#elif defined(AMPM) + strftime(TimeBuf,100,"%D %r",LocalTime(&t,GMT_TO_LOCAL)); +#elif defined(TZ_TIME) + { + strftime(TimeBuf,100,"%D:%T",LocalTime(&t,0)); + sprintf(TimeBuf+strlen(TimeBuf)," %+03d%02d", + -TimeDiff(t)/(60*60),-(TimeDiff(t)/60)%60); + } +#else + strftime(TimeBuf,100,"%D %T",LocalTime(&t,GMT_TO_LOCAL)); +#endif + return(TimeBuf); +} + +/**************************************************************************** +determine whether we are in the specified group +****************************************************************************/ +BOOL in_group(gid_t group, int current_gid, int ngroups, int *groups) +{ + int i; + + if (group == current_gid) return(True); + + for (i=0;i<ngroups;i++) + if (group == groups[i]) + return(True); + + return(False); +} + +/**************************************************************************** +this is a safer strcpy(), meant to prevent core dumps when nasty things happen +****************************************************************************/ +char *StrCpy(char *dest,char *src) +{ + char *d = dest; + +#if AJT + /* I don't want to get lazy with these ... */ + if (!dest || !src) { + DEBUG(0,("ERROR: NULL StrCpy() called!\n")); + ajt_panic(); + } +#endif + + if (!dest) return(NULL); + if (!src) { + *dest = 0; + return(dest); + } + while ((*d++ = *src++)) ; + return(dest); +} + +/**************************************************************************** +line strncpy but always null terminates. Make sure there is room! +****************************************************************************/ +char *StrnCpy(char *dest,const char *src,int n) +{ + char *d = dest; + if (!dest) return(NULL); + if (!src) { + *dest = 0; + return(dest); + } + while (n-- && (*d++ = *src++)) ; + *d = 0; + return(dest); +} + + +/******************************************************************* +copy an IP address from one buffer to another +********************************************************************/ +void putip(void *dest,void *src) +{ + memcpy(dest,src,4); +} + + +/**************************************************************************** +interpret the weird netbios "name". Return the name type +****************************************************************************/ +static int name_interpret(char *in,char *out) +{ + int ret; + int len = (*in++) / 2; + + *out=0; + + if (len > 30 || len<1) return(0); + + while (len--) + { + if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') { + *out = 0; + return(0); + } + *out = ((in[0]-'A')<<4) + (in[1]-'A'); + in += 2; + out++; + } + *out = 0; + ret = out[-1]; + +#ifdef NETBIOS_SCOPE + /* Handle any scope names */ + while(*in) + { + *out++ = '.'; /* Scope names are separated by periods */ + len = *(unsigned char *)in++; + StrnCpy(out, in, len); + out += len; + *out=0; + in += len; + } +#endif + return(ret); +} + +/**************************************************************************** +mangle a name into netbios format +****************************************************************************/ +int name_mangle(char *In,char *Out,char name_type) +{ + fstring name; + char buf[20]; + char *in = (char *)&buf[0]; + char *out = (char *)Out; + char *p, *label; + int i; + + if (In[0] != '*') { + StrnCpy(name,In,sizeof(name)-1); + sprintf(buf,"%-15.15s%c",name,name_type); + } else { + buf[0]='*'; + memset(&buf[1],0,16); + } + + *out++ = 32; + for (i=0;i<16;i++) { + char c = toupper(in[i]); + out[i*2] = (c>>4) + 'A'; + out[i*2+1] = (c & 0xF) + 'A'; + } + out[32]=0; + out += 32; + + label = scope; + while (*label) + { + p = strchr(label, '.'); + if (p == 0) + p = label + strlen(label); + *out++ = p - label; + memcpy(out, label, p - label); + out += p - label; + label += p - label + (*p == '.'); + } + *out = 0; + return(name_len(Out)); +} + + +/******************************************************************* + check if a file exists +********************************************************************/ +BOOL file_exist(char *fname,struct stat *sbuf) +{ + struct stat st; + if (!sbuf) sbuf = &st; + + if (sys_stat(fname,sbuf) != 0) + return(False); + + return(S_ISREG(sbuf->st_mode)); +} + +/******************************************************************* +check a files mod time +********************************************************************/ +time_t file_modtime(char *fname) +{ + struct stat st; + + if (sys_stat(fname,&st) != 0) + return(0); + + return(st.st_mtime); +} + +/******************************************************************* + check if a directory exists +********************************************************************/ +BOOL directory_exist(char *dname,struct stat *st) +{ + struct stat st2; + if (!st) st = &st2; + + if (sys_stat(dname,st) != 0) + return(False); + + return(S_ISDIR(st->st_mode)); +} + +/******************************************************************* +returns the size in bytes of the named file +********************************************************************/ +uint32 file_size(char *file_name) +{ + struct stat buf; + buf.st_size = 0; + sys_stat(file_name,&buf); + return(buf.st_size); +} + +/**************************************************************************** +check if it's a null mtime +****************************************************************************/ +static BOOL null_mtime(time_t mtime) +{ + if (mtime == 0 || mtime == 0xFFFFFFFF) + return(True); + return(False); +} + +/******************************************************************* + create a 16 bit dos packed date +********************************************************************/ +static uint16 make_dos_date1(time_t unixdate,struct tm *t) +{ + uint16 ret=0; + ret = (((unsigned)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1); + ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5)); + return(ret); +} + +/******************************************************************* + create a 16 bit dos packed time +********************************************************************/ +static uint16 make_dos_time1(time_t unixdate,struct tm *t) +{ + uint16 ret=0; + ret = ((((unsigned)t->tm_min >> 3)&0x7) | (((unsigned)t->tm_hour) << 3)); + ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5)); + return(ret); +} + +/******************************************************************* + create a 32 bit dos packed date/time from some parameters + This takes a GMT time and returns a packed localtime structure +********************************************************************/ +static uint32 make_dos_date(time_t unixdate) +{ + struct tm *t; + uint32 ret=0; + + t = LocalTime(&unixdate,GMT_TO_LOCAL); + + ret = make_dos_date1(unixdate,t); + ret = ((ret&0xFFFF)<<16) | make_dos_time1(unixdate,t); + + return(ret); +} + +/******************************************************************* +put a dos date into a buffer (time/date format) +This takes GMT time and puts local time in the buffer +********************************************************************/ +void put_dos_date(char *buf,int offset,time_t unixdate) +{ + uint32 x = make_dos_date(unixdate); + SIVAL(buf,offset,x); +} + +/******************************************************************* +put a dos date into a buffer (date/time format) +This takes GMT time and puts local time in the buffer +********************************************************************/ +void put_dos_date2(char *buf,int offset,time_t unixdate) +{ + uint32 x = make_dos_date(unixdate); + x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16); + SIVAL(buf,offset,x); +} + +/******************************************************************* +put a dos 32 bit "unix like" date into a buffer. This routine takes +GMT and converts it to LOCAL time before putting it (most SMBs assume +localtime for this sort of date) +********************************************************************/ +void put_dos_date3(char *buf,int offset,time_t unixdate) +{ + if (!null_mtime(unixdate)) + unixdate += GMT_TO_LOCAL*TimeDiff(unixdate); + SIVAL(buf,offset,unixdate); +} + +/******************************************************************* + interpret a 32 bit dos packed date/time to some parameters +********************************************************************/ +static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second) +{ + uint32 p0,p1,p2,p3; + + p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF; + p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF; + + *second = 2*(p0 & 0x1F); + *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3); + *hour = (p1>>3)&0xFF; + *day = (p2&0x1F); + *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1; + *year = ((p3>>1)&0xFF) + 80; +} + +/******************************************************************* + create a unix date (int GMT) from a dos date (which is actually in + localtime) +********************************************************************/ +time_t make_unix_date(void *date_ptr) +{ + uint32 dos_date=0; + struct tm t; + time_t ret; + + dos_date = IVAL(date_ptr,0); + + if (dos_date == 0) return(0); + + interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon, + &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec); + t.tm_wday = 1; + t.tm_yday = 1; + t.tm_isdst = -1; + + /* mktime() also does the local to GMT time conversion for us. XXXXX + Do all unixes do this the same?? */ + ret = mktime(&t); + + return(ret); +} + +/******************************************************************* +like make_unix_date() but the words are reversed +********************************************************************/ +time_t make_unix_date2(void *date_ptr) +{ + uint32 x,x2; + + x = IVAL(date_ptr,0); + x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16); + SIVAL(&x,0,x2); + + return(make_unix_date((void *)&x)); +} + +/******************************************************************* + create a unix GMT date from a dos date in 32 bit "unix like" format +these generally arrive as localtimes, with corresponding DST +********************************************************************/ +time_t make_unix_date3(void *date_ptr) +{ + time_t t = IVAL(date_ptr,0); + if (!null_mtime(t)) + t += LOCAL_TO_GMT*TimeDiff(t); + return(t); +} + +/******************************************************************* +return a string representing an attribute for a file +********************************************************************/ +char *attrib_string(int mode) +{ + static char attrstr[10]; + + attrstr[0] = 0; + + if (mode & aVOLID) strcat(attrstr,"V"); + if (mode & aDIR) strcat(attrstr,"D"); + if (mode & aARCH) strcat(attrstr,"A"); + if (mode & aHIDDEN) strcat(attrstr,"H"); + if (mode & aSYSTEM) strcat(attrstr,"S"); + if (mode & aRONLY) strcat(attrstr,"R"); + + return(attrstr); +} + + +/******************************************************************* + case insensitive string compararison +********************************************************************/ +int StrCaseCmp(char *s, char *t) +{ + for (; tolower(*s) == tolower(*t); ++s, ++t) + if (!*s) return 0; + + return tolower(*s) - tolower(*t); +} + +/******************************************************************* + case insensitive string compararison, length limited +********************************************************************/ +int StrnCaseCmp(char *s, char *t, int n) +{ + while (n-- && *s && *t) { + if (tolower(*s) != tolower(*t)) return(tolower(*s) - tolower(*t)); + s++; t++; + } + if (n) return(tolower(*s) - tolower(*t)); + + return(0); +} + +/******************************************************************* + compare 2 strings +********************************************************************/ +BOOL strequal(char *s1,char *s2) +{ + if (s1 == s2) return(True); + if (!s1 || !s2) return(False); + + return(StrCaseCmp(s1,s2)==0); +} + +/******************************************************************* + compare 2 strings up to and including the nth char. + ******************************************************************/ +BOOL strnequal(char *s1,char *s2,int n) +{ + if (s1 == s2) return(True); + if (!s1 || !s2 || !n) return(False); + + return(StrnCaseCmp(s1,s2,n)==0); +} + +/******************************************************************* + compare 2 strings (case sensitive) +********************************************************************/ +BOOL strcsequal(char *s1,char *s2) +{ + if (s1 == s2) return(True); + if (!s1 || !s2) return(False); + + return(strcmp(s1,s2)==0); +} + + +/******************************************************************* + convert a string to lower case +********************************************************************/ +void strlower(char *s) +{ + while (*s) + { +#ifdef KANJI + if (is_shift_jis (*s)) { + s += 2; + } else if (is_kana (*s)) { + s++; + } else { + if (isupper(*s)) + *s = tolower(*s); + s++; + } +#else + if (isupper(*s)) + *s = tolower(*s); + s++; +#endif /* KANJI */ + } +} + +/******************************************************************* + convert a string to upper case +********************************************************************/ +void strupper(char *s) +{ + while (*s) + { +#ifdef KANJI + if (is_shift_jis (*s)) { + s += 2; + } else if (is_kana (*s)) { + s++; + } else { + if (islower(*s)) + *s = toupper(*s); + s++; + } +#else + if (islower(*s)) + *s = toupper(*s); + s++; +#endif + } +} + +/******************************************************************* + convert a string to "normal" form +********************************************************************/ +void strnorm(char *s) +{ + if (case_default == CASE_UPPER) + strupper(s); + else + strlower(s); +} + +/******************************************************************* +check if a string is in "normal" case +********************************************************************/ +BOOL strisnormal(char *s) +{ + if (case_default == CASE_UPPER) + return(!strhaslower(s)); + + return(!strhasupper(s)); +} + + +/**************************************************************************** + string replace +****************************************************************************/ +void string_replace(char *s,char oldc,char newc) +{ + while (*s) + { +#ifdef KANJI + if (is_shift_jis (*s)) { + s += 2; + } else if (is_kana (*s)) { + s++; + } else { + if (oldc == *s) + *s = newc; + s++; + } +#else + if (oldc == *s) + *s = newc; + s++; +#endif /* KANJI */ + } +} + +/**************************************************************************** + make a file into unix format +****************************************************************************/ +void unix_format(char *fname) +{ + pstring namecopy; + string_replace(fname,'\\','/'); +#ifndef KANJI + dos2unix_format(fname, True); +#endif /* KANJI */ + + if (*fname == '/') + { + strcpy(namecopy,fname); + strcpy(fname,"."); + strcat(fname,namecopy); + } +} + +/**************************************************************************** + make a file into dos format +****************************************************************************/ +void dos_format(char *fname) +{ +#ifndef KANJI + unix2dos_format(fname, True); +#endif /* KANJI */ + string_replace(fname,'/','\\'); +} + + +/******************************************************************* + show a smb message structure +********************************************************************/ +void show_msg(char *buf) +{ + int i; + int bcc=0; + if (DEBUGLEVEL < 5) + return; + + DEBUG(5,("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\nsmb_flg=%d\nsmb_flg2=%d\n", + smb_len(buf), + (int)CVAL(buf,smb_com), + (int)CVAL(buf,smb_rcls), + (int)CVAL(buf,smb_reh), + (int)SVAL(buf,smb_err), + (int)CVAL(buf,smb_flg), + (int)SVAL(buf,smb_flg2))); + DEBUG(5,("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\nsmt_wct=%d\n", + (int)SVAL(buf,smb_tid), + (int)SVAL(buf,smb_pid), + (int)SVAL(buf,smb_uid), + (int)SVAL(buf,smb_mid), + (int)CVAL(buf,smb_wct))); + for (i=0;i<(int)CVAL(buf,smb_wct);i++) + DEBUG(5,("smb_vwv[%d]=%d (0x%X)\n",i, + SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i))); + bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct))); + DEBUG(5,("smb_bcc=%d\n",bcc)); + if (DEBUGLEVEL < 10) + return; + for (i=0;i<MIN(bcc,128);i++) + DEBUG(10,("%X ",CVAL(smb_buf(buf),i))); + DEBUG(10,("\n")); +} + +/******************************************************************* + return the length of an smb packet +********************************************************************/ +int smb_len(char *buf) +{ + return( PVAL(buf,3) | (PVAL(buf,2)<<8) | ((PVAL(buf,1)&1)<<16) ); +} + +/******************************************************************* + set the length of an smb packet +********************************************************************/ +void _smb_setlen(char *buf,int len) +{ + buf[0] = 0; + buf[1] = (len&0x10000)>>16; + buf[2] = (len&0xFF00)>>8; + buf[3] = len&0xFF; +} + +/******************************************************************* + set the length and marker of an smb packet +********************************************************************/ +void smb_setlen(char *buf,int len) +{ + _smb_setlen(buf,len); + + CVAL(buf,4) = 0xFF; + CVAL(buf,5) = 'S'; + CVAL(buf,6) = 'M'; + CVAL(buf,7) = 'B'; +} + +/******************************************************************* + setup the word count and byte count for a smb message +********************************************************************/ +int set_message(char *buf,int num_words,int num_bytes,BOOL zero) +{ + if (zero) + bzero(buf + smb_size,num_words*2 + num_bytes); + CVAL(buf,smb_wct) = num_words; + SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes); + smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4); + return (smb_size + num_words*2 + num_bytes); +} + +/******************************************************************* +return the number of smb words +********************************************************************/ +int smb_numwords(char *buf) +{ + return (CVAL(buf,smb_wct)); +} + +/******************************************************************* +return the size of the smb_buf region of a message +********************************************************************/ +int smb_buflen(char *buf) +{ + return(SVAL(buf,smb_vwv0 + smb_numwords(buf)*2)); +} + +/******************************************************************* + return a pointer to the smb_buf data area +********************************************************************/ +int smb_buf_ofs(char *buf) +{ + return (smb_size + CVAL(buf,smb_wct)*2); +} + +/******************************************************************* + return a pointer to the smb_buf data area +********************************************************************/ +char *smb_buf(char *buf) +{ + return (buf + smb_buf_ofs(buf)); +} + +/******************************************************************* +return the SMB offset into an SMB buffer +********************************************************************/ +int smb_offset(char *p,char *buf) +{ + return(PTR_DIFF(p,buf+4)); +} + + +/******************************************************************* +skip past some strings in a buffer +********************************************************************/ +char *skip_string(char *buf,int n) +{ + while (n--) + buf += strlen(buf) + 1; + return(buf); +} + +/******************************************************************* +trim the specified elements off the front and back of a string +********************************************************************/ +BOOL trim_string(char *s,char *front,char *back) +{ + BOOL ret = False; + while (front && *front && strncmp(s,front,strlen(front)) == 0) + { + char *p = s; + ret = True; + while (1) + { + if (!(*p = p[strlen(front)])) + break; + p++; + } + } + while (back && *back && strlen(s) >= strlen(back) && + (strncmp(s+strlen(s)-strlen(back),back,strlen(back))==0)) + { + ret = True; + s[strlen(s)-strlen(back)] = 0; + } + return(ret); +} + + +/******************************************************************* +reduce a file name, removing .. elements. +********************************************************************/ +void dos_clean_name(char *s) +{ + char *p=NULL; + + DEBUG(3,("dos_clean_name [%s]\n",s)); + + /* remove any double slashes */ + string_sub(s, "\\\\", "\\"); + + while ((p = strstr(s,"\\..\\")) != NULL) + { + pstring s1; + + *p = 0; + strcpy(s1,p+3); + + if ((p=strrchr(s,'\\')) != NULL) + *p = 0; + else + *s = 0; + strcat(s,s1); + } + + trim_string(s,NULL,"\\.."); + + string_sub(s, "\\.\\", "\\"); +} + +/******************************************************************* +reduce a file name, removing .. elements. +********************************************************************/ +void unix_clean_name(char *s) +{ + char *p=NULL; + + DEBUG(3,("unix_clean_name [%s]\n",s)); + + /* remove any double slashes */ + string_sub(s, "//","/"); + + while ((p = strstr(s,"/../")) != NULL) + { + pstring s1; + + *p = 0; + strcpy(s1,p+3); + + if ((p=strrchr(s,'/')) != NULL) + *p = 0; + else + *s = 0; + strcat(s,s1); + } + + trim_string(s,NULL,"/.."); +} + + +/******************************************************************* +a wrapper for the normal chdir() function +********************************************************************/ +int ChDir(char *path) +{ + int res; + static pstring LastDir=""; + + if (strcsequal(path,".")) return(0); + + if (*path == '/' && strcsequal(LastDir,path)) return(0); + DEBUG(3,("chdir to %s\n",path)); + res = sys_chdir(path); + if (!res) + strcpy(LastDir,path); + return(res); +} + + +/******************************************************************* + return the absolute current directory path. A dumb version. +********************************************************************/ +static char *Dumb_GetWd(char *s) +{ +#ifdef USE_GETCWD + return ((char *)getcwd(s,sizeof(pstring))); +#else + return ((char *)getwd(s)); +#endif +} + + +/* number of list structures for a caching GetWd function. */ +#define MAX_GETWDCACHE (50) + +struct +{ + ino_t inode; + dev_t dev; + char *text; + BOOL valid; +} ino_list[MAX_GETWDCACHE]; + +BOOL use_getwd_cache=True; + +/******************************************************************* + return the absolute current directory path +********************************************************************/ +char *GetWd(char *str) +{ + pstring s; + static BOOL getwd_cache_init = False; + struct stat st, st2; + int i; + + *s = 0; + + if (!use_getwd_cache) + return(Dumb_GetWd(str)); + + /* init the cache */ + if (!getwd_cache_init) + { + getwd_cache_init = True; + for (i=0;i<MAX_GETWDCACHE;i++) + { + string_init(&ino_list[i].text,""); + ino_list[i].valid = False; + } + } + + /* Get the inode of the current directory, if this doesn't work we're + in trouble :-) */ + + if (stat(".",&st) == -1) + { + DEBUG(0,("Very strange, couldn't stat \".\"\n")); + return(Dumb_GetWd(str)); + } + + + for (i=0; i<MAX_GETWDCACHE; i++) + if (ino_list[i].valid) + { + + /* If we have found an entry with a matching inode and dev number + then find the inode number for the directory in the cached string. + If this agrees with that returned by the stat for the current + directory then all is o.k. (but make sure it is a directory all + the same...) */ + + if (st.st_ino == ino_list[i].inode && + st.st_dev == ino_list[i].dev) + { + if (stat(ino_list[i].text,&st2) == 0) + { + if (st.st_ino == st2.st_ino && + st.st_dev == st2.st_dev && + (st2.st_mode & S_IFMT) == S_IFDIR) + { + strcpy (str, ino_list[i].text); + + /* promote it for future use */ + array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); + return (str); + } + else + { + /* If the inode is different then something's changed, + scrub the entry and start from scratch. */ + ino_list[i].valid = False; + } + } + } + } + + + /* We don't have the information to hand so rely on traditional methods. + The very slow getcwd, which spawns a process on some systems, or the + not quite so bad getwd. */ + + if (!Dumb_GetWd(s)) + { + DEBUG(0,("Getwd failed, errno %d\n",errno)); + return (NULL); + } + + strcpy(str,s); + + DEBUG(5,("GetWd %s, inode %d, dev %x\n",s,(int)st.st_ino,(int)st.st_dev)); + + /* add it to the cache */ + i = MAX_GETWDCACHE - 1; + string_set(&ino_list[i].text,s); + ino_list[i].dev = st.st_dev; + ino_list[i].inode = st.st_ino; + ino_list[i].valid = True; + + /* put it at the top of the list */ + array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); + + return (str); +} + + + +/******************************************************************* +reduce a file name, removing .. elements and checking that +it is below dir in the heirachy. This uses GetWd() and so must be run +on the system that has the referenced file system. + +widelinks are allowed if widelinks is true +********************************************************************/ +BOOL reduce_name(char *s,char *dir,BOOL widelinks) +{ +#ifndef REDUCE_PATHS + return True; +#else + pstring dir2; + pstring wd; + pstring basename; + pstring newname; + char *p=NULL; + BOOL relative = (*s != '/'); + + *dir2 = *wd = *basename = *newname = 0; + + if (widelinks) + { + unix_clean_name(s); + /* can't have a leading .. */ + if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/')) + { + DEBUG(3,("Illegal file name? (%s)\n",s)); + return(False); + } + return(True); + } + + DEBUG(3,("reduce_name [%s] [%s]\n",s,dir)); + + /* remove any double slashes */ + string_sub(s,"//","/"); + + strcpy(basename,s); + p = strrchr(basename,'/'); + + if (!p) + return(True); + + if (!GetWd(wd)) + { + DEBUG(0,("couldn't getwd for %s %s\n",s,dir)); + return(False); + } + + if (ChDir(dir) != 0) + { + DEBUG(0,("couldn't chdir to %s\n",dir)); + return(False); + } + + if (!GetWd(dir2)) + { + DEBUG(0,("couldn't getwd for %s\n",dir)); + ChDir(wd); + return(False); + } + + + if (p && (p != basename)) + { + *p = 0; + if (strcmp(p+1,".")==0) + p[1]=0; + if (strcmp(p+1,"..")==0) + *p = '/'; + } + + if (ChDir(basename) != 0) + { + ChDir(wd); + DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,basename)); + return(False); + } + + if (!GetWd(newname)) + { + ChDir(wd); + DEBUG(2,("couldn't get wd for %s %s\n",s,dir2)); + return(False); + } + + if (p && (p != basename)) + { + strcat(newname,"/"); + strcat(newname,p+1); + } + + { + int l = strlen(dir2); + if (dir2[l-1] == '/') + l--; + + if (strncmp(newname,dir2,l) != 0) + { + ChDir(wd); + DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,l)); + return(False); + } + + if (relative) + { + if (newname[l] == '/') + strcpy(s,newname + l + 1); + else + strcpy(s,newname+l); + } + else + strcpy(s,newname); + } + + ChDir(wd); + + if (strlen(s) == 0) + strcpy(s,"./"); + + DEBUG(3,("reduced to %s\n",s)); + return(True); +#endif +} + +/**************************************************************************** +expand some *s +****************************************************************************/ +static void expand_one(char *Mask,int len) +{ + char *p1; + while ((p1 = strchr(Mask,'*')) != NULL) + { + int lfill = (len+1) - strlen(Mask); + int l1= (p1 - Mask); + pstring tmp; + strcpy(tmp,Mask); + memset(tmp+l1,'?',lfill); + strcpy(tmp + l1 + lfill,Mask + l1 + 1); + strcpy(Mask,tmp); + } +} + +/**************************************************************************** +expand a wildcard expression, replacing *s with ?s +****************************************************************************/ +void expand_mask(char *Mask,BOOL doext) +{ + pstring mbeg,mext; + pstring dirpart; + pstring filepart; + BOOL hasdot = False; + char *p1; + BOOL absolute = (*Mask == '\\'); + + *mbeg = *mext = *dirpart = *filepart = 0; + + /* parse the directory and filename */ + if (strchr(Mask,'\\')) + dirname_dos(Mask,dirpart); + + filename_dos(Mask,filepart); + + strcpy(mbeg,filepart); + if ((p1 = strchr(mbeg,'.')) != NULL) + { + hasdot = True; + *p1 = 0; + p1++; + strcpy(mext,p1); + } + else + { + strcpy(mext,""); + if (strlen(mbeg) > 8) + { + strcpy(mext,mbeg + 8); + mbeg[8] = 0; + } + } + + if (*mbeg == 0) + strcpy(mbeg,"????????"); + if ((*mext == 0) && doext && !hasdot) + strcpy(mext,"???"); + + if (strequal(mbeg,"*") && *mext==0) + strcpy(mext,"*"); + + /* expand *'s */ + expand_one(mbeg,8); + if (*mext) + expand_one(mext,3); + + strcpy(Mask,dirpart); + if (*dirpart || absolute) strcat(Mask,"\\"); + strcat(Mask,mbeg); + strcat(Mask,"."); + strcat(Mask,mext); + + DEBUG(6,("Mask expanded to [%s]\n",Mask)); +} + + +/**************************************************************************** +does a string have any uppercase chars in it? +****************************************************************************/ +BOOL strhasupper(char *s) +{ + while (*s) + { +#ifdef KANJI + if (is_shift_jis (*s)) { + s += 2; + } else if (is_kana (*s)) { + s++; + } else { + if (isupper(*s)) return(True); + s++; + } +#else + if (isupper(*s)) return(True); + s++; +#endif /* KANJI */ + } + return(False); +} + +/**************************************************************************** +does a string have any lowercase chars in it? +****************************************************************************/ +BOOL strhaslower(char *s) +{ + while (*s) + { +#ifdef KANJI + if (is_shift_jis (*s)) { + s += 2; + } else if (is_kana (*s)) { + s++; + } else { + if (islower(*s)) return(True); + s++; + } +#else + if (islower(*s)) return(True); + s++; +#endif /* KANJI */ + } + return(False); +} + +/**************************************************************************** +find the number of chars in a string +****************************************************************************/ +int count_chars(char *s,char c) +{ + int count=0; + while (*s) + { + if (*s == c) + count++; + s++; + } + return(count); +} + + +/**************************************************************************** + make a dir struct +****************************************************************************/ +void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode,time_t date) +{ + char *p; + pstring mask2; + + strcpy(mask2,mask); + + if ((mode & aDIR) != 0) + size = 0; + + memset(buf+1,' ',11); + if ((p = strchr(mask2,'.')) != NULL) + { + *p = 0; + memcpy(buf+1,mask2,MIN(strlen(mask2),8)); + memcpy(buf+9,p+1,MIN(strlen(p+1),3)); + *p = '.'; + } + else + memcpy(buf+1,mask2,MIN(strlen(mask2),11)); + + bzero(buf+21,DIR_STRUCT_SIZE-21); + CVAL(buf,21) = mode; + put_dos_date(buf,22,date); + SSVAL(buf,26,size & 0xFFFF); + SSVAL(buf,28,size >> 16); + StrnCpy(buf+30,fname,12); + if (!case_sensitive) + strupper(buf+30); + DEBUG(8,("put name [%s] into dir struct\n",buf+30)); +} + + +/******************************************************************* +close the low 3 fd's and open dev/null in their place +********************************************************************/ +void close_low_fds(void) +{ + int fd; + int i; + close(0); close(1); close(2); + /* try and use up these file descriptors, so silly + library routines writing to stdout etc won't cause havoc */ + for (i=0;i<3;i++) { + fd = open("/dev/null",O_RDWR,0); + if (fd < 0) fd = open("/dev/null",O_WRONLY,0); + if (fd < 0) { + DEBUG(0,("Can't open /dev/null\n")); + return; + } + if (fd != i) { + DEBUG(0,("Didn't get file descriptor %d\n",i)); + return; + } + } +} + + +/**************************************************************************** +write to a socket +****************************************************************************/ +int write_socket(int fd,char *buf,int len) +{ + int ret=0; + + if (passive) + return(len); + DEBUG(6,("write_socket(%d,%d)\n",fd,len)); + ret = write_data(fd,buf,len); + + DEBUG(6,("write_socket(%d,%d) wrote %d\n",fd,len,ret)); + return(ret); +} + +/**************************************************************************** +read from a socket +****************************************************************************/ +int read_udp_socket(int fd,char *buf,int len) +{ + int ret; + struct sockaddr sock; + int socklen; + + socklen = sizeof(sock); + bzero((char *)&sock,socklen); + bzero((char *)&lastip,sizeof(lastip)); + ret = recvfrom(fd,buf,len,0,&sock,&socklen); + if (ret <= 0) + { + DEBUG(2,("read socket failed. ERRNO=%d\n",errno)); + return(0); + } + + lastip = *(struct in_addr *) &sock.sa_data[2]; + lastport = ntohs(((struct sockaddr_in *)&sock)->sin_port); + + return(ret); +} + +/**************************************************************************** +Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available, +else +if SYSV use O_NDELAY +if BSD use FNDELAY +****************************************************************************/ +int set_blocking(int fd, BOOL set) +{ +int val; +#ifdef O_NONBLOCK +#define FLAG_TO_SET O_NONBLOCK +#else +#ifdef SYSV +#define FLAG_TO_SET O_NDELAY +#else /* BSD */ +#define FLAG_TO_SET FNDELAY +#endif +#endif + + if((val = fcntl(fd, F_GETFL, 0))==-1) + return -1; + if(set) /* Turn blocking on - ie. clear nonblock flag */ + val &= ~FLAG_TO_SET; + else + val |= FLAG_TO_SET; + return fcntl( fd, F_SETFL, val); +#undef FLAG_TO_SET +} + + +/**************************************************************************** +Calculate the difference in timeout values. Return 1 if val1 > val2, +0 if val1 == val2, -1 if val1 < val2. Stores result in retval. retval +may be == val1 or val2 +****************************************************************************/ +static int tval_sub( struct timeval *retval, struct timeval *val1, struct timeval *val2) +{ + int usecdiff = val1->tv_usec - val2->tv_usec; + int secdiff = val1->tv_sec - val2->tv_sec; + if(usecdiff < 0) { + usecdiff = 1000000 + usecdiff; + secdiff--; + } + retval->tv_sec = secdiff; + retval->tv_usec = usecdiff; + if(secdiff < 0) + return -1; + if(secdiff > 0) + return 1; + return (usecdiff < 0 ) ? -1 : ((usecdiff > 0 ) ? 1 : 0); +} + +/**************************************************************************** +read data from a device with a timout in msec. +mincount = if timeout, minimum to read before returning +maxcount = number to be read. +****************************************************************************/ +int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact) +{ + fd_set fds; + int selrtn; + int readret; + int nread = 0; + struct timeval timeout, tval1, tval2, tvaldiff; + int error_limit = 5; + + /* just checking .... */ + if (maxcnt <= 0) return(0); + + if(time_out == -2) + time_out = DEFAULT_PIPE_TIMEOUT; + + /* Blocking read */ + if(time_out < 0) { + if (mincnt == 0) mincnt = maxcnt; + + while (nread < mincnt) + { + readret = read(fd, buf + nread, maxcnt - nread); + if (readret <= 0) return(nread); + nread += readret; + } + return(nread); + } + + /* Non blocking read */ + if(time_out == 0) { + set_blocking(fd, False); + nread = read_data(fd, buf, mincnt); + if (nread < maxcnt) + nread += read(fd,buf+nread,maxcnt-nread); + if(nread == -1 && errno == EWOULDBLOCK) + nread = 0; + set_blocking(fd,True); + return nread; + } + + /* Most difficult - timeout read */ + /* If this is ever called on a disk file and + mincnt is greater then the filesize then + system performance will suffer severely as + select always return true on disk files */ + + /* Set initial timeout */ + timeout.tv_sec = time_out / 1000; + timeout.tv_usec = 1000 * (time_out % 1000); + + /* As most UNIXes don't modify the value of timeout + when they return from select we need to get the timeofday (in usec) + now, and also after the select returns so we know + how much time has elapsed */ + + if (exact) + GetTimeOfDay( &tval1); + nread = 0; /* Number of bytes we have read */ + + for(;;) + { + FD_ZERO(&fds); + FD_SET(fd,&fds); + + selrtn = sys_select(&fds,&timeout); + + /* Check if error */ + if(selrtn == -1) { + errno = EBADF; + return -1; + } + + /* Did we timeout ? */ + if (selrtn == 0) { + if (nread < mincnt) return -1; + break; /* Yes */ + } + + readret = read(fd, buf+nread, maxcnt-nread); + if (readret == 0 && nread < mincnt) { + /* error_limit should not really be needed, but some systems + do strange things ... I don't want to just continue + indefinately in case we get an infinite loop */ + if (error_limit--) continue; + return(-1); + } + + if (readret < 0) { + /* force a particular error number for + portability */ + DEBUG(5,("read gave error %s\n",strerror(errno))); + errno = EBADF; + return -1; + } + + nread += readret; + + /* If we have read more than mincnt then return */ + if (nread >= mincnt) + break; + + /* We need to do another select - but first reduce the + time_out by the amount of time already elapsed - if + this is less than zero then return */ + if (exact) { + GetTimeOfDay(&tval2); + (void)tval_sub( &tvaldiff, &tval2, &tval1); + + if (tval_sub(&timeout, &timeout, &tvaldiff) <= 0) + break; /* We timed out */ + } + + /* Save the time of day as we need to do the select + again (saves a system call) */ + tval1 = tval2; + } + + /* Return the number we got */ + return(nread); +} + +/**************************************************************************** +read data from the client. Maxtime is in milliseconds +****************************************************************************/ +int read_max_udp(int fd,char *buffer,int bufsize,int maxtime) +{ + fd_set fds; + int selrtn; + int nread; + struct timeval timeout; + + FD_ZERO(&fds); + FD_SET(fd,&fds); + + timeout.tv_sec = maxtime / 1000; + timeout.tv_usec = (maxtime % 1000) * 1000; + + selrtn = sys_select(&fds,maxtime>0?&timeout:NULL); + + if (!FD_ISSET(fd,&fds)) + return 0; + + nread = read_udp_socket(fd, buffer, bufsize); + + /* return the number got */ + return(nread); +} + +/******************************************************************* +find the difference in milliseconds between two struct timeval +values +********************************************************************/ +int TvalDiff(struct timeval *tvalold,struct timeval *tvalnew) +{ + return((tvalnew->tv_sec - tvalold->tv_sec)*1000 + + ((int)tvalnew->tv_usec - (int)tvalold->tv_usec)/1000); +} + +/**************************************************************************** +send a keepalive packet (rfc1002) +****************************************************************************/ +BOOL send_keepalive(int client) +{ + unsigned char buf[4]; + + buf[0] = 0x85; + buf[1] = buf[2] = buf[3] = 0; + + return(write_data(client,(char *)buf,4) == 4); +} + + + +/**************************************************************************** + read data from the client, reading exactly N bytes. +****************************************************************************/ +int read_data(int fd,char *buffer,int N) +{ + int ret; + int total=0; + + while (total < N) + { + ret = read(fd,buffer + total,N - total); + + /* this is for portability */ + if (ret < 0) + errno = EBADF; + + if (ret <= 0) + return total; + total += ret; + } + return total; +} + + +/**************************************************************************** + write data to a fd +****************************************************************************/ +int write_data(int fd,char *buffer,int N) +{ + int total=0; + int ret; + + while (total < N) + { + ret = write(fd,buffer + total,N - total); + + if (ret <= 0) + return total; + + total += ret; + } + return total; +} + + +/* variables used by the read prediction module */ +int rp_fd = -1; +int rp_offset = 0; +int rp_length = 0; +int rp_alloced = 0; +int rp_predict_fd = -1; +int rp_predict_offset = 0; +int rp_predict_length = 0; +int rp_timeout = 5; +time_t rp_time = 0; +char *rp_buffer = NULL; +BOOL predict_skip=False; +time_t smb_last_time=(time_t)0; + +/**************************************************************************** +handle read prediction on a file +****************************************************************************/ +int read_predict(int fd,int offset,char *buf,char **ptr,int num) +{ + int ret = 0; + int possible = rp_length - (offset - rp_offset); + + possible = MIN(possible,num); + + /* give data if possible */ + if (fd == rp_fd && + offset >= rp_offset && + possible>0 && + smb_last_time-rp_time < rp_timeout) + { + ret = possible; + if (buf) + memcpy(buf,rp_buffer + (offset-rp_offset),possible); + else + *ptr = rp_buffer + (offset-rp_offset); + DEBUG(5,("read-prediction gave %d bytes of %d\n",ret,num)); + } + + if (ret == num) { + predict_skip = True; + } else { + predict_skip = False; + + /* prepare the next prediction */ + rp_predict_fd = fd; + rp_predict_offset = offset + num; + rp_predict_length = num; + } + + if (ret < 0) ret = 0; + + return(ret); +} + +/**************************************************************************** +pre-read some data +****************************************************************************/ +void do_read_prediction() +{ + if (predict_skip) return; + + if (rp_predict_fd == -1) + return; + + rp_fd = rp_predict_fd; + rp_offset = rp_predict_offset; + rp_length = 0; + + rp_predict_fd = -1; + + rp_predict_length = MIN(rp_predict_length,2*ReadSize); + rp_predict_length = MAX(rp_predict_length,1024); + rp_offset = (rp_offset/1024)*1024; + rp_predict_length = (rp_predict_length/1024)*1024; + + if (rp_predict_length > rp_alloced) + { + rp_buffer = Realloc(rp_buffer,rp_predict_length); + rp_alloced = rp_predict_length; + if (!rp_buffer) + { + DEBUG(0,("can't allocate read-prediction buffer\n")); + rp_predict_fd = -1; + rp_fd = -1; + rp_alloced = 0; + return; + } + } + + if (lseek(rp_fd,rp_offset,SEEK_SET) != rp_offset) { + rp_fd = -1; + rp_predict_fd = -1; + return; + } + + rp_length = read(rp_fd,rp_buffer,rp_predict_length); + rp_time = time(NULL); + if (rp_length < 0) + rp_length = 0; +} + +/**************************************************************************** +invalidate read-prediction on a fd +****************************************************************************/ +void invalidate_read_prediction(int fd) +{ + if (rp_fd == fd) + rp_fd = -1; + if (rp_predict_fd == fd) + rp_predict_fd = -1; +} + + +/**************************************************************************** +transfer some data between two fd's +****************************************************************************/ +int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align) +{ + static char *buf=NULL; + char *buf1,*abuf; + static int size = 0; + int total = 0; + + DEBUG(4,("transfer_file %d (head=%d) called\n",n,headlen)); + + if ((size < ReadSize) && buf) { + free(buf); + buf = NULL; + } + + size = MAX(ReadSize,1024); + + while (!buf && size>0) { + buf = (char *)Realloc(buf,size+8); + if (!buf) size /= 2; + } + if (!buf) { + DEBUG(0,("Can't allocate transfer buffer!\n")); + exit(1); + } + + abuf = buf + (align%8); + + if (header) + n += headlen; + + while (n > 0) + { + int s = MIN(n,size); + int ret,ret2=0; + + ret = 0; + + if (header && (headlen >= MIN(s,1024))) { + buf1 = header; + s = headlen; + ret = headlen; + headlen = 0; + header = NULL; + } else { + buf1 = abuf; + } + + if (header && headlen > 0) + { + ret = MIN(headlen,size); + memcpy(buf1,header,ret); + headlen -= ret; + header += ret; + if (headlen <= 0) header = NULL; + } + + if (s > ret) + ret += read(infd,buf1+ret,s-ret); + + if (ret > 0) + { + ret2 = (outfd>=0?write_data(outfd,buf1,ret):ret); + if (ret2 > 0) total += ret2; + /* if we can't write then dump excess data */ + if (ret2 != ret) + transfer_file(infd,-1,n-(ret+headlen),NULL,0,0); + } + if (ret <= 0 || ret2 != ret) + return(total); + n -= ret; + } + return(total); +} + + +/**************************************************************************** +read 4 bytes of a smb packet and return the smb length of the packet +possibly store the result in the buffer +****************************************************************************/ +int read_smb_length(int fd,char *inbuf,int timeout) +{ + char *buffer; + char buf[4]; + int len=0, msg_type; + BOOL ok=False; + + if (inbuf) + buffer = inbuf; + else + buffer = buf; + + while (!ok) + { + if (timeout > 0) + ok = (read_with_timeout(fd,buffer,4,4,timeout,False) == 4); + else + ok = (read_data(fd,buffer,4) == 4); + + if (!ok) + { + if (timeout>0) + { + DEBUG(10,("select timeout (%d)\n", timeout)); + return(-1); + } + else + { + DEBUG(6,("couldn't read from client\n")); + exit(1); + } + } + + len = smb_len(buffer); + msg_type = CVAL(buffer,0); + + if (msg_type == 0x85) + { + DEBUG(5,( "Got keepalive packet\n")); + ok = False; + } + } + + DEBUG(10,("got smb length of %d\n",len)); + + return(len); +} + + + +/**************************************************************************** + read an smb from a fd and return it's length +The timeout is in milli seconds +****************************************************************************/ +BOOL receive_smb(int fd,char *buffer,int timeout) +{ + int len; + BOOL ok; + + bzero(buffer,smb_size + 100); + + len = read_smb_length(fd,buffer,timeout); + if (len == -1) + return(False); + + if (len > BUFFER_SIZE) + { + DEBUG(0,("Invalid packet length! (%d bytes)\n",len)); + if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) + exit(1); + } + + ok = (read_data(fd,buffer+4,len) == len); + + if (!ok) + { + close_sockets(); + exit(1); + } + + return(True); +} + + +/**************************************************************************** + send an smb to a fd +****************************************************************************/ +BOOL send_smb(int fd,char *buffer) +{ + int len; + int ret,nwritten=0; + len = smb_len(buffer) + 4; + + while (nwritten < len) + { + ret = write_socket(fd,buffer+nwritten,len - nwritten); + if (ret <= 0) + { + DEBUG(0,("Error writing %d bytes to client. %d. Exiting\n",len,ret)); + close_sockets(); + exit(1); + } + nwritten += ret; + } + + + return True; +} + + +/**************************************************************************** +find a pointer to a netbios name +****************************************************************************/ +char *name_ptr(char *buf,int ofs) +{ + unsigned char c = *(unsigned char *)(buf+ofs); + + if ((c & 0xC0) == 0xC0) + { + uint16 l; + char p[2]; + memcpy(p,buf+ofs,2); + p[0] &= ~0xC0; + l = RSVAL(p,0); + DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l)); + return(buf + l); + } + else + return(buf+ofs); +} + +/**************************************************************************** +extract a netbios name from a buf +****************************************************************************/ +int name_extract(char *buf,int ofs,char *name) +{ + char *p = name_ptr(buf,ofs); + int d = PTR_DIFF(p,buf+ofs); + strcpy(name,""); + if (d < -50 || d > 50) return(0); + return(name_interpret(p,name)); +} + + +/**************************************************************************** +return the total storage length of a mangled name +****************************************************************************/ +int name_len(char *s) +{ + char *s0=s; + unsigned char c = *(unsigned char *)s; + if ((c & 0xC0) == 0xC0) + return(2); + while (*s) s += (*s)+1; + return(PTR_DIFF(s,s0)+1); +} + +/**************************************************************************** +send a single packet to a port on another machine +****************************************************************************/ +BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type) +{ + BOOL ret; + int out_fd; + struct sockaddr_in sock_out; + + if (passive) + return(True); + + /* create a socket to write to */ + out_fd = socket(AF_INET, type, 0); + if (out_fd == -1) + { + DEBUG(0,("socket failed")); + return False; + } + + /* set the address and port */ + bzero((char *)&sock_out,sizeof(sock_out)); + putip((char *)&sock_out.sin_addr,(char *)&ip); + sock_out.sin_port = htons( port ); + sock_out.sin_family = AF_INET; + + if (DEBUGLEVEL > 0) + DEBUG(3,("sending a packet of len %d to (%s) on port %d of type %s\n", + len,inet_ntoa(ip),port,type==SOCK_DGRAM?"DGRAM":"STREAM")); + + /* send it */ + ret = (sendto(out_fd,buf,len,0,(struct sockaddr *)&sock_out,sizeof(sock_out)) >= 0); + + if (!ret) + DEBUG(0,("Packet send to %s(%d) failed ERRNO=%d\n", + inet_ntoa(ip),port,errno)); + + close(out_fd); + return(ret); +} + +/******************************************************************* +sleep for a specified number of milliseconds +********************************************************************/ +void msleep(int t) +{ + int tdiff=0; + struct timeval tval,t1,t2; + fd_set fds; + + GetTimeOfDay(&t1); + GetTimeOfDay(&t2); + + while (tdiff < t) { + tval.tv_sec = (t-tdiff)/1000; + tval.tv_usec = 1000*((t-tdiff)%1000); + + FD_ZERO(&fds); + errno = 0; + sys_select(&fds,&tval); + + GetTimeOfDay(&t2); + tdiff = TvalDiff(&t1,&t2); + } +} + +/**************************************************************************** +check if a string is part of a list +****************************************************************************/ +BOOL in_list(char *s,char *list,BOOL casesensitive) +{ + pstring tok; + char *p=list; + + if (!list) return(False); + + while (next_token(&p,tok,LIST_SEP)) + { + if (casesensitive) { + if (strcmp(tok,s) == 0) + return(True); + } else { + if (StrCaseCmp(tok,s) == 0) + return(True); + } + } + return(False); +} + +/* this is used to prevent lots of mallocs of size 1 */ +static char *null_string = NULL; + +/**************************************************************************** +set a string value, allocing the space for the string +****************************************************************************/ +BOOL string_init(char **dest,char *src) +{ + int l; + if (!src) + src = ""; + + l = strlen(src); + + if (l == 0) + { + if (!null_string) + null_string = (char *)malloc(1); + + *null_string = 0; + *dest = null_string; + } + else + { + *dest = (char *)malloc(l+1); + strcpy(*dest,src); + } + return(True); +} + +/**************************************************************************** +free a string value +****************************************************************************/ +void string_free(char **s) +{ + if (!s || !(*s)) return; + if (*s == null_string) + *s = NULL; + if (*s) free(*s); + *s = NULL; +} + +/**************************************************************************** +set a string value, allocing the space for the string, and deallocating any +existing space +****************************************************************************/ +BOOL string_set(char **dest,char *src) +{ + string_free(dest); + + return(string_init(dest,src)); +} + +/**************************************************************************** +substitute a string for a pattern in another string. Make sure there is +enough room! + +This routine looks for pattern in s and replaces it with +insert. It may do multiple replacements. + +return True if a substitution was done. +****************************************************************************/ +BOOL string_sub(char *s,char *pattern,char *insert) +{ + BOOL ret = False; + char *p; + int ls,lp,li; + + if (!insert || !pattern || !s) return(False); + + ls = strlen(s); + lp = strlen(pattern); + li = strlen(insert); + + if (!*pattern) return(False); + + while (lp <= ls && (p = strstr(s,pattern))) + { + ret = True; + memmove(p+li,p+lp,ls + 1 - (PTR_DIFF(p,s) + lp)); + memcpy(p,insert,li); + s = p + li; + ls = strlen(s); + } + return(ret); +} + + + +/********************************************************* +* Recursive routine that is called by mask_match. +* Does the actual matching. +*********************************************************/ +BOOL do_match(char *str, char *regexp, int case_sig) +{ + char *p; + + for( p = regexp; *p && *str; ) { + switch(*p) { + case '?': + str++; p++; + break; + + case '*': + /* Look for a character matching + the one after the '*' */ + p++; + if(!*p) + return True; /* Automatic match */ + while(*str) { + while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str)))) + str++; + if(do_match(str,p,case_sig)) + return True; + if(!*str) + return False; + else + str++; + } + return False; + + default: + if(case_sig) { + if(*str != *p) + return False; + } else { + if(toupper(*str) != toupper(*p)) + return False; + } + str++, p++; + break; + } + } + if(!*p && !*str) + return True; + + if (!*p && str[0] == '.' && str[1] == 0) + return(True); + + if (!*str && *p == '?') + { + while (*p == '?') p++; + return(!*p); + } + + if(!*str && (*p == '*' && p[1] == '\0')) + return True; + return False; +} + + +/********************************************************* +* Routine to match a given string with a regexp - uses +* simplified regexp that takes * and ? only. Case can be +* significant or not. +*********************************************************/ +BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2) +{ + char *p; + pstring p1, p2; + fstring ebase,eext,sbase,sext; + + BOOL matched; + + /* Make local copies of str and regexp */ + StrnCpy(p1,regexp,sizeof(pstring)-1); + StrnCpy(p2,str,sizeof(pstring)-1); + + if (!strchr(p2,'.')) { + strcat(p2,"."); + } + +/* + if (!strchr(p1,'.')) { + strcat(p1,"."); + } +*/ + +#if 0 + if (strchr(p1,'.')) + { + string_sub(p1,"*.*","*"); + string_sub(p1,".*","*"); + } +#endif + + /* Remove any *? and ** as they are meaningless */ + for(p = p1; *p; p++) + while( *p == '*' && (p[1] == '?' ||p[1] == '*')) + (void)strcpy( &p[1], &p[2]); + + if (strequal(p1,"*")) return(True); + + DEBUG(5,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig)); + + if (trans2) { + strcpy(ebase,p1); + strcpy(sbase,p2); + } else { + if ((p=strrchr(p1,'.'))) { + *p = 0; + strcpy(ebase,p1); + strcpy(eext,p+1); + } else { + strcpy(ebase,p1); + eext[0] = 0; + } + + if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) { + *p = 0; + strcpy(sbase,p2); + strcpy(sext,p+1); + } else { + strcpy(sbase,p2); + strcpy(sext,""); + } + } + + matched = do_match(sbase,ebase,case_sig) && + (trans2 || do_match(sext,eext,case_sig)); + + DEBUG(5,("mask_match returning %d\n", matched)); + + return matched; +} + + + +/**************************************************************************** +become a daemon, discarding the controlling terminal +****************************************************************************/ +void become_daemon(void) +{ +#ifndef NO_FORK_DEBUG + if (fork()) + exit(0); + + /* detach from the terminal */ +#ifdef USE_SETSID + setsid(); +#else +#ifdef TIOCNOTTY + { + int i = open("/dev/tty", O_RDWR); + if (i >= 0) + { + ioctl(i, (int) TIOCNOTTY, (char *)0); + close(i); + } + } +#endif +#endif +#endif +} + +/**************************************************************************** +calculate the default netmask for an address +****************************************************************************/ +static void default_netmask(struct in_addr *inm, struct in_addr *iad) +{ + unsigned long ad = ntohl(iad->s_addr); + unsigned long nm; + /* + ** Guess a netmask based on the class of the IP address given. + */ + if ( (ad & 0x80000000) == 0 ) { + /* class A address */ + nm = 0xFF000000; + } else if ( (ad & 0xC0000000) == 0x80000000 ) { + /* class B address */ + nm = 0xFFFF0000; + } else if ( (ad & 0xE0000000) == 0xC0000000 ) { + /* class C address */ + nm = 0xFFFFFF00; + } else { + /* class D or E; netmask doesn't make much sense - guess 4 bits */ + nm = 0xFFFFFFF0; + } + inm->s_addr = htonl(nm); +} + +/**************************************************************************** + get the broadcast address for our address +(troyer@saifr00.ateng.az.honeywell.com) +****************************************************************************/ +void get_broadcast(struct in_addr *if_ipaddr, + struct in_addr *if_bcast, + struct in_addr *if_nmask) +{ + BOOL found = False; +#ifndef NO_GET_BROADCAST + int sock = -1; /* AF_INET raw socket desc */ + char buff[1024]; + struct ifreq *ifr=NULL; + int i; + +#if defined(EVEREST) + int n_interfaces; + struct ifconf ifc; + struct ifreq *ifreqs; +#elif defined(USE_IFREQ) + struct ifreq ifreq; + struct strioctl strioctl; + struct ifconf *ifc; +#else + struct ifconf ifc; +#endif +#endif + + /* get a default netmask and broadcast */ + default_netmask(if_nmask, if_ipaddr); + +#ifndef NO_GET_BROADCAST + /* Create a socket to the INET kernel. */ +#if USE_SOCKRAW + if ((sock = socket(AF_INET, SOCK_RAW, PF_INET )) < 0) +#else + if ((sock = socket(AF_INET, SOCK_DGRAM, 0 )) < 0) +#endif + { + DEBUG(0,( "Unable to open socket to get broadcast address\n")); + return; + } + + /* Get a list of the configured interfaces */ +#ifdef EVEREST + /* This is part of SCO Openserver 5: The ioctls are no longer part + if the lower level STREAMS interface glue. They are now real + ioctl calls */ + + if (ioctl(sock, SIOCGIFANUM, &n_interfaces) < 0) { + DEBUG(0,( "SIOCGIFANUM: %s\n", strerror(errno))); + } else { + DEBUG(0,( "number of interfaces returned is: %d\n", n_interfaces)); + + ifc.ifc_len = sizeof(struct ifreq) * n_interfaces; + ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len); + + if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) + DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno))); + else { + ifr = ifc.ifc_req; + + for (i = 0; i < n_interfaces; ++i) { + if (if_ipaddr->s_addr == + ((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr.s_addr) { + found = True; + break; + } + } + } + } +#elif defined(USE_IFREQ) + ifc = (struct ifconf *)buff; + ifc->ifc_len = BUFSIZ - sizeof(struct ifconf); + strioctl.ic_cmd = SIOCGIFCONF; + strioctl.ic_dp = (char *)ifc; + strioctl.ic_len = sizeof(buff); + if (ioctl(sock, I_STR, &strioctl) < 0) { + DEBUG(0,( "I_STR/SIOCGIFCONF: %s\n", strerror(errno))); + } else { + ifr = (struct ifreq *)ifc->ifc_req; + + /* Loop through interfaces, looking for given IP address */ + for (i = ifc->ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { + if (if_ipaddr->s_addr == + (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) { + found = True; + break; + } + } + } +#elif defined(__FreeBSD__) || defined(NETBSD) + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { + DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno))); + } else { + ifr = ifc.ifc_req; + /* Loop through interfaces, looking for given IP address */ + i = ifc.ifc_len; + while (i > 0) { + if (if_ipaddr->s_addr == + (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) { + found = True; + break; + } + i -= ifr->ifr_addr.sa_len + IFNAMSIZ; + ifr = (struct ifreq*) ((char*) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ); + } + } +#else + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { + DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno))); + } else { + ifr = ifc.ifc_req; + + /* Loop through interfaces, looking for given IP address */ + for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { +#ifdef BSDI + if (ioctl(sock, SIOCGIFADDR, ifr) < 0) break; +#endif + if (if_ipaddr->s_addr == + (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) { + found = True; + break; + } + } + } +#endif + + if (!found) { + DEBUG(0,("No interface found for address %s\n", inet_ntoa(*if_ipaddr))); + } else { + /* Get the netmask address from the kernel */ +#ifdef USE_IFREQ + ifreq = *ifr; + + strioctl.ic_cmd = SIOCGIFNETMASK; + strioctl.ic_dp = (char *)&ifreq; + strioctl.ic_len = sizeof(struct ifreq); + if (ioctl(sock, I_STR, &strioctl) < 0) + DEBUG(0,("Failed I_STR/SIOCGIFNETMASK: %s\n", strerror(errno))); + else + *if_nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr; +#else + if (ioctl(sock, SIOCGIFNETMASK, ifr) < 0) + DEBUG(0,("SIOCGIFNETMASK failed\n")); + else + *if_nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; +#endif + + DEBUG(2,("Netmask for %s = %s\n", ifr->ifr_name, + inet_ntoa(*if_nmask))); + } + + /* Close up shop */ + (void) close(sock); + +#endif + + /* sanity check on the netmask */ + { + unsigned long nm = ntohl(if_nmask->s_addr); + if ((nm >> 24) != 0xFF) { + DEBUG(0,("Impossible netmask %s - using defaults\n",inet_ntoa(*if_nmask))); + default_netmask(if_nmask, if_ipaddr); + } + } + + /* derive the broadcast assuming a 1's broadcast, as this is what + all MS operating systems do, we have to comply even if the unix + box is setup differently */ + { + unsigned long ad = ntohl(if_ipaddr->s_addr); + unsigned long nm = ntohl(if_nmask->s_addr); + unsigned long bc = (ad & nm) | (0xffffffff & ~nm); + if_bcast->s_addr = htonl(bc); + } + + DEBUG(2,("Derived broadcast address %s\n", inet_ntoa(*if_bcast))); +} /* get_broadcast */ + + +/**************************************************************************** +put up a yes/no prompt +****************************************************************************/ +BOOL yesno(char *p) +{ + pstring ans; + printf("%s",p); + + if (!fgets(ans,sizeof(ans)-1,stdin)) + return(False); + + if (*ans == 'y' || *ans == 'Y') + return(True); + + return(False); +} + +/**************************************************************************** +read a line from a file with possible \ continuation chars. +Blanks at the start or end of a line are stripped. +The string will be allocated if s2 is NULL +****************************************************************************/ +char *fgets_slash(char *s2,int maxlen,FILE *f) +{ + char *s=s2; + int len = 0; + int c; + BOOL start_of_line = True; + + if (feof(f)) + return(NULL); + + if (!s2) + { + maxlen = MIN(maxlen,8); + s = (char *)Realloc(s,maxlen); + } + + if (!s || maxlen < 2) return(NULL); + + *s = 0; + + while (len < maxlen-1) + { + c = getc(f); + switch (c) + { + case '\r': + break; + case '\n': + while (len > 0 && s[len-1] == ' ') + { + s[--len] = 0; + } + if (len > 0 && s[len-1] == '\\') + { + s[--len] = 0; + start_of_line = True; + break; + } + return(s); + case EOF: + if (len <= 0 && !s2) + free(s); + return(len>0?s:NULL); + case ' ': + if (start_of_line) + break; + default: + start_of_line = False; + s[len++] = c; + s[len] = 0; + } + if (!s2 && len > maxlen-3) + { + maxlen *= 2; + s = (char *)Realloc(s,maxlen); + if (!s) return(NULL); + } + } + return(s); +} + + + +/**************************************************************************** +set the length of a file from a filedescriptor. +Returns 0 on success, -1 on failure. +****************************************************************************/ +int set_filelen(int fd, long len) +{ +/* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot + extend a file with ftruncate. Provide alternate implementation + for this */ + +#if FTRUNCATE_CAN_EXTEND + return ftruncate(fd, len); +#else + struct stat st; + char c = 0; + long currpos = lseek(fd, 0L, SEEK_CUR); + + if(currpos < 0) + return -1; + /* Do an fstat to see if the file is longer than + the requested size (call ftruncate), + or shorter, in which case seek to len - 1 and write 1 + byte of zero */ + if(fstat(fd, &st)<0) + return -1; + +#ifdef S_ISFIFO + if (S_ISFIFO(st.st_mode)) return 0; +#endif + + if(st.st_size == len) + return 0; + if(st.st_size > len) + return ftruncate(fd, len); + + if(lseek(fd, len-1, SEEK_SET) != len -1) + return -1; + if(write(fd, &c, 1)!=1) + return -1; + /* Seek to where we were */ + lseek(fd, currpos, SEEK_SET); + return 0; +#endif +} + + +/**************************************************************************** +return the byte checksum of some data +****************************************************************************/ +int byte_checksum(char *buf,int len) +{ + unsigned char *p = (unsigned char *)buf; + int ret = 0; + while (len--) + ret += *p++; + return(ret); +} + + + +#ifdef HPUX +/**************************************************************************** +this is a version of setbuffer() for those machines that only have setvbuf +****************************************************************************/ +void setbuffer(FILE *f,char *buf,int bufsize) +{ + setvbuf(f,buf,_IOFBF,bufsize); +} +#endif + + +/**************************************************************************** +parse out a directory name from a path name. Assumes dos style filenames. +****************************************************************************/ +char *dirname_dos(char *path,char *buf) +{ + char *p = strrchr(path,'\\'); + + if (!p) + strcpy(buf,path); + else + { + *p = 0; + strcpy(buf,path); + *p = '\\'; + } + + return(buf); +} + + +/**************************************************************************** +parse out a filename from a path name. Assumes dos style filenames. +****************************************************************************/ +static char *filename_dos(char *path,char *buf) +{ + char *p = strrchr(path,'\\'); + + if (!p) + strcpy(buf,path); + else + strcpy(buf,p+1); + + return(buf); +} + + + +/**************************************************************************** +expand a pointer to be a particular size +****************************************************************************/ +void *Realloc(void *p,int size) +{ + void *ret=NULL; + if (!p) + ret = (void *)malloc(size); + else + ret = (void *)realloc(p,size); + + if (!ret) + DEBUG(0,("Memory allocation error: failed to expand to %d bytes\n",size)); + + return(ret); +} + +/**************************************************************************** +set the time on a file +****************************************************************************/ +BOOL set_filetime(char *fname,time_t mtime) +{ + struct utimbuf times; + + if (null_mtime(mtime)) return(True); + + times.modtime = times.actime = mtime; + + if (sys_utime(fname,×)) { + DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno))); + } + + return(True); +} + + +#ifdef NOSTRDUP +/**************************************************************************** +duplicate a string +****************************************************************************/ +char *strdup(char *s) +{ + char *ret = NULL; + if (!s) return(NULL); + ret = (char *)malloc(strlen(s)+1); + if (!ret) return(NULL); + strcpy(ret,s); + return(ret); +} +#endif + + +/**************************************************************************** + Signal handler for SIGPIPE (write on a disconnected socket) +****************************************************************************/ +void Abort(void ) +{ + DEBUG(0,("Probably got SIGPIPE\nExiting\n")); + exit(2); +} + + +#ifdef REPLACE_STRLEN +/**************************************************************************** +a replacement strlen() that returns int for solaris +****************************************************************************/ +int Strlen(char *s) +{ + int ret=0; + if (!s) return(0); + while (*s++) ret++; + return(ret); +} +#endif + + +/**************************************************************************** +return a time at the start of the current month +****************************************************************************/ +time_t start_of_month(void) +{ + time_t t = time(NULL); + struct tm *t2; + + t2 = gmtime(&t); + + t2->tm_mday = 1; + t2->tm_hour = 0; + t2->tm_min = 0; + t2->tm_sec = 0; + + return(mktime(t2)); +} + + +/******************************************************************* + check for a sane unix date +********************************************************************/ +BOOL sane_unix_date(time_t unixdate) +{ + struct tm t,today; + time_t t_today = time(NULL); + + t = *(LocalTime(&unixdate,LOCAL_TO_GMT)); + today = *(LocalTime(&t_today,LOCAL_TO_GMT)); + + if (t.tm_year < 80) + return(False); + + if (t.tm_year > today.tm_year) + return(False); + + if (t.tm_year == today.tm_year && + t.tm_mon > today.tm_mon) + return(False); + + + if (t.tm_year == today.tm_year && + t.tm_mon == today.tm_mon && + t.tm_mday > (today.tm_mday+1)) + return(False); + + return(True); +} + + + +#ifdef NO_FTRUNCATE + /******************************************************************* +ftruncate for operating systems that don't have it +********************************************************************/ +int ftruncate(int f,long l) +{ + struct flock fl; + + fl.l_whence = 0; + fl.l_len = 0; + fl.l_start = l; + fl.l_type = F_WRLCK; + return fcntl(f, F_FREESP, &fl); +} +#endif + + + +/**************************************************************************** +get my own name and IP +****************************************************************************/ +BOOL get_myname(char *myname,struct in_addr *ip) +{ + struct hostent *hp; + pstring hostname; + + *hostname = 0; + + /* get my host name */ + if (gethostname(hostname, MAXHOSTNAMELEN) == -1) + { + DEBUG(0,("gethostname failed\n")); + return False; + } + + /* get host info */ + if ((hp = Get_Hostbyname(hostname)) == 0) + { + DEBUG(0,( "Get_Hostbyname: Unknown host %s.\n",hostname)); + return False; + } + + if (myname) + { + /* split off any parts after an initial . */ + char *p = strchr(hostname,'.'); + if (p) *p = 0; + + strcpy(myname,hostname); + } + + if (ip) + putip((char *)ip,(char *)hp->h_addr); + + return(True); +} + + +/**************************************************************************** +true if two IP addresses are equal +****************************************************************************/ +BOOL ip_equal(struct in_addr ip1,struct in_addr ip2) +{ + unsigned long a1,a2; + a1 = ntohl(ip1.s_addr); + a2 = ntohl(ip2.s_addr); + return(a1 == a2); +} + + +/**************************************************************************** +open a socket of the specified type, port and address for incoming data +****************************************************************************/ +int open_socket_in(int type, int port, int dlevel) +{ + struct hostent *hp; + struct sockaddr_in sock; + pstring host_name; + int res; + + /* get my host name */ +#ifdef MAXHOSTNAMELEN + if (gethostname(host_name, MAXHOSTNAMELEN) == -1) +#else + if (gethostname(host_name, sizeof(host_name)) == -1) +#endif + { DEBUG(0,("gethostname failed\n")); return -1; } + + /* get host info */ + if ((hp = Get_Hostbyname(host_name)) == 0) + { + DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",host_name)); + return -1; + } + + bzero((char *)&sock,sizeof(sock)); + memcpy((char *)&sock.sin_addr,(char *)hp->h_addr, hp->h_length); +#if defined(__FreeBSD__) || defined(NETBSD) /* XXX not the right ifdef */ + sock.sin_len = sizeof(sock); +#endif + sock.sin_port = htons( port ); + sock.sin_family = hp->h_addrtype; + sock.sin_addr.s_addr = INADDR_ANY; + res = socket(hp->h_addrtype, type, 0); + if (res == -1) + { DEBUG(0,("socket failed\n")); return -1; } + + { + int one=1; + setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one)); + } + + /* now we've got a socket - we need to bind it */ + if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) + { + if (port) { + if (port == 139 || port == 137) + DEBUG(dlevel,("bind failed on port %d (%s)\n", + port,strerror(errno))); + close(res); + + if (dlevel > 0 && port < 1000) + port = 7999; + + if (port >= 1000 && port < 9000) + return(open_socket_in(type,port+1,dlevel)); + } + + return(-1); + } + DEBUG(3,("bind succeeded on port %d\n",port)); + + return res; +} + + +/**************************************************************************** + create an outgoing socket + **************************************************************************/ +int open_socket_out(int type, struct in_addr *addr, int port ) +{ + struct sockaddr_in sock_out; + int res; + + /* create a socket to write to */ + res = socket(PF_INET, type, 0); + if (res == -1) + { DEBUG(0,("socket error\n")); return -1; } + + if (type != SOCK_STREAM) return(res); + + bzero((char *)&sock_out,sizeof(sock_out)); + putip((char *)&sock_out.sin_addr,(char *)addr); + + sock_out.sin_port = htons( port ); + sock_out.sin_family = PF_INET; + + DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port)); + + /* and connect it to the destination */ + if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))<0) { + DEBUG(0,("connect error: %s\n",strerror(errno))); + close(res); + return(-1); + } + + return res; +} + + +/**************************************************************************** +interpret a protocol description string, with a default +****************************************************************************/ +int interpret_protocol(char *str,int def) +{ + if (strequal(str,"NT1")) + return(PROTOCOL_NT1); + if (strequal(str,"LANMAN2")) + return(PROTOCOL_LANMAN2); + if (strequal(str,"LANMAN1")) + return(PROTOCOL_LANMAN1); + if (strequal(str,"CORE")) + return(PROTOCOL_CORE); + if (strequal(str,"COREPLUS")) + return(PROTOCOL_COREPLUS); + if (strequal(str,"CORE+")) + return(PROTOCOL_COREPLUS); + + DEBUG(0,("Unrecognised protocol level %s\n",str)); + + return(def); +} + +/**************************************************************************** +interpret a security level +****************************************************************************/ +int interpret_security(char *str,int def) +{ + if (strequal(str,"SERVER")) + return(SEC_SERVER); + if (strequal(str,"USER")) + return(SEC_USER); + if (strequal(str,"SHARE")) + return(SEC_SHARE); + + DEBUG(0,("Unrecognised security level %s\n",str)); + + return(def); +} + + +/**************************************************************************** +interpret an internet address or name into an IP address in 4 byte form +****************************************************************************/ +unsigned long interpret_addr(char *str) +{ + struct hostent *hp; + unsigned long res; + + if (strcmp(str,"0.0.0.0") == 0) return(0); + if (strcmp(str,"255.255.255.255") == 0) return(0xFFFFFFFF); + + /* if it's in the form of an IP address then get the lib to interpret it */ + if (isdigit(str[0])) { + res = inet_addr(str); + } else { + /* otherwise assume it's a network name of some sort and use Get_Hostbyname */ + if ((hp = Get_Hostbyname(str)) == 0) { + DEBUG(3,("Get_Hostbyname: Unknown host. %s\n",str)); + return 0; + } + putip((char *)&res,(char *)hp->h_addr); + } + + if (res == (unsigned long)-1) return(0); + + return(res); +} + +/******************************************************************* + a convenient addition to interpret_addr() + ******************************************************************/ +struct in_addr *interpret_addr2(char *str) +{ + static struct in_addr ret; + unsigned long a = interpret_addr(str); + putip((char *)&ret,(char *)&a); + return(&ret); +} + +/******************************************************************* + check if an IP is the 0.0.0.0 + ******************************************************************/ +BOOL zero_ip(struct in_addr ip) +{ + unsigned long a; + putip((char *)&a,(char *)&ip); + return(a == 0); +} + +#define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60)) + +/**************************************************************************** +interpret an 8 byte "filetime" structure to a time_t +It's originally in "100ns units since jan 1st 1601" + +It appears to be kludge-GMT (at least for file listings). This means +its the GMT you get by taking a localtime and adding the +serverzone. This is NOT the same as GMT in some cases. This routine +converts this to real GMT. +****************************************************************************/ +time_t interpret_long_date(char *p) +{ + double d; + time_t ret; + uint32 tlow,thigh; + tlow = IVAL(p,0); + thigh = IVAL(p,4); + + if (thigh == 0) return(0); + + d = ((double)thigh)*4.0*(double)(1<<30); + d += (tlow&0xFFF00000); + d *= 1.0e-7; + + /* now adjust by 369 years to make the secs since 1970 */ + d -= TIME_FIXUP_CONSTANT; + + if (d>=MAXINT) + return(0); + + ret = (time_t)(d+0.5); + + /* this takes us from kludge-GMT to real GMT */ + ret += TimeDiff(ret) - serverzone; + + return(ret); +} + + +/**************************************************************************** +put a 8 byte filetime from a time_t +This takes real GMT as input and converts to kludge-GMT +****************************************************************************/ +void put_long_date(char *p,time_t t) +{ + uint32 tlow,thigh; + double d; + + if (t==0) { + SIVAL(p,0,0); SIVAL(p,4,0); + return; + } + + /* this converts GMT to kludge-GMT */ + t -= TimeDiff(t) - serverzone; + + d = (double) (t); + + d += TIME_FIXUP_CONSTANT; + + d *= 1.0e7; + + thigh = (uint32)(d * (1.0/(4.0*(double)(1<<30)))); + tlow = (uint32)(d - ((double)thigh)*4.0*(double)(1<<30)); + + SIVAL(p,0,tlow); + SIVAL(p,4,thigh); +} + +/******************************************************************* +sub strings with useful parameters +********************************************************************/ +void standard_sub_basic(char *s) +{ + if (!strchr(s,'%')) return; + + string_sub(s,"%R",remote_proto); + string_sub(s,"%a",remote_arch); + string_sub(s,"%m",remote_machine); + string_sub(s,"%L",local_machine); + + if (!strchr(s,'%')) return; + + string_sub(s,"%v",VERSION); + string_sub(s,"%h",myhostname); + string_sub(s,"%U",sesssetup_user); + + if (!strchr(s,'%')) return; + + string_sub(s,"%I",Client_info.addr); + string_sub(s,"%M",Client_info.name); + string_sub(s,"%T",timestring()); + + if (!strchr(s,'%')) return; + + { + char pidstr[10]; + sprintf(pidstr,"%d",(int)getpid()); + string_sub(s,"%d",pidstr); + } + + if (!strchr(s,'%')) return; + + { + struct passwd *pass = Get_Pwnam(sesssetup_user,False); + if (pass) { + string_sub(s,"%G",gidtoname(pass->pw_gid)); + } + } +} + + +/******************************************************************* +write a string in unicoode format +********************************************************************/ +int PutUniCode(char *dst,char *src) +{ + int ret = 0; + while (*src) { + dst[ret++] = src[0]; + dst[ret++] = 0; + src++; + } + dst[ret++]=0; + dst[ret++]=0; + return(ret); +} + + +pstring smbrun_path = SMBRUN; + +/**************************************************************************** +run a command via system() using smbrun +****************************************************************************/ +int smbrun(char *cmd,char *outfile) +{ + int ret; + pstring syscmd; + + if (!file_exist(smbrun_path,NULL)) + { + DEBUG(0,("SMBRUN ERROR: Can't find %s. Installation problem?\n",smbrun_path)); + return(1); + } + + sprintf(syscmd,"%s \"(%s 2>&1) > %s\"", + smbrun_path,cmd, + outfile?outfile:"/dev/null"); + + DEBUG(5,("smbrun - running %s ",syscmd)); + ret = system(syscmd); + DEBUG(5,("gave %d\n",ret)); + return(ret); +} + + +/**************************************************************************** +a wrapper for gethostbyname() that tries with all lower and all upper case +if the initial name fails +****************************************************************************/ +struct hostent *Get_Hostbyname(char *name) +{ + char *name2 = strdup(name); + struct hostent *ret; + + if (!name2) + { + DEBUG(0,("Memory allocation error in Get_Hostbyname! panic\n")); + exit(0); + } + + if (!isalnum(*name2)) + { + free(name2); + return(NULL); + } + + ret = gethostbyname(name2); + if (ret != NULL) + { + free(name2); + return(ret); + } + + /* try with all lowercase */ + strlower(name2); + ret = gethostbyname(name2); + if (ret != NULL) + { + free(name2); + return(ret); + } + + /* try with all uppercase */ + strupper(name2); + ret = gethostbyname(name2); + if (ret != NULL) + { + free(name2); + return(ret); + } + + /* nothing works :-( */ + free(name2); + return(NULL); +} + + +/**************************************************************************** +check if a process exists. Does this work on all unixes? +****************************************************************************/ +BOOL process_exists(int pid) +{ +#ifdef LINUX + fstring s; + sprintf(s,"/proc/%d",pid); + return(directory_exist(s,NULL)); +#else + { + static BOOL tested=False; + static BOOL ok=False; + fstring s; + if (!tested) { + tested = True; + sprintf(s,"/proc/%05d",getpid()); + ok = file_exist(s,NULL); + } + if (ok) { + sprintf(s,"/proc/%05d",pid); + return(file_exist(s,NULL)); + } + } + + /* a best guess for non root access */ + if (geteuid() != 0) return(True); + + /* otherwise use kill */ + return(pid == getpid() || kill(pid,0) == 0); +#endif +} + + +/******************************************************************* +turn a uid into a user name +********************************************************************/ +char *uidtoname(int uid) +{ + static char name[40]; + struct passwd *pass = getpwuid(uid); + if (pass) return(pass->pw_name); + sprintf(name,"%d",uid); + return(name); +} + +/******************************************************************* +turn a gid into a group name +********************************************************************/ +char *gidtoname(int gid) +{ + static char name[40]; + struct group *grp = getgrgid(gid); + if (grp) return(grp->gr_name); + sprintf(name,"%d",gid); + return(name); +} + +/******************************************************************* +block sigs +********************************************************************/ +void BlockSignals(BOOL block) +{ +#ifdef USE_SIGBLOCK + int block_mask = (sigmask(SIGTERM)|sigmask(SIGQUIT)|sigmask(SIGSEGV) + |sigmask(SIGCHLD)|sigmask(SIGQUIT)|sigmask(SIGBUS)| + sigmask(SIGINT)); + if (block) + sigblock(block_mask); + else + sigunblock(block_mask); +#endif +} + +#if AJT +/******************************************************************* +my own panic function - not suitable for general use +********************************************************************/ +void ajt_panic(void) +{ + pstring cmd = "/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT &"; + smbrun(cmd,NULL); +} +#endif + +#ifdef USE_DIRECT +#define DIRECT direct +#else +#define DIRECT dirent +#endif + +/******************************************************************* +a readdir wrapper which just returns the file name +also return the inode number if requested +********************************************************************/ +char *readdirname(void *p) +{ + struct DIRECT *ptr; + char *dname; + + if (!p) return(NULL); + + ptr = (struct DIRECT *)readdir(p); + if (!ptr) return(NULL); + + dname = ptr->d_name; + +#ifdef KANJI + { + static pstring buf; + strcpy(buf, dname); + unix_to_dos(buf, True); + dname = buf; + } +#endif + +#ifdef NEXT2 + if (telldir(p) < 0) return(NULL); +#endif + +#ifdef SUNOS5 + /* this handles a broken compiler setup, causing a mixture + of BSD and SYSV headers and libraries */ + { + static BOOL broken_readdir = False; + if (!broken_readdir && !(*(dname)) && strequal("..",dname-2)) + { + DEBUG(0,("Your readdir() is broken. You have somehow mixed SYSV and BSD headers and libraries\n")); + broken_readdir = True; + } + if (broken_readdir) + return(dname-2); + } +#endif + + return(dname); +} + + + +#if (defined(SecureWare) && defined(SCO)) +/* This is needed due to needing the nap() function but we don't want + to include the Xenix libraries since that will break other things... + BTW: system call # 0x0c28 is the same as calling nap() */ +long nap(long milliseconds) { + return syscall(0x0c28, milliseconds); +} +#endif + +#ifdef NO_INITGROUPS +#include <sys/types.h> +#include <limits.h> +#include <grp.h> + +#ifndef NULL +#define NULL (void *)0 +#endif + +/**************************************************************************** + some systems don't have an initgroups call +****************************************************************************/ +int initgroups(char *name,gid_t id) +{ +#ifdef NO_SETGROUPS + /* yikes! no SETGROUPS or INITGROUPS? how can this work? */ + return(0); +#else + gid_t grouplst[NGROUPS_MAX]; + int i,j; + struct group *g; + char *gr; + + grouplst[0] = id; + i = 1; + while (i < NGROUPS_MAX && + ((g = (struct group *)getgrent()) != (struct group *)NULL)) + { + if (g->gr_gid == id) + continue; + j = 0; + gr = g->gr_mem[0]; + while (gr && (*gr != (char)NULL)) { + if (strcmp(name,gr) == 0) { + grouplst[i] = g->gr_gid; + i++; + gr = (char *)NULL; + break; + } + gr = g->gr_mem[++j]; + } + } + endgrent(); + return(setgroups(i,grouplst)); +#endif +} +#endif + + +#if WRAP_MALLOC + +/* undo the wrapping temporarily */ +#undef malloc +#undef realloc +#undef free + +/**************************************************************************** +wrapper for malloc() to catch memory errors +****************************************************************************/ +void *malloc_wrapped(int size,char *file,int line) +{ +#ifdef xx_old_malloc + void *res = xx_old_malloc(size); +#else + void *res = malloc(size); +#endif + DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n", + file,line, + size,(unsigned int)res)); + return(res); +} + +/**************************************************************************** +wrapper for realloc() to catch memory errors +****************************************************************************/ +void *realloc_wrapped(void *ptr,int size,char *file,int line) +{ +#ifdef xx_old_realloc + void *res = xx_old_realloc(ptr,size); +#else + void *res = realloc(ptr,size); +#endif + DEBUG(3,("Realloc\n")); + DEBUG(3,("free called from %s(%d) with ptr=0x%X\n", + file,line, + (unsigned int)ptr)); + DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n", + file,line, + size,(unsigned int)res)); + return(res); +} + +/**************************************************************************** +wrapper for free() to catch memory errors +****************************************************************************/ +void free_wrapped(void *ptr,char *file,int line) +{ +#ifdef xx_old_free + xx_old_free(ptr); +#else + free(ptr); +#endif + DEBUG(3,("free called from %s(%d) with ptr=0x%X\n", + file,line,(unsigned int)ptr)); + return; +} + +/* and re-do the define for spots lower in this file */ +#define malloc(size) malloc_wrapped(size,__FILE__,__LINE__) +#define realloc(ptr,size) realloc_wrapped(ptr,size,__FILE__,__LINE__) +#define free(ptr) free_wrapped(ptr,__FILE__,__LINE__) + +#endif + +#ifdef REPLACE_STRSTR +/**************************************************************************** +Mips version of strstr doesn't seem to work correctly. +There is a #define in includes.h to redirect calls to this function. +****************************************************************************/ +char *Strstr(char *s, char *p) +{ + int len = strlen(p); + + while ( *s != '\0' ) { + if ( strncmp(s, p, len) == 0 ) + return s; + s++; + } + + return NULL; +} +#endif /* REPLACE_STRSTR */ + + +#ifdef REPLACE_MKTIME +/******************************************************************* +a mktime() replacement for those who don't have it - contributed by +C.A. Lademann <cal@zls.com> +********************************************************************/ +#define MINUTE 60 +#define HOUR 60*MINUTE +#define DAY 24*HOUR +#define YEAR 365*DAY +time_t Mktime(struct tm *t) +{ + struct tm *u; + time_t epoch = 0; + int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + y, m, i; + + if(t->tm_year < 70) + return((time_t)-1); + + epoch = (t->tm_year - 70) * YEAR + + (t->tm_year / 4 - 70 / 4 - t->tm_year / 100) * DAY; + + y = t->tm_year; + m = 0; + + for(i = 0; i < t->tm_mon; i++) { + epoch += mon [m] * DAY; + if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) + epoch += DAY; + + if(++m > 11) { + m = 0; + y++; + } + } + + epoch += (t->tm_mday - 1) * DAY; + epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec; + + if((u = localtime(&epoch)) != NULL) { + t->tm_sec = u->tm_sec; + t->tm_min = u->tm_min; + t->tm_hour = u->tm_hour; + t->tm_mday = u->tm_mday; + t->tm_mon = u->tm_mon; + t->tm_year = u->tm_year; + t->tm_wday = u->tm_wday; + t->tm_yday = u->tm_yday; + t->tm_isdst = u->tm_isdst; +#ifndef NO_TM_NAME + memcpy(t->tm_name, u->tm_name, LTZNMAX); +#endif + } + + return(epoch); +} +#endif /* REPLACE_MKTIME */ + + + +#ifdef REPLACE_RENAME +/* Rename a file. (from libiberty in GNU binutils) */ +int +rename (zfrom, zto) + const char *zfrom; + const char *zto; +{ + if (link (zfrom, zto) < 0) + { + if (errno != EEXIST) + return -1; + if (unlink (zto) < 0 + || link (zfrom, zto) < 0) + return -1; + } + return unlink (zfrom); +} +#endif + + +#ifdef REPLACE_INNETGR +/* + * Search for a match in a netgroup. This replaces it on broken systems. + */ +int InNetGr(group, host, user, dom) + char *group, *host, *user, *dom; +{ + char *hst, *usr, *dm; + + setnetgrent(group); + while (getnetgrent(&hst, &usr, &dm)) + if (((host == 0) || (hst == 0) || !strcmp(host, hst)) && + ((user == 0) || (usr == 0) || !strcmp(user, usr)) && + ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) { + endnetgrent(); + return (1); + } + endnetgrent(); + return (0); +} +#endif + + +#if WRAP_MEMCPY +#undef memcpy +/******************************************************************* +a wrapper around memcpy for diagnostic purposes +********************************************************************/ +void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line) +{ + if (l>64 && (((int)d)%4) != (((int)s)%4)) + DEBUG(4,("Misaligned memcpy(0x%X,0x%X,%d) at %s(%d)\n",d,s,l,fname,line)); +#ifdef xx_old_memcpy + return(xx_old_memcpy(d,s,l)); +#else + return(memcpy(d,s,l)); +#endif +} +#define memcpy(d,s,l) memcpy_wrapped(d,s,l,__FILE__,__LINE__) +#endif + + + |