Add harmless parentheses so that dmalloc doesn't get confused by a
[ira/wip.git] / source3 / lib / util.c
index 3161aba63ff9755406c0a35d8f489e1262c0aa39..6caa605066367e5ffef7713dfa833e36ef660f6d 100644 (file)
@@ -3,6 +3,8 @@
    Version 1.9.
    Samba utility functions
    Copyright (C) Andrew Tridgell 1992-1998
+   Copyright (C) Jeremy Allison 2001
+   Copyright (C) Simo Sorce 2001
    
    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
 #endif /* HAVE_NETGROUP && WITH_AUTOMOUNT */
 
 #ifdef WITH_SSL
-#include <ssl.h>
+#include <openssl/ssl.h>
 #undef Realloc  /* SSLeay defines this and samba has a function of this name */
 extern SSL  *ssl;
 extern int  sslFd;
 #endif  /* WITH_SSL */
 
-extern int DEBUGLEVEL;
-
 int Protocol = PROTOCOL_COREPLUS;
 
 /* a default finfo structure to ensure all fields are sensible */
@@ -93,26 +93,26 @@ char **my_netbios_names;
 
 /****************************************************************************
   find a suitable temporary directory. The result should be copied immediately
-  as it may be overwritten by a subsequent call
+ as it may be overwritten by a subsequent call.
   ****************************************************************************/
 char *tmpdir(void)
 {
   char *p;
-  if ((p = getenv("TMPDIR"))) {
+       if ((p = getenv("TMPDIR")))
     return p;
-  }
   return "/tmp";
 }
 
 /****************************************************************************
-determine whether we are in the specified group
+ Determine whether we are in the specified group.
 ****************************************************************************/
 
 BOOL in_group(gid_t group, gid_t current_gid, int ngroups, gid_t *groups)
 {
        int i;
 
-       if (group == current_gid) return(True);
+       if (group == current_gid)
+               return(True);
 
        for (i=0;i<ngroups;i++)
                if (group == groups[i])
@@ -121,14 +121,13 @@ BOOL in_group(gid_t group, gid_t current_gid, int ngroups, gid_t *groups)
        return(False);
 }
 
-
 /****************************************************************************
-like atoi but gets the value up to the separater character
+ Like atoi but gets the value up to the separater character.
 ****************************************************************************/
+
 char *Atoic(char *p, int *n, char *c)
 {
-       if (!isdigit((int)*p))
-       {
+       if (!isdigit((int)*p)) {
                DEBUG(5, ("Atoic: malformed number\n"));
                return NULL;
        }
@@ -136,9 +135,7 @@ char *Atoic(char *p, int *n, char *c)
        (*n) = atoi(p);
 
        while ((*p) && isdigit((int)*p))
-       {
                p++;
-       }
 
        if (strchr_m(c, *p) == NULL)
        {
@@ -150,31 +147,29 @@ char *Atoic(char *p, int *n, char *c)
 }
 
 /*************************************************************************
- reads a list of numbers
+ Reads a list of numbers.
  *************************************************************************/
+
 char *get_numlist(char *p, uint32 **num, int *count)
 {
        int val;
 
        if (num == NULL || count == NULL)
-       {
                return NULL;
-       }
 
        (*count) = 0;
        (*num  ) = NULL;
 
-       while ((p = Atoic(p, &val, ":,")) != NULL && (*p) != ':')
-       {
+       while ((p = Atoic(p, &val, ":,")) != NULL && (*p) != ':') {
                uint32 *tn;
                
                tn = Realloc((*num), ((*count)+1) * sizeof(uint32));
                if (tn == NULL)
                {
-                       if (*num) free(*num);
+                       SAFE_FREE(*num);
                        return NULL;
-               }
-               else (*num) = tn;
+               } else
+                       (*num) = tn;
                (*num)[(*count)] = val;
                (*count)++;
                p++;
@@ -183,14 +178,15 @@ char *get_numlist(char *p, uint32 **num, int *count)
        return p;
 }
 
-
 /*******************************************************************
-  check if a file exists - call vfs_file_exist for samba files
+ Check if a file exists - call vfs_file_exist for samba files.
 ********************************************************************/
+
 BOOL file_exist(char *fname,SMB_STRUCT_STAT *sbuf)
 {
   SMB_STRUCT_STAT st;
-  if (!sbuf) sbuf = &st;
+       if (!sbuf)
+               sbuf = &st;
   
   if (sys_stat(fname,sbuf) != 0) 
     return(False);
@@ -199,8 +195,9 @@ BOOL file_exist(char *fname,SMB_STRUCT_STAT *sbuf)
 }
 
 /*******************************************************************
-check a files mod time
+ Check a files mod time.
 ********************************************************************/
+
 time_t file_modtime(char *fname)
 {
   SMB_STRUCT_STAT st;
@@ -212,8 +209,9 @@ time_t file_modtime(char *fname)
 }
 
 /*******************************************************************
-  check if a directory exists
+ Check if a directory exists.
 ********************************************************************/
+
 BOOL directory_exist(char *dname,SMB_STRUCT_STAT *st)
 {
   SMB_STRUCT_STAT st2;
@@ -335,20 +333,21 @@ int set_message(char *buf,int num_words,int num_bytes,BOOL zero)
 /*******************************************************************
   setup only the byte count for a smb message
 ********************************************************************/
-void set_message_bcc(char *buf,int num_bytes)
+int set_message_bcc(char *buf,int num_bytes)
 {
        int num_words = CVAL(buf,smb_wct);
        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);
 }
 
 /*******************************************************************
   setup only the byte count for a smb message, using the end of the
   message as a marker
 ********************************************************************/
-void set_message_end(void *outbuf,void *end_ptr)
+int set_message_end(void *outbuf,void *end_ptr)
 {
-       set_message_bcc((char *)outbuf,PTR_DIFF(end_ptr,smb_buf((char *)outbuf)));
+       return set_message_bcc((char *)outbuf,PTR_DIFF(end_ptr,smb_buf((char *)outbuf)));
 }
 
 /*******************************************************************
@@ -418,6 +417,58 @@ 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")); */
+
+       /* 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 ((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;
+                       memmove(p, t, (strlen_w(t) + 1) * sizeof(smb_ucs2_t));
+                       t = p;
+               }
+       }
+
+       /* remove any trailing /. */
+       trim_string_wa(ns, NULL, "/.");
+
+       /* remove any leading and trailing / */
+       trim_string_wa(ns, "/", "/");
+
+       return ns;
+}
+
 /****************************************************************************
   make a dir struct
 ****************************************************************************/
@@ -511,85 +562,70 @@ int set_blocking(int fd, BOOL set)
 }
 
 /****************************************************************************
-transfer some data between two fd's
+ Transfer some data between two fd's.
 ****************************************************************************/
-SMB_OFF_T transfer_file(int infd,int outfd,SMB_OFF_T n,char *header,int headlen,int align)
-{
-  static char *buf=NULL;  
-  static int size=0;
-  char *buf1,*abuf;
-  SMB_OFF_T total = 0;
 
-  DEBUG(4,("transfer_file n=%.0f  (head=%d) called\n",(double)n,headlen));
-
-  if (size == 0) {
-    size = lp_readsize();
-    size = MAX(size,1024);
-  }
-
-  while (!buf && size>0) {
-    buf = (char *)malloc(size+8);
-    if (!buf) size /= 2;
-  }
-
-  if (!buf) {
-    DEBUG(0,("Can't allocate transfer buffer!\n"));
-    exit(1);
-  }
-
-  abuf = buf + (align%8);
+#ifndef TRANSFER_BUF_SIZE
+#define TRANSFER_BUF_SIZE 65536
+#endif
 
-  if (header)
-    n += headlen;
+ssize_t transfer_file_internal(int infd, int outfd, size_t n, ssize_t (*read_fn)(int, void *, size_t),
+                                               ssize_t (*write_fn)(int, const void *, size_t))
+{
+       char *buf;
+       size_t total = 0;
+       ssize_t read_ret;
+       ssize_t write_ret;
+       size_t num_to_read_thistime;
+       size_t num_written = 0;
 
-  while (n > 0)
-  {
-    int s = (int)MIN(n,(SMB_OFF_T)size);
-    int ret,ret2=0;
+       if ((buf = malloc(TRANSFER_BUF_SIZE)) == NULL)
+               return -1;
 
-    ret = 0;
+       while (total < n) {
+               num_to_read_thistime = MIN((n - total), TRANSFER_BUF_SIZE);
 
-    if (header && (headlen >= MIN(s,1024))) {
-      buf1 = header;
-      s = headlen;
-      ret = headlen;
-      headlen = 0;
-      header = NULL;
-    } else {
-      buf1 = abuf;
-    }
+               read_ret = (*read_fn)(infd, buf, num_to_read_thistime);
+               if (read_ret == -1) {
+                       DEBUG(0,("transfer_file_internal: read failure. Error = %s\n", strerror(errno) ));
+                       SAFE_FREE(buf);
+                       return -1;
+               }
+               if (read_ret == 0)
+                       break;
 
-    if (header && headlen > 0)
-    {
-      ret = MIN(headlen,size);
-      memcpy(buf1,header,ret);
-      headlen -= ret;
-      header += ret;
-      if (headlen <= 0) header = NULL;
-    }
+               num_written = 0;
+               while (num_written < read_ret) {
+                       write_ret = (*write_fn)(outfd,buf + num_written, read_ret - num_written);
+                       if (write_ret == -1) {
+                               DEBUG(0,("transfer_file_internal: write failure. Error = %s\n", strerror(errno) ));
+                               SAFE_FREE(buf);
+                               return -1;
+                       }
+                       if (write_ret == 0)
+                               return (ssize_t)total;
+                       num_written += (size_t)write_ret;
+               }
 
-    if (s > ret)
-      ret += read(infd,buf1+ret,s-ret);
+               total += (size_t)read_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);
+       SAFE_FREE(buf);
+       return (ssize_t)total;          
 }
 
+SMB_OFF_T transfer_file(int infd,int outfd,SMB_OFF_T n)
+{
+       return (SMB_OFF_T)transfer_file_internal(infd, outfd, (size_t)n, read, write);
+}
 
 /*******************************************************************
-sleep for a specified number of milliseconds
+ Sleep for a specified number of milliseconds.
 ********************************************************************/
+
 void msleep(int t)
 {
   int tdiff=0;
@@ -612,10 +648,10 @@ void msleep(int t)
   }
 }
 
-
 /****************************************************************************
-become a daemon, discarding the controlling terminal
+ Become a daemon, discarding the controlling terminal.
 ****************************************************************************/
+
 void become_daemon(void)
 {
        if (sys_fork()) {
@@ -657,25 +693,16 @@ BOOL yesno(char *p)
   return(False);
 }
 
-#ifdef HPUX
 /****************************************************************************
-this is a version of setbuffer() for those machines that only have setvbuf
+ Expand a pointer to be a particular size.
 ****************************************************************************/
- void setbuffer(FILE *f,char *buf,int bufsize)
-{
-  setvbuf(f,buf,_IOFBF,bufsize);
-}
-#endif
 
-/****************************************************************************
-expand a pointer to be a particular size
-****************************************************************************/
 void *Realloc(void *p,size_t size)
 {
   void *ret=NULL;
 
   if (size == 0) {
-    if (p) free(p);
+    SAFE_FREE(p);
     DEBUG(5,("Realloc asked for 0 bytes\n"));
     return NULL;
   }
@@ -691,22 +718,21 @@ void *Realloc(void *p,size_t size)
   return(ret);
 }
 
-
 /****************************************************************************
-free memory, checks for NULL
+ Free memory, checks for NULL.
+use directly SAFE_FREE()
+exist only because we need to pass a function pointer somewhere --SSS
 ****************************************************************************/
+
 void safe_free(void *p)
 {
-       if (p != NULL)
-       {
-               free(p);
-       }
+       SAFE_FREE(p);
 }
 
-
 /****************************************************************************
-get my own name and IP
+ Get my own name and IP.
 ****************************************************************************/
+
 BOOL get_myname(char *my_name)
 {
        pstring hostname;
@@ -725,7 +751,9 @@ BOOL get_myname(char *my_name)
        if (my_name) {
                /* split off any parts after an initial . */
                char *p = strchr_m(hostname,'.');
-               if (p) *p = 0;
+
+               if (p)
+                       *p = 0;
                
                fstrcpy(my_name,hostname);
        }
@@ -734,8 +762,9 @@ BOOL get_myname(char *my_name)
 }
 
 /****************************************************************************
-interpret a protocol description string, with a default
+ Interpret a protocol description string, with a default.
 ****************************************************************************/
+
 int interpret_protocol(char *str,int def)
 {
   if (strequal(str,"NT1"))
@@ -823,13 +852,27 @@ struct in_addr *interpret_addr2(const char *str)
 /*******************************************************************
   check if an IP is the 0.0.0.0
   ******************************************************************/
-BOOL zero_ip(struct in_addr ip)
+BOOL is_zero_ip(struct in_addr ip)
 {
   uint32 a;
   putip((char *)&a,(char *)&ip);
   return(a == 0);
 }
 
+/* Set an IP to 0.0.0.0 */
+
+void zero_ip(struct in_addr *ip)
+{
+        static BOOL init;
+        static struct in_addr ipzero;
+
+        if (!init) {
+                ipzero = *interpret_addr2("0.0.0.0");
+                init = True;
+        }
+
+        *ip = ipzero;
+}
 
 #if (defined(HAVE_NETGROUP) && defined(WITH_AUTOMOUNT))
 /******************************************************************
@@ -863,7 +906,7 @@ static void strip_mount_options( pstring *str)
 *******************************************************************/
 
 #ifdef WITH_NISPLUS_HOME
-char *automount_lookup(char *user_name)
+char *automount_lookup(const char *user_name)
 {
   static fstring last_key = "";
   static pstring last_value = "";
@@ -911,7 +954,7 @@ char *automount_lookup(char *user_name)
   return last_value;
 }
 #else /* WITH_NISPLUS_HOME */
-char *automount_lookup(char *user_name)
+char *automount_lookup(const char *user_name)
 {
   static fstring last_key = "";
   static pstring last_value = "";
@@ -1059,7 +1102,7 @@ uid_t nametouid(char *name)
  is present does a shortcut lookup...
 ********************************************************************/
 
-gid_t nametogid(char *name)
+gid_t nametogid(const char *name)
 {
        struct group *grp;
        char *p;
@@ -1280,13 +1323,11 @@ routine to free a namearray.
 
 void free_namearray(name_compare_entry *name_array)
 {
-  if(name_array == 0)
+  if(name_array == NULL)
     return;
 
-  if(name_array->name != NULL)
-    free(name_array->name);
-
-  free((char *)name_array);
+  SAFE_FREE(name_array->name);
+  SAFE_FREE(name_array);
 }
 
 /****************************************************************************
@@ -1361,6 +1402,47 @@ BOOL is_myname(char *s)
   return(ret);
 }
 
+BOOL is_myname_or_ipaddr(char *s)
+{
+       char **ptr;
+       
+       /* optimize for the common case */
+       if (strequal(s, global_myname)) 
+               return True;
+
+       /* maybe its an IP address? */
+       if (is_ipaddress(s))
+       {
+               struct iface_struct nics[MAX_INTERFACES];
+               int i, n;
+               uint32 ip;
+               
+               ip = interpret_addr(s);
+               if ((ip==0) || (ip==0xffffffff))
+                       return False;
+                       
+               n = get_interfaces(nics, MAX_INTERFACES);
+               for (i=0; i<n; i++) {
+                       if (ip == nics[i].ip.s_addr)
+                               return True;
+               }
+       }       
+
+       /* check for an alias */
+       ptr = lp_netbios_aliases();
+       for ( ; *ptr; ptr++ )
+       {
+               if (StrCaseCmp(s, *ptr) == 0)
+                       return True;
+       }
+       
+       
+       /* no match */
+       return False;
+
+}
+
+
 /*******************************************************************
 set the horrid remote_arch string based on an enum.
 ********************************************************************/
@@ -1535,7 +1617,7 @@ zero a memory area then free it. Used to catch bugs faster
 void zero_free(void *p, size_t size)
 {
        memset(p, 0, size);
-       free(p);
+       SAFE_FREE(p);
 }
 
 
@@ -1682,10 +1764,59 @@ int smb_mkstemp(char *template)
 #endif
 }
 
+
+/**
+ malloc that aborts with smb_panic on fail or zero size.
+**/
+void *smb_xmalloc(size_t size)
+{
+       void *p;
+       if (size == 0)
+               smb_panic("smb_xmalloc: called with zero size.\n");
+       if ((p = malloc(size)) == NULL)
+               smb_panic("smb_xmalloc: malloc fail.\n");
+       return p;
+}
+
+/**
+ Memdup with smb_panic on fail.
+**/
+void *smb_xmemdup(const void *p, size_t size)
+{
+       void *p2;
+       p2 = smb_xmalloc(size);
+       memcpy(p2, p, size);
+       return p2;
+}
+
+/**
+ strdup that aborts on malloc fail.
+**/
+char *smb_xstrdup(const char *s)
+{
+       char *s1 = strdup(s);
+       if (!s1)
+               smb_panic("smb_xstrdup: malloc fail\n");
+       return s1;
+}
+
+/*
+  vasprintf that aborts on malloc fail
+*/
+int smb_xvasprintf(char **ptr, const char *format, va_list ap)
+{
+       int n;
+       n = vasprintf(ptr, format, ap);
+       if (n == -1 || ! *ptr) {
+               smb_panic("smb_xvasprintf: out of memory");
+       }
+       return n;
+}
+
 /*****************************************************************
 like strdup but for memory
  *****************************************************************/  
-void *memdup(void *p, size_t size)
+void *memdup(const void *p, size_t size)
 {
        void *p2;
        if (size == 0) return NULL;
@@ -1728,6 +1859,21 @@ char *lock_path(char *name)
        return fname;
 }
 
+
+/**
+ * @brief Returns an absolute path to a file in the Samba lib directory.
+ *
+ * @param name File to find, relative to LIBDIR.
+ *
+ * @retval Pointer to a static #pstring containing the full path.
+ **/
+char *lib_path(char *name)
+{
+       static pstring fname;
+       snprintf(fname, sizeof(fname), "%s/%s", dyn_LIBDIR, name);
+       return fname;
+}
+
 /*******************************************************************
  Given a filename - get its directory name
  NB: Returned in static storage.  Caveats:
@@ -1776,13 +1922,28 @@ BOOL ms_has_wild(char *s)
        return False;
 }
 
+BOOL ms_has_wild_w(const smb_ucs2_t *s)
+{
+       smb_ucs2_t c;
+       while ((c = *s++)) {
+               switch (c) {
+               case UCS2_CHAR('*'):
+               case UCS2_CHAR('?'):
+               case UCS2_CHAR('<'):
+               case UCS2_CHAR('>'):
+               case UCS2_CHAR('"'):
+                       return True;
+               }
+       }
+       return False;
+}
+
 /*******************************************************************
  a wrapper that handles case sensitivity and the special handling
    of the ".." name
  *******************************************************************/
 BOOL mask_match(char *string, char *pattern, BOOL is_case_sensitive)
 {
-       extern int Protocol;
        fstring p2, s2;
 
        if (strcmp(string,"..") == 0) string = ".";
@@ -1799,20 +1960,216 @@ BOOL mask_match(char *string, char *pattern, BOOL is_case_sensitive)
        return ms_fnmatch(p2, s2, Protocol) == 0;
 }
 
+/*********************************************************
+ Recursive routine that is called by unix_wild_match.
+*********************************************************/
+
+static BOOL unix_do_match(char *regexp, char *str)
+{
+       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 && (*p != *str))
+                                               str++;
+
+                                       /*
+                                        * Patch from weidel@multichart.de. In the case of the regexp
+                                        * '*XX*' we want to ensure there are at least 2 'X' characters
+                                        * in the string after the '*' for a match to be made.
+                                        */
+
+                                       {
+                                               int matchcount=0;
+
+                                               /*
+                                                * Eat all the characters that match, but count how many there were.
+                                                */
+
+                                               while(*str && (*p == *str)) {
+                                                       str++;
+                                                       matchcount++;
+                                               }
+
+                                               /*
+                                                * Now check that if the regexp had n identical characters that
+                                                * matchcount had at least that many matches.
+                                                */
+
+                                               while ( *(p+1) && (*(p+1) == *p)) {
+                                                       p++;
+                                                       matchcount--;
+                                               }
+
+                                               if ( matchcount <= 0 )
+                                                       return False;
+                                       }
+
+                                       str--; /* We've eaten the match char after the '*' */
+
+                                       if(unix_do_match(p, str))
+                                               return True;
+
+                                       if(!*str)
+                                               return False;
+                                       else
+                                               str++;
+                               }
+                               return False;
+
+                       default:
+                               if(*str != *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;
+}
+
 /*******************************************************************
- Simple case insensitive interface to ms_fnmatch.
+ Simple case insensitive interface to a UNIX wildcard matcher.
 *******************************************************************/
-BOOL wild_match(char *string, char *pattern)
+
+BOOL unix_wild_match(char *pattern, char *string)
 {
        pstring p2, s2;
-       extern int Protocol;
+       char *p;
 
        pstrcpy(p2, pattern);
        pstrcpy(s2, string);
        strlower(p2);
        strlower(s2);
-       return ms_fnmatch(p2, s2, Protocol) == 0;
+
+       /* Remove any *? and ** from the pattern as they are meaningless */
+       for(p = p2; *p; p++)
+               while( *p == '*' && (p[1] == '?' ||p[1] == '*'))
+                       pstrcpy( &p[1], &p[2]);
+       if (strequal(p2,"*"))
+               return True;
+
+       return unix_do_match(p2, s2) == 0;      
+}
+
+/*******************************************************************
+ free() a data blob
+*******************************************************************/
+static void free_data_blob(DATA_BLOB *d)
+{
+       if ((d) && (d->free)) {
+               SAFE_FREE(d->data);
+       }
+}
+
+/*******************************************************************
+ construct a data blob, must be freed with data_blob_free()
+ you can pass NULL for p and get a blank data blob
+*******************************************************************/
+DATA_BLOB data_blob(const void *p, size_t length)
+{
+       DATA_BLOB ret;
+
+       if (!length) {
+               ZERO_STRUCT(ret);
+               return ret;
+       }
+
+       if (p) {
+               ret.data = smb_xmemdup(p, length);
+       } else {
+               ret.data = smb_xmalloc(length);
+       }
+       ret.length = length;
+       ret.free = free_data_blob;
+       return ret;
+}
+
+/*******************************************************************
+ construct a data blob, using supplied TALLOC_CTX
+*******************************************************************/
+DATA_BLOB data_blob_talloc(TALLOC_CTX *mem_ctx, const void *p, size_t length)
+{
+       DATA_BLOB ret;
+
+       if (!p || !length) {
+               ZERO_STRUCT(ret);
+               return ret;
+       }
+
+       ret.data = talloc_memdup(mem_ctx, p, length);
+       if (ret.data == NULL)
+               smb_panic("data_blob_talloc: talloc_memdup failed.\n");
+
+       ret.length = length;
+       ret.free = NULL;
+       return ret;
+}
+
+/*******************************************************************
+free a data blob
+*******************************************************************/
+void data_blob_free(DATA_BLOB *d)
+{
+       if (d) {
+               if (d->free) {
+                       (d->free)(d);
+               }
+               ZERO_STRUCTP(d);
+       }
+}
+
+/*******************************************************************
+clear a DATA_BLOB's contents
+*******************************************************************/
+void data_blob_clear(DATA_BLOB *d)
+{
+       if (d->data) {
+               memset(d->data, 0, d->length);
+       }
+}
+
+/*******************************************************************
+free a data blob and clear its contents
+*******************************************************************/
+void data_blob_clear_free(DATA_BLOB *d)
+{
+       data_blob_clear(d);
+       data_blob_free(d);
 }
 
 #ifdef __INSURE__
@@ -1827,7 +2184,9 @@ int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
        static int (*fn)();
        int ret;
        char pidstr[10];
-       pstring cmd = "/usr/X11R6/bin/xterm -display :0 -T Panic -n Panic -e /bin/sh -c 'cat /tmp/ierrs.*.%d ; gdb /proc/%d/exe %d'";
+       /* you can get /usr/bin/backtrace from 
+           http://samba.org/ftp/unpacked/junkcode/backtrace */
+       pstring cmd = "/usr/bin/backtrace %d";
 
        slprintf(pidstr, sizeof(pidstr)-1, "%d", sys_getpid());
        pstring_sub(cmd, "%d", pidstr);