Unix SMB/Netbios implementation.
Version 1.9.
Samba utility functions
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
pstring user_socket_options="";
pstring sesssetup_user="";
pstring myname = "";
+fstring myworkgroup = "";
+char **my_netbios_names;
int smb_read_error = 0;
-static char *filename_dos(char *path,char *buf);
-
static BOOL stdout_logging = False;
+static char *filename_dos(char *path,char *buf);
/*******************************************************************
get ready for syslog stuff
BOOL directory_exist(char *dname,struct stat *st)
{
struct stat st2;
+ BOOL ret;
+
if (!st) st = &st2;
if (sys_stat(dname,st) != 0)
return(False);
- return(S_ISDIR(st->st_mode));
+ ret = S_ISDIR(st->st_mode);
+ if(!ret)
+ errno = ENOTDIR;
+ return ret;
}
/*******************************************************************
int StrCaseCmp(const char *s, const char *t)
{
/* compare until we run out of string, either t or s, or find a difference */
- while (*s && *t && tolower(*s) == tolower(*t))
+ /* We *must* use toupper rather than tolower here due to the
+ asynchronous upper to lower mapping.
+ */
+#ifdef KANJI
+ int diff;
+ for (;;)
+ {
+ if (!*s || !*t)
+ return toupper (*s) - toupper (*t);
+ else if (is_sj_alph (*s) && is_sj_alph (*t))
+ {
+ diff = sj_toupper2 (*(s+1)) - sj_toupper2 (*(t+1));
+ if (diff)
+ return diff;
+ s += 2;
+ t += 2;
+ }
+ else if (is_shift_jis (*s) && is_shift_jis (*t))
+ {
+ diff = ((int) (unsigned char) *s) - ((int) (unsigned char) *t);
+ if (diff)
+ return diff;
+ diff = ((int) (unsigned char) *(s+1)) - ((int) (unsigned char) *(t+1));
+ if (diff)
+ return diff;
+ s += 2;
+ t += 2;
+ }
+ else if (is_shift_jis (*s))
+ return 1;
+ else if (is_shift_jis (*t))
+ return -1;
+ else
+ {
+ diff = toupper (*s) - toupper (*t);
+ if (diff)
+ return diff;
+ s++;
+ t++;
+ }
+ }
+#else /* KANJI */
+ while (*s && *t && toupper(*s) == toupper(*t))
{
s++; t++;
}
- return(tolower(*s) - tolower(*t));
+ return(toupper(*s) - toupper(*t));
+#endif /* KANJI */
}
/*******************************************************************
int StrnCaseCmp(const char *s, const char *t, int n)
{
/* compare until we run out of string, either t or s, or chars */
- while (n-- && *s && *t && tolower(*s) == tolower(*t))
+ /* We *must* use toupper rather than tolower here due to the
+ asynchronous upper to lower mapping.
+ */
+#ifdef KANJI
+ int diff;
+ for (;n > 0;)
+ {
+ if (!*s || !*t)
+ return toupper (*s) - toupper (*t);
+ else if (is_sj_alph (*s) && is_sj_alph (*t))
+ {
+ diff = sj_toupper2 (*(s+1)) - sj_toupper2 (*(t+1));
+ if (diff)
+ return diff;
+ s += 2;
+ t += 2;
+ n -= 2;
+ }
+ else if (is_shift_jis (*s) && is_shift_jis (*t))
+ {
+ diff = ((int) (unsigned char) *s) - ((int) (unsigned char) *t);
+ if (diff)
+ return diff;
+ diff = ((int) (unsigned char) *(s+1)) - ((int) (unsigned char) *(t+1));
+ if (diff)
+ return diff;
+ s += 2;
+ t += 2;
+ n -= 2;
+ }
+ else if (is_shift_jis (*s))
+ return 1;
+ else if (is_shift_jis (*t))
+ return -1;
+ else
+ {
+ diff = toupper (*s) - toupper (*t);
+ if (diff)
+ return diff;
+ s++;
+ t++;
+ n--;
+ }
+ }
+ return 0;
+#else /* KANJI */
+ while (n-- && *s && *t && toupper(*s) == toupper(*t))
{
s++; t++;
}
/* not run out of chars - strings are different lengths */
- if (n) return(tolower(*s) - tolower(*t));
+ if (n) return(toupper(*s) - toupper(*t));
/* identical up to where we run out of chars, and strings are same length */
return(0);
+#endif /* KANJI */
}
/*******************************************************************
compare 2 strings
********************************************************************/
-BOOL strequal(char *s1,char *s2)
+BOOL strequal(const char *s1, const char *s2)
{
if (s1 == s2) return(True);
if (!s1 || !s2) return(False);
/*******************************************************************
compare 2 strings up to and including the nth char.
******************************************************************/
-BOOL strnequal(char *s1,char *s2,int n)
+BOOL strnequal(const char *s1,const char *s2,int n)
{
if (s1 == s2) return(True);
if (!s1 || !s2 || !n) return(False);
{
#ifdef KANJI
if (is_shift_jis (*s)) {
+ if (is_sj_upper (s[0], s[1])) {
+ s[1] = sj_tolower2 (s[1]);
+ }
s += 2;
} else if (is_kana (*s)) {
s++;
*s = tolower(*s);
s++;
}
-#else
+#else /* KANJI */
if (isupper(*s))
*s = tolower(*s);
s++;
{
#ifdef KANJI
if (is_shift_jis (*s)) {
+ if (is_sj_lower (s[0], s[1])) {
+ s[1] = sj_toupper2 (s[1]);
+ }
s += 2;
} else if (is_kana (*s)) {
s++;
*s = toupper(*s);
s++;
}
-#else
+#else /* KANJI */
if (islower(*s))
*s = toupper(*s);
s++;
-#endif
+#endif /* KANJI */
}
}
*s = newc;
s++;
}
-#else
+#else /* KANJI */
if (oldc == *s)
*s = newc;
s++;
void show_msg(char *buf)
{
int i;
+ int j;
int bcc=0;
if (DEBUGLEVEL < 5)
return;
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"));
+ for (i = 0; i < MIN(bcc, 256); i += 16)
+ {
+ for (j = 0; j < 16 && i+j < MIN(bcc,256); j++)
+ {
+
+ DEBUG(10,("%2X ",CVAL(smb_buf(buf),i+j)));
+ if (j == 7) DEBUG(10, (" "));
+
+ }
+ DEBUG(10,(" "));
+
+ for (j = 0; j < 16 && i+j < MIN(bcc,256); j++)
+ {
+ unsigned char c = CVAL(smb_buf(buf),i+j);
+ if (c < 32 || c > 128) c = '.';
+ DEBUG(10,("%c",c));
+
+ if (j == 7) DEBUG(10, (" "));
+ }
+
+ DEBUG(10,("\n"));
+ }
}
/*******************************************************************
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)
*s = 0;
if (!use_getwd_cache)
- return(Dumb_GetWd(str));
+ return(sys_getwd(str));
/* init the cache */
if (!getwd_cache_init)
if (stat(".",&st) == -1)
{
DEBUG(0,("Very strange, couldn't stat \".\"\n"));
- return(Dumb_GetWd(str));
+ return(sys_getwd(str));
}
The very slow getcwd, which spawns a process on some systems, or the
not quite so bad getwd. */
- if (!Dumb_GetWd(s))
+ if (!sys_getwd(s))
{
DEBUG(0,("Getwd failed, errno %d\n",errno));
return (NULL);
if (isupper(*s)) return(True);
s++;
}
-#else
+#else /* KANJI */
if (isupper(*s)) return(True);
s++;
#endif /* KANJI */
{
#ifdef KANJI
if (is_shift_jis (*s)) {
+ if (is_sj_upper (s[0], s[1])) return(True);
+ if (is_sj_lower (s[0], s[1])) return (True);
s += 2;
} else if (is_kana (*s)) {
s++;
if (islower(*s)) return(True);
s++;
}
-#else
+#else /* KANJI */
if (islower(*s)) return(True);
s++;
#endif /* KANJI */
int count_chars(char *s,char c)
{
int count=0;
+#ifdef KANJI
+ while (*s)
+ {
+ if (is_shift_jis (*s))
+ s += 2;
+ else
+ {
+ if (*s == c)
+ count++;
+ s++;
+ }
+ }
+#else /* KANJI */
while (*s)
{
if (*s == c)
count++;
s++;
}
+#endif /* KANJI */
return(count);
}
if SYSV use O_NDELAY
if BSD use FNDELAY
****************************************************************************/
-int set_blocking(int fd, int set)
+int set_blocking(int fd, BOOL set)
{
int val;
#ifdef O_NONBLOCK
/* detach from the terminal */
#ifdef USE_SETSID
setsid();
-#else
+#else /* USE_SETSID */
#ifdef TIOCNOTTY
{
int i = open("/dev/tty", O_RDWR);
close(i);
}
}
-#endif
-#endif
-#endif
+#endif /* TIOCNOTTY */
+#endif /* USE_SETSID */
+ /* Close fd's 0,1,2. Needed if started by rsh */
+ close_low_fds();
+#endif /* NO_FORK_DEBUG */
}
sock_out.sin_family = PF_INET;
/* set it non-blocking */
- set_blocking(res,0);
+ set_blocking(res,False);
DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port));
connect_again:
ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out));
- if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY) && loops--) {
+ /* Some systems return EAGAIN when they mean EINPROGRESS */
+ if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+ errno == EAGAIN) && loops--) {
msleep(connect_loop);
goto connect_again;
}
- if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY)) {
+ if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+ errno == EAGAIN)) {
DEBUG(1,("timeout connecting to %s:%d\n",inet_ntoa(*addr),port));
close(res);
return -1;
}
/* set it blocking again */
- set_blocking(res,1);
+ set_blocking(res,True);
return res;
}
}
-/* matchname - determine if host name matches IP address */
+/*******************************************************************
+ matchname - determine if host name matches IP address
+ ******************************************************************/
static BOOL matchname(char *remotehost,struct in_addr addr)
{
struct hostent *hp;
return False;
}
-/* return the DNS name of the client */
+/*******************************************************************
+ Reset the 'done' variables so after a client process is created
+ from a fork call these calls will be re-done. This should be
+ expanded if more variables need reseting.
+ ******************************************************************/
+
+static BOOL global_client_name_done = False;
+static BOOL global_client_addr_done = False;
+
+void reset_globals_after_fork()
+{
+ global_client_name_done = False;
+ global_client_addr_done = False;
+}
+
+/*******************************************************************
+ return the DNS name of the client
+ ******************************************************************/
char *client_name(void)
{
extern int Client;
struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
int length = sizeof(sa);
static pstring name_buf;
- static BOOL done = False;
struct hostent *hp;
- if (done)
+ if (global_client_name_done)
return name_buf;
- done = True;
strcpy(name_buf,"UNKNOWN");
if (getpeername(Client, &sa, &length) < 0) {
DEBUG(0,("getpeername failed\n"));
- done = False;
return name_buf;
}
AF_INET)) == 0) {
DEBUG(1,("Gethostbyaddr failed for %s\n",client_addr()));
StrnCpy(name_buf,client_addr(),sizeof(name_buf) - 1);
- done = False;
} else {
StrnCpy(name_buf,(char *)hp->h_name,sizeof(name_buf) - 1);
if (!matchname(name_buf, sockin->sin_addr)) {
strcpy(name_buf,"UNKNOWN");
}
}
+ global_client_name_done = True;
return name_buf;
}
-/* return the IP addr of the client as a string */
+/*******************************************************************
+ return the IP addr of the client as a string
+ ******************************************************************/
char *client_addr(void)
{
extern int Client;
struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
int length = sizeof(sa);
static fstring addr_buf;
- static BOOL done = False;
- if (done)
+ if (global_client_addr_done)
return addr_buf;
- done = True;
strcpy(addr_buf,"0.0.0.0");
if (getpeername(Client, &sa, &length) < 0) {
strcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
+ global_client_addr_done = True;
return addr_buf;
}
/*******************************************************************
sub strings with useful parameters
+Rewritten by Stefaan A Eeckels <Stefaan.Eeckels@ecc.lu> and
+Paul Rippin <pr3245@nopc.eurostat.cec.be>
********************************************************************/
-void standard_sub_basic(char *s)
+void standard_sub_basic(char *string)
{
- 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_addr());
- if (strstr(s,"%M"))
- string_sub(s,"%M",client_name());
- string_sub(s,"%T",timestring());
-
- if (!strchr(s,'%')) return;
+ char *s, *p;
+ char pidstr[10];
+ struct passwd *pass;
+ for (s = string ; (p = strchr(s,'%')) != NULL ; s = p )
{
- 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));
+ switch (*(p+1))
+ {
+ case 'G' : if ((pass = Get_Pwnam(sesssetup_user,False))!=NULL)
+ string_sub(p,"%G",gidtoname(pass->pw_gid));
+ else
+ p += 2;
+ break;
+ case 'I' : string_sub(p,"%I",client_addr()); break;
+ case 'L' : string_sub(p,"%L",local_machine); break;
+ case 'M' : string_sub(p,"%M",client_name()); break;
+ case 'R' : string_sub(p,"%R",remote_proto); break;
+ case 'T' : string_sub(p,"%T",timestring()); break;
+ case 'U' : string_sub(p,"%U",sesssetup_user); break;
+ case 'a' : string_sub(p,"%a",remote_arch); break;
+ case 'd' : sprintf(pidstr,"%d",(int)getpid());
+ string_sub(p,"%d",pidstr);
+ break;
+ case 'h' : string_sub(p,"%h",myhostname); break;
+ case 'm' : string_sub(p,"%m",remote_machine); break;
+ case 'v' : string_sub(p,"%v",VERSION); break;
+ case '\0' : p++; break; /* don't run off end if last character is % */
+ default : p+=2; break;
}
}
+ return;
}
-
/*******************************************************************
are two IPs on the same subnet?
********************************************************************/
return(NULL);
}
- ret = gethostbyname(name2);
+ ret = sys_gethostbyname(name2);
if (ret != NULL)
{
free(name2);
/* try with all lowercase */
strlower(name2);
- ret = gethostbyname(name2);
+ ret = sys_gethostbyname(name2);
if (ret != NULL)
{
free(name2);
/* try with all uppercase */
strupper(name2);
- ret = gethostbyname(name2);
+ ret = sys_gethostbyname(name2);
if (ret != NULL)
{
free(name2);
fstring s;
if (!tested) {
tested = True;
- sprintf(s,"/proc/%05d",getpid());
+ sprintf(s,"/proc/%05d",(int)getpid());
ok = file_exist(s,NULL);
}
if (ok) {
dname = ptr->d_name;
- {
- static pstring buf;
- strcpy(buf, dname);
- unix_to_dos(buf, True);
- dname = buf;
- }
-
#ifdef NEXT2
if (telldir(p) < 0) return(NULL);
#endif
broken_readdir = True;
}
if (broken_readdir)
- return(dname-2);
+ dname = dname - 2;
}
#endif
+ {
+ static pstring buf;
+ strcpy(buf, dname);
+ unix_to_dos(buf, True);
+ dname = buf;
+ }
+
return(dname);
}
+/*
+ * Utility function used to decide if the last component
+ * of a path matches a (possibly wildcarded) entry in a namelist.
+ */
-BOOL is_vetoed_name(char *name)
+BOOL is_in_path(char *name, name_compare_entry *namelist)
{
- char *namelist = lp_veto_files();
- char *nameptr = namelist;
- char *name_end;
+ pstring last_component;
+ char *p;
- /* if we have no list it's obviously not vetoed */
- if((nameptr == NULL ) || (*nameptr == '\0'))
- return 0;
+ DEBUG(5, ("is_in_path: %s\n", name));
- /* if the name doesn't exist in the list, it's obviously ok too */
- if(strstr(namelist,name) == NULL )
- return 0;
+ /* if we have no list it's obviously not in the path */
+ if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL)))
+ {
+ DEBUG(5,("is_in_path: no name list.\n"));
+ return False;
+ }
+
+ /* Get the last component of the unix name. */
+ p = strrchr(name, '/');
+ strncpy(last_component, p ? p : name, sizeof(last_component)-1);
+ last_component[sizeof(last_component)-1] = '\0';
- /* now, we need to find the names one by one and check them
- they can contain spaces and all sorts of stuff so we
- separate them with of all things '/' which can never be in a filename
- I could use "" but then I have to break them all out
- maybe such a routine exists somewhere?
- */
- while(*nameptr)
+ for(; namelist->name != NULL; namelist++)
+ {
+ if(namelist->is_wild)
{
- if ( *nameptr == '/' )
- {
- nameptr++;
- continue;
- }
- if(name_end = strchr(nameptr,'/'))
+ /* look for a wildcard match. */
+ if (mask_match(last_component, namelist->name, case_sensitive, False))
+ {
+ DEBUG(5,("is_in_path: mask match succeeded\n"));
+ return True;
+ }
+ }
+ else
+ {
+ if((case_sensitive && (strcmp(last_component, namelist->name) == 0))||
+ (!case_sensitive && (StrCaseCmp(last_component, namelist->name) == 0)))
{
- *name_end = 0;
+ DEBUG(5,("is_in_path: match succeeded\n"));
+ return True;
}
- /* a match! it's veto'd */
- if(strcmp(name,nameptr) == 0)
- return 1;
- if(name_end == NULL)
- return 0;
- /* next segment please */
- nameptr = name_end + 1;
}
- return 0;
+ }
+ DEBUG(5,("is_in_path: match not found\n"));
+
+ return False;
}
-BOOL is_vetoed_path(char *name)
+/*
+ * Strip a '/' separated list into an array of
+ * name_compare_enties structures suitable for
+ * passing to is_in_path(). We do this for
+ * speed so we can pre-parse all the names in the list
+ * and don't do it for each call to is_in_path().
+ * namelist is modified here and is assumed to be
+ * a copy owned by the caller.
+ * We also check if the entry contains a wildcard to
+ * remove a potentially expensive call to mask_match
+ * if possible.
+ */
+
+void set_namearray(name_compare_entry **ppname_array, char *namelist)
{
- char *namelist = lp_veto_files();
- char *nameptr = namelist;
- char *sub;
char *name_end;
- int len;
+ char *nameptr = namelist;
+ int num_entries = 0;
+ int i;
- /* if we have no list it's obviously not vetoed */
- if((nameptr == NULL ) || (*nameptr == '\0'))
- return 0;
+ (*ppname_array) = NULL;
+ if((nameptr == NULL ) || ((nameptr != NULL) && (*nameptr == '\0')))
+ return;
- /* now, we need to find the names one by one and check them
- they can contain spaces and all sorts of stuff so we
- separate them with of all things '/' which can never be in a filename
- I could use "" but then I have to break them all out
- maybe such a routine exists somewhere?
- */
- while(*nameptr)
+ /* We need to make two passes over the string. The
+ first to count the number of elements, the second
+ to split it.
+ */
+ while (*nameptr )
{
if ( *nameptr == '/' )
- {
+ {
+ /* cope with multiple (useless) /s) */
nameptr++;
continue;
- }
- if(name_end = strchr(nameptr,'/'))
- {
+ }
+ /* find the next / */
+ name_end = strchr(nameptr, '/');
+
+ /* oops - the last check for a / didn't find one. */
+ if (name_end == NULL)
+ break;
+
+ /* next segment please */
+ nameptr = name_end + 1;
+ num_entries++;
+ }
+
+ if(num_entries == 0)
+ return;
+
+ if(( (*ppname_array) = (name_compare_entry *)malloc(
+ (num_entries + 1) * sizeof(name_compare_entry))) == NULL)
+ {
+ DEBUG(0,("set_namearray: malloc fail\n"));
+ return;
+ }
+
+ /* Now copy out the names */
+ nameptr = namelist;
+ i = 0;
+ while(*nameptr)
+ {
+ if ( *nameptr == '/' )
+ {
+ /* cope with multiple (useless) /s) */
+ nameptr++;
+ continue;
+ }
+ /* find the next / */
+ if ((name_end = strchr(nameptr, '/')) != NULL)
+ {
*name_end = 0;
- }
+ }
+
+ /* oops - the last check for a / didn't find one. */
+ if (name_end == NULL)
+ break;
+
+ (*ppname_array)[i].is_wild = ((strchr( nameptr, '?')!=NULL) ||
+ (strchr( nameptr, '*')!=NULL));
+ if(((*ppname_array)[i].name = strdup(nameptr)) == NULL)
+ {
+ DEBUG(0,("set_namearray: malloc fail (1)\n"));
+ return;
+ }
- len = strlen(nameptr);
- sub = name;
- /* If the name doesn't exist in the path, try the next name.. */
- while( sub && ((sub = strstr(sub,nameptr)) != NULL))
- {
- /* Is it a whole component? */
- if(((sub == name) || (sub[-1] == '/'))
- && ((sub[len] == '\0') || (sub[len] == '/')))
- {
- return 1;
- }
- /* skip to the next component of the path */
- sub =strchr(sub,'/');
- }
- if(name_end == NULL)
- return 0;
/* next segment please */
nameptr = name_end + 1;
+ i++;
}
- return 0;
+
+ (*ppname_array)[i].name = NULL;
+
+ return;
+}
+
+/****************************************************************************
+routine to free a namearray.
+****************************************************************************/
+
+void free_namearray(name_compare_entry *name_array)
+{
+ if(name_array == 0)
+ return;
+
+ if(name_array->name != NULL)
+ free(name_array->name);
+
+ free((char *)name_array);
}
/****************************************************************************
close(fd);
}
+/*******************************************************************
+is the name specified one of my netbios names
+returns true is it is equal, false otherwise
+********************************************************************/
+BOOL is_myname(const char *s)
+{
+ int n;
+ BOOL ret = False;
+ for (n=0; my_netbios_names[n]; n++) {
+ if (strequal(my_netbios_names[n], s))
+ ret=True;
+ }
+ DEBUG(8, ("is_myname(\"%s\") returns %d\n", s, ret));
+ return(ret);
+}