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 */
/****************************************************************************
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])
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;
}
(*n) = atoi(p);
while ((*p) && isdigit((int)*p))
- {
p++;
- }
if (strchr_m(c, *p) == NULL)
{
}
/*************************************************************************
- 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++;
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);
}
/*******************************************************************
-check a files mod time
+ Check a files mod time.
********************************************************************/
+
time_t file_modtime(char *fname)
{
SMB_STRUCT_STAT st;
}
/*******************************************************************
- check if a directory exists
+ Check if a directory exists.
********************************************************************/
+
BOOL directory_exist(char *dname,SMB_STRUCT_STAT *st)
{
SMB_STRUCT_STAT st2;
/*******************************************************************
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)));
}
/*******************************************************************
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
****************************************************************************/
}
/****************************************************************************
-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;
}
}
-
/****************************************************************************
-become a daemon, discarding the controlling terminal
+ Become a daemon, discarding the controlling terminal.
****************************************************************************/
+
void become_daemon(void)
{
if (sys_fork()) {
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;
}
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;
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);
}
}
/****************************************************************************
-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"))
/*******************************************************************
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))
/******************************************************************
*******************************************************************/
#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 = "";
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 = "";
is present does a shortcut lookup...
********************************************************************/
-gid_t nametogid(char *name)
+gid_t nametogid(const char *name)
{
struct group *grp;
char *p;
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);
}
/****************************************************************************
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.
********************************************************************/
void zero_free(void *p, size_t size)
{
memset(p, 0, size);
- free(p);
+ SAFE_FREE(p);
}
#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;
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:
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 = ".";
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__
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);