r1085: Now it's had some proper user testing, merge in the deferred open fix. I'm
[tprouty/samba.git] / source / lib / util.c
index 8bc36a4fb45b17100d80029c3ac67cdf30f07212..9d7a2648c5b603874c4128d9c044a5dc9a4bb82f 100644 (file)
@@ -4,7 +4,7 @@
    Copyright (C) Andrew Tridgell 1992-1998
    Copyright (C) Jeremy Allison 2001-2002
    Copyright (C) Simo Sorce 2001
-   Copyright (C) Anthony Liguori 2003
+   Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
    
    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
@@ -63,19 +63,6 @@ int chain_size = 0;
 
 int trans_num = 0;
 
-/*
-   case handling on filenames 
-*/
-int case_default = CASE_LOWER;
-
-/* 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;
-
 static enum remote_arch_types ra_type = RA_UNKNOWN;
 pstring user_socket_options=DEFAULT_SOCKET_OPTIONS;   
 
@@ -99,7 +86,7 @@ BOOL set_global_myname(const char *myname)
        smb_myname = strdup(myname);
        if (!smb_myname)
                return False;
-       strupper(smb_myname);
+       strupper_m(smb_myname);
        return True;
 }
 
@@ -118,7 +105,7 @@ BOOL set_global_myworkgroup(const char *myworkgroup)
        smb_myworkgroup = strdup(myworkgroup);
        if (!smb_myworkgroup)
                return False;
-       strupper(smb_myworkgroup);
+       strupper_m(smb_myworkgroup);
        return True;
 }
 
@@ -137,7 +124,7 @@ BOOL set_global_scope(const char *scope)
        smb_scope = strdup(scope);
        if (!smb_scope)
                return False;
-       strupper(smb_scope);
+       strupper_m(smb_scope);
        return True;
 }
 
@@ -184,7 +171,7 @@ static BOOL set_my_netbios_names(const char *name, int i)
        smb_my_netbios_names[i] = strdup(name);
        if (!smb_my_netbios_names[i])
                return False;
-       strupper(smb_my_netbios_names[i]);
+       strupper_m(smb_my_netbios_names[i]);
        return True;
 }
 
@@ -261,11 +248,11 @@ BOOL init_names(void)
        }                       
 
        fstrcpy( local_machine, global_myname() );
-       trim_string( local_machine, " ", " " );
+       trim_char( local_machine, ' ', ' ' );
        p = strchr( local_machine, ' ' );
        if (p)
                *p = 0;
-       strlower( local_machine );
+       strlower_m( local_machine );
 
        DEBUG( 5, ("Netbios name list:-\n") );
        for( n=0; my_netbios_names(n); n++ )
@@ -311,7 +298,7 @@ BOOL in_group(gid_t group, gid_t current_gid, int ngroups, const gid_t *groups)
 
 static const char *Atoic(const char *p, int *n, const char *c)
 {
-       if (!isdigit((const int)*p)) {
+       if (!isdigit((int)*p)) {
                DEBUG(5, ("Atoic: malformed number\n"));
                return NULL;
        }
@@ -551,7 +538,7 @@ void dos_clean_name(char *s)
        /* remove any double slashes */
        all_string_sub(s, "\\\\", "\\", 0);
 
-       while ((p = strstr(s,"\\..\\")) != NULL) {
+       while ((p = strstr_m(s,"\\..\\")) != NULL) {
                pstring s1;
 
                *p = 0;
@@ -589,7 +576,7 @@ void unix_clean_name(char *s)
                        pstrcpy(s,"./");
        }
 
-       while ((p = strstr(s,"/../")) != NULL) {
+       while ((p = strstr_m(s,"/../")) != NULL) {
                pstring s1;
 
                *p = 0;
@@ -605,73 +592,11 @@ void unix_clean_name(char *s)
        trim_string(s,NULL,"/..");
 }
 
-/*******************************************************************
- Convert '\' to '/'.
- Reduce a file name, removing or reducing /../ , /./ , // elements.
- Remove also any trailing . and /
- Return a new allocated string.
-********************************************************************/
-
-smb_ucs2_t *unix_clean_path(const smb_ucs2_t *s)
-{
-       smb_ucs2_t *ns;
-       smb_ucs2_t *p, *r, *t;
-
-       DEBUG(3, ("unix_clean_path\n")); /*  [%unicode]\n")); */
-       if(!s)
-               return NULL;
-
-       /* convert '\' to '/' */
-       ns = strdup_w(s);
-       if (!ns)
-               return NULL;
-       unix_format_w(ns);
-
-       /* remove all double slashes */
-       p = ns;
-       ns = all_string_sub_wa(p, "//", "/");
-       SAFE_FREE(p);
-       if (!ns)
-               return NULL;
-
-       /* remove any /./ */
-       p = ns;
-       ns = all_string_sub_wa(p, "/./", "/");
-       SAFE_FREE(p);
-       if (!ns)
-               return NULL;
-
-       /* reduce any /../ */
-       t = ns;
-       while (*t && (r = strstr_wa(t, "/.."))) {
-               t = &(r[3]);
-               if (*t == UCS2_CHAR('/') || *t == 0) {
-                       *r = 0;
-                       p = strrchr_w(ns, UCS2_CHAR('/'));
-                       if (!p)
-                               p = ns;
-                       if (*t == 0)
-                               *p = 0;
-                       else
-                               memmove(p, t, (strlen_w(t) + 1) * sizeof(smb_ucs2_t));
-                       t = p;
-               }
-       }
-
-       /* remove any leading ./ trailing /. */
-       trim_string_wa(ns, "./", "/.");
-
-       /* remove any leading and trailing / */
-       trim_string_wa(ns, "/", "/");
-
-       return ns;
-}
-
 /****************************************************************************
  Make a dir struct.
 ****************************************************************************/
 
-void make_dir_struct(char *buf, const char *mask, const char *fname,SMB_OFF_T size,int mode,time_t date)
+void make_dir_struct(char *buf, const char *mask, const char *fname,SMB_OFF_T size,int mode,time_t date, BOOL case_sensitive)
 {  
        char *p;
        pstring mask2;
@@ -831,7 +756,7 @@ SMB_OFF_T transfer_file(int infd,int outfd,SMB_OFF_T n)
  Sleep for a specified number of milliseconds.
 ********************************************************************/
 
-void msleep(unsigned int t)
+void smb_msleep(unsigned int t)
 {
        unsigned int tdiff=0;
        struct timeval tval,t1,t2;  
@@ -937,6 +862,19 @@ void *Realloc(void *p,size_t size)
        return(ret);
 }
 
+void *Realloc_zero(void *ptr, size_t size)
+{
+       void *tptr = NULL;
+               
+       tptr = Realloc(ptr, size);
+       if(tptr == NULL)
+               return NULL;
+
+       memset((char *)tptr,'\0',size);
+
+       return tptr;
+}
+
 /****************************************************************************
  Free memory, checks for NULL.
  Use directly SAFE_FREE()
@@ -981,26 +919,33 @@ BOOL get_myname(char *my_name)
 }
 
 /****************************************************************************
- Get my own name, including domain.
+ Get my own canonical name, including domain.
 ****************************************************************************/
 
-BOOL get_myfullname(char *my_name)
+BOOL get_mydnsfullname(fstring my_dnsname)
 {
-       pstring hostname;
-
-       *hostname = 0;
+       static fstring dnshostname;
+       struct hostent *hp;
 
-       /* get my host name */
-       if (gethostname(hostname, sizeof(hostname)) == -1) {
-               DEBUG(0,("gethostname failed\n"));
-               return False;
-       } 
+       if (!*dnshostname) {
+               /* get my host name */
+               if (gethostname(dnshostname, sizeof(dnshostname)) == -1) {
+                       *dnshostname = '\0';
+                       DEBUG(0,("gethostname failed\n"));
+                       return False;
+               } 
 
-       /* Ensure null termination. */
-       hostname[sizeof(hostname)-1] = '\0';
+               /* Ensure null termination. */
+               dnshostname[sizeof(dnshostname)-1] = '\0';
 
-       if (my_name)
-               fstrcpy(my_name, hostname);
+               /* Ensure we get the cannonical name. */
+               if (!(hp = sys_gethostbyname(dnshostname))) {
+                       *dnshostname = '\0';
+                       return False;
+               }
+               fstrcpy(dnshostname, hp->h_name);
+       }
+       fstrcpy(my_dnsname, dnshostname);
        return True;
 }
 
@@ -1008,32 +953,22 @@ BOOL get_myfullname(char *my_name)
  Get my own domain name.
 ****************************************************************************/
 
-BOOL get_mydomname(fstring my_domname)
+BOOL get_mydnsdomname(fstring my_domname)
 {
-       pstring hostname;
+       fstring domname;
        char *p;
 
-       *hostname = 0;
-       /* get my host name */
-       if (gethostname(hostname, sizeof(hostname)) == -1) {
-               DEBUG(0,("gethostname failed\n"));
-               return False;
-       } 
-
-       /* Ensure null termination. */
-       hostname[sizeof(hostname)-1] = '\0';
-
-       p = strchr_m(hostname, '.');
-
-       if (!p)
+       *my_domname = '\0';
+       if (!get_mydnsfullname(domname)) {
                return False;
-
-       p++;
-       
-       if (my_domname)
+       }       
+       p = strchr_m(domname, '.');
+       if (p) {
+               p++;
                fstrcpy(my_domname, p);
+       }
 
-       return True;
+       return False;
 }
 
 /****************************************************************************
@@ -1352,7 +1287,7 @@ char *gidtoname(gid_t gid)
  Convert a user name into a uid. 
 ********************************************************************/
 
-uid_t nametouid(char *name)
+uid_t nametouid(const char *name)
 {
        struct passwd *pass;
        char *p;
@@ -1392,18 +1327,31 @@ gid_t nametogid(const char *name)
        return (gid_t)-1;
 }
 
+/*******************************************************************
+ legacy wrapper for smb_panic2()
+********************************************************************/
+void smb_panic( const char *why )
+{
+       smb_panic2( why, True );
+}
+
 /*******************************************************************
  Something really nasty happened - panic !
 ********************************************************************/
 
-void smb_panic(const char *why)
+#ifdef HAVE_LIBEXC_H
+#include <libexc.h>
+#endif
+
+void smb_panic2(const char *why, BOOL decrement_pid_count )
 {
        char *cmd;
        int result;
-       size_t i;
+#ifdef HAVE_BACKTRACE_SYMBOLS
        void *backtrace_stack[BACKTRACE_STACK_SIZE];
        size_t backtrace_size;
        char **backtrace_strings;
+#endif
 
 #ifdef DEVELOPER
        {
@@ -1418,6 +1366,10 @@ void smb_panic(const char *why)
        }
 #endif
 
+       /* only smbd needs to decrement the smbd counter in connections.tdb */
+       if ( decrement_pid_count )
+               decrement_smbd_process_count();
+
        cmd = lp_panic_action();
        if (cmd && *cmd) {
                DEBUG(0, ("smb_panic(): calling panic action [%s]\n", cmd));
@@ -1431,22 +1383,66 @@ void smb_panic(const char *why)
                                          WEXITSTATUS(result)));
        }
        DEBUG(0,("PANIC: %s\n", why));
-       DEBUG(0, ("%d stack frames:\n", backtrace_size));
 
 #ifdef HAVE_BACKTRACE_SYMBOLS
        /* get the backtrace (stack frames) */
        backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE);
        backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size);
+
+       DEBUG(0, ("BACKTRACE: %lu stack frames:\n", 
+                 (unsigned long)backtrace_size));
        
        if (backtrace_strings) {
+               int i;
+
                for (i = 0; i < backtrace_size; i++)
-                       DEBUG(0, (" #%u %s\n", i, backtrace_strings[i]));
+                       DEBUGADD(0, (" #%u %s\n", i, backtrace_strings[i]));
+
+               /* Leak the backtrace_strings, rather than risk what free() might do */
        }
 
-       free(backtrace_strings);
+#elif HAVE_LIBEXC
+
+#define NAMESIZE 32 /* Arbitrary */
+
+       /* The IRIX libexc library provides an API for unwinding the stack. See
+        * libexc(3) for details. Apparantly trace_back_stack leaks memory, but
+        * since we are about to abort anyway, it hardly matters.
+        *
+        * Note that if we paniced due to a SIGSEGV or SIGBUS (or similar) this
+        * will fail with a nasty message upon failing to open the /proc entry.
+        */
+       {
+               __uint64_t      addrs[BACKTRACE_STACK_SIZE];
+               char *          names[BACKTRACE_STACK_SIZE];
+               char            namebuf[BACKTRACE_STACK_SIZE * NAMESIZE];
+
+               int             i;
+               int             levels;
+
+               ZERO_ARRAY(addrs);
+               ZERO_ARRAY(names);
+               ZERO_ARRAY(namebuf);
+
+               for (i = 0; i < BACKTRACE_STACK_SIZE; i++) {
+                       names[i] = namebuf + (i * NAMESIZE);
+               }
+
+               levels = trace_back_stack(0, addrs, names,
+                               BACKTRACE_STACK_SIZE, NAMESIZE);
+
+               DEBUG(0, ("BACKTRACE: %d stack frames:\n", levels));
+               for (i = 0; i < levels; i++) {
+                       DEBUGADD(0, (" #%d 0x%llx %s\n", i, addrs[i], names[i]));
+               }
+     }
+#undef NAMESIZE
 #endif
 
        dbgflush();
+#ifdef SIGABRT
+       CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
+#endif
        abort();
 }
 
@@ -1494,7 +1490,7 @@ const char *readdirname(DIR *p)
  of a path matches a (possibly wildcarded) entry in a namelist.
 ********************************************************************/
 
-BOOL is_in_path(const char *name, name_compare_entry *namelist)
+BOOL is_in_path(const char *name, name_compare_entry *namelist, BOOL case_sensitive)
 {
        pstring last_component;
        char *p;
@@ -1707,24 +1703,6 @@ BOOL is_myname(const char *s)
        return(ret);
 }
 
-/********************************************************************
- Return only the first IP address of our configured interfaces
- as a string
- *******************************************************************/
-
-const char* get_my_primary_ip (void)
-{
-       static fstring ip_string;
-       int n;
-       struct iface_struct nics[MAX_INTERFACES];
-
-       if ((n=get_interfaces(nics, MAX_INTERFACES)) <= 0)
-               return NULL;
-
-       fstrcpy(ip_string, inet_ntoa(nics[0].ip));
-       return ip_string;
-}
-
 BOOL is_myname_or_ipaddr(const char *s)
 {
        /* optimize for the common case */
@@ -1779,13 +1757,15 @@ BOOL is_myworkgroup(const char *s)
    Win2k => "Windows 2000 5.0"
    NT4   => "Windows NT 4.0" 
    Win9x => "Windows 4.0"
+ Windows 2003 doesn't set the native lan manager string but 
+ they do set the domain to "Windows 2003 5.2" (probably a bug).
 ********************************************************************/
 
 void ra_lanman_string( const char *native_lanman )
 {               
-       if ( 0 == strcmp( native_lanman, "Windows 2002 5.1" ) )
+       if ( strcmp( native_lanman, "Windows 2002 5.1" ) == 0 )
                set_remote_arch( RA_WINXP );
-       else if ( 0 == strcmp( native_lanman, "Windows .NET 5.2" ) )
+       else if ( strcmp( native_lanman, "Windows Server 2003 5.2" ) == 0 )
                set_remote_arch( RA_WIN2K3 );
 }
 
@@ -1800,33 +1780,35 @@ void set_remote_arch(enum remote_arch_types type)
        switch( type ) {
        case RA_WFWG:
                fstrcpy(remote_arch, "WfWg");
-               return;
+               break;
        case RA_OS2:
                fstrcpy(remote_arch, "OS2");
-               return;
+               break;
        case RA_WIN95:
                fstrcpy(remote_arch, "Win95");
-               return;
+               break;
        case RA_WINNT:
                fstrcpy(remote_arch, "WinNT");
-               return;
+               break;
        case RA_WIN2K:
                fstrcpy(remote_arch, "Win2K");
-               return;
+               break;
        case RA_WINXP:
                fstrcpy(remote_arch, "WinXP");
-               return;
+               break;
        case RA_WIN2K3:
                fstrcpy(remote_arch, "Win2K3");
-               return;
+               break;
        case RA_SAMBA:
                fstrcpy(remote_arch,"Samba");
-               return;
+               break;
        default:
                ra_type = RA_UNKNOWN;
                fstrcpy(remote_arch, "UNKNOWN");
                break;
        }
+
+       DEBUG(10,("set_remote_arch: Client arch is \'%s\'\n", remote_arch));
 }
 
 /*******************************************************************
@@ -1838,50 +1820,6 @@ enum remote_arch_types get_remote_arch(void)
        return ra_type;
 }
 
-
-void out_ascii(FILE *f, unsigned char *buf,int len)
-{
-       int i;
-       for (i=0;i<len;i++)
-               fprintf(f, "%c", isprint(buf[i])?buf[i]:'.');
-}
-
-void out_data(FILE *f,char *buf1,int len, int per_line)
-{
-       unsigned char *buf = (unsigned char *)buf1;
-       int i=0;
-       if (len<=0) {
-               return;
-       }
-
-       fprintf(f, "[%03X] ",i);
-       for (i=0;i<len;) {
-               fprintf(f, "%02X ",(int)buf[i]);
-               i++;
-               if (i%(per_line/2) == 0) fprintf(f, " ");
-               if (i%per_line == 0) {      
-                       out_ascii(f,&buf[i-per_line  ],per_line/2); fprintf(f, " ");
-                       out_ascii(f,&buf[i-per_line/2],per_line/2); fprintf(f, "\n");
-                       if (i<len) fprintf(f, "[%03X] ",i);
-               }
-       }
-       if ((i%per_line) != 0) {
-               int n;
-
-               n = per_line - (i%per_line);
-               fprintf(f, " ");
-               if (n>(per_line/2)) fprintf(f, " ");
-               while (n--) {
-                       fprintf(f, "   ");
-               }
-               n = MIN(per_line/2,i%per_line);
-               out_ascii(f,&buf[i-(i%per_line)],n); fprintf(f, " ");
-               n = (i%per_line) - n;
-               if (n>0) out_ascii(f,&buf[i-n],n); 
-               fprintf(f, "\n");    
-       }
-}
-
 void print_asc(int level, const unsigned char *buf,int len)
 {
        int i;
@@ -1922,6 +1860,17 @@ void dump_data(int level, const char *buf1,int len)
        }       
 }
 
+void dump_data_pw(const char *msg, const uchar * data, size_t len)
+{
+#ifdef DEBUG_PASSWORD
+       DEBUG(11, ("%s", msg));
+       if (data != NULL && len > 0)
+       {
+               dump_data(11, data, len);
+       }
+#endif
+}
+
 char *tab_depth(int depth)
 {
        static pstring spaces;
@@ -2205,7 +2154,7 @@ char *lock_path(const char *name)
        static pstring fname;
 
        pstrcpy(fname,lp_lockdir());
-       trim_string(fname,"","/");
+       trim_char(fname,'\0','/');
        
        if (!directory_exist(fname,NULL))
                mkdir(fname,0755);
@@ -2225,7 +2174,7 @@ char *pid_path(const char *name)
        static pstring fname;
 
        pstrcpy(fname,lp_piddir());
-       trim_string(fname,"","/");
+       trim_char(fname,'\0','/');
 
        if (!directory_exist(fname,NULL))
                mkdir(fname,0755);
@@ -2247,7 +2196,7 @@ char *pid_path(const char *name)
 char *lib_path(const char *name)
 {
        static pstring fname;
-       snprintf(fname, sizeof(fname), "%s/%s", dyn_LIBDIR, name);
+       fstr_sprintf(fname, "%s/%s", dyn_LIBDIR, name);
        return fname;
 }
 
@@ -2295,7 +2244,7 @@ char *parent_dirname(const char *path)
  Determine if a pattern contains any Microsoft wildcard characters.
 *******************************************************************/
 
-BOOL ms_has_wild(char *s)
+BOOL ms_has_wild(const char *s)
 {
        char c;
        while ((c = *s++)) {
@@ -2335,30 +2284,35 @@ BOOL ms_has_wild_w(const smb_ucs2_t *s)
 
 BOOL mask_match(const char *string, char *pattern, BOOL is_case_sensitive)
 {
-       fstring p2, s2;
-
        if (strcmp(string,"..") == 0)
                string = ".";
        if (strcmp(pattern,".") == 0)
                return False;
        
-       if (is_case_sensitive)
-               return ms_fnmatch(pattern, string, Protocol) == 0;
+       return ms_fnmatch(pattern, string, Protocol, is_case_sensitive) == 0;
+}
 
-       fstrcpy(p2, pattern);
-       fstrcpy(s2, string);
-       strlower(p2); 
-       strlower(s2);
-       return ms_fnmatch(p2, s2, Protocol) == 0;
+/*******************************************************************
+ A wrapper that handles a list of patters and calls mask_match()
+ on each.  Returns True if any of the patterns match.
+*******************************************************************/
+
+BOOL mask_match_list(const char *string, char **list, int listLen, BOOL is_case_sensitive)
+{
+       while (listLen-- > 0) {
+               if (mask_match(string, *list++, is_case_sensitive))
+                       return True;
+       }
+       return False;
 }
 
 /*********************************************************
  Recursive routine that is called by unix_wild_match.
 *********************************************************/
 
-static BOOL unix_do_match(char *regexp, char *str)
+static BOOL unix_do_match(const char *regexp, const char *str)
 {
-       char *p;
+       const char *p;
 
        for( p = regexp; *p && *str; ) {
 
@@ -2464,8 +2418,8 @@ BOOL unix_wild_match(const char *pattern, const char *string)
 
        pstrcpy(p2, pattern);
        pstrcpy(s2, string);
-       strlower(p2);
-       strlower(s2);
+       strlower_m(p2);
+       strlower_m(s2);
 
        /* Remove any *? and ** from the pattern as they are meaningless */
        for(p = p2; *p; p++)
@@ -2478,6 +2432,7 @@ BOOL unix_wild_match(const char *pattern, const char *string)
        return unix_do_match(p2, s2) == 0;      
 }
 
+
 #ifdef __INSURE__
 
 /*******************************************************************