summaryrefslogtreecommitdiff
path: root/source4/lib/util
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@samba.org>2006-02-23 15:52:24 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:52:05 -0500
commitdfc517b05395d925a4d7b1ce9633a849f9468e70 (patch)
treea81c020c89022980e6fbb68116648da217fbb0fc /source4/lib/util
parent80c8a522861068e7b0974986936f65052dd6f70f (diff)
downloadsamba-dfc517b05395d925a4d7b1ce9633a849f9468e70.tar.gz
samba-dfc517b05395d925a4d7b1ce9633a849f9468e70.tar.bz2
samba-dfc517b05395d925a4d7b1ce9633a849f9468e70.zip
r13658: More moving around of files:
- Collect the generic utility functions into a lib/util/ (a la GLib is for the GNOME folks) - Remove even more files from include/ (This used to be commit ba62880f5b05c2a505dc7f54676b231197a7e707)
Diffstat (limited to 'source4/lib/util')
-rw-r--r--source4/lib/util/README296
-rw-r--r--source4/lib/util/byteorder.h224
-rw-r--r--source4/lib/util/capability.c112
-rw-r--r--source4/lib/util/config.mk34
-rw-r--r--source4/lib/util/data_blob.c209
-rw-r--r--source4/lib/util/debug.c205
-rw-r--r--source4/lib/util/debug.h66
-rw-r--r--source4/lib/util/dprintf.c107
-rw-r--r--source4/lib/util/fault.c213
-rw-r--r--source4/lib/util/fsusage.c149
-rw-r--r--source4/lib/util/genrand.c314
-rw-r--r--source4/lib/util/idtree.c384
-rw-r--r--source4/lib/util/module.c97
-rw-r--r--source4/lib/util/ms_fnmatch.c219
-rw-r--r--source4/lib/util/mutex.c52
-rw-r--r--source4/lib/util/mutex.h71
-rw-r--r--source4/lib/util/pidfile.c116
-rw-r--r--source4/lib/util/safe_string.h55
-rw-r--r--source4/lib/util/select.c169
-rw-r--r--source4/lib/util/signal.c140
-rw-r--r--source4/lib/util/substitute.c165
-rw-r--r--source4/lib/util/system.c98
-rw-r--r--source4/lib/util/time.c596
-rw-r--r--source4/lib/util/unix_privs.c68
-rw-r--r--source4/lib/util/util.c737
-rw-r--r--source4/lib/util/util.h81
-rw-r--r--source4/lib/util/util_file.c385
-rw-r--r--source4/lib/util/util_getent.c284
-rw-r--r--source4/lib/util/util_pw.c89
-rw-r--r--source4/lib/util/util_sock.c128
-rw-r--r--source4/lib/util/util_str.c1209
-rw-r--r--source4/lib/util/util_strlist.c292
-rw-r--r--source4/lib/util/util_unistr.c150
-rw-r--r--source4/lib/util/xfile.c384
-rw-r--r--source4/lib/util/xfile.h49
35 files changed, 7947 insertions, 0 deletions
diff --git a/source4/lib/util/README b/source4/lib/util/README
new file mode 100644
index 0000000000..e52e04ed92
--- /dev/null
+++ b/source4/lib/util/README
@@ -0,0 +1,296 @@
+This directory contains convenience functions that are used heavily
+throughout Samba. None of these functions are SMB or Samba-specific.
+It's a bit to Samba what GLib is to the GNOME folks.
+
+(This file should be migrated to doxygen sometime.. )
+
+Also TODO: Remove dependency on loadparm
+
+XFILE wrapper functions
+=======================
+The XFILE implementation contains a clone of the standard UNIX stdio
+functions
+
+Debug functions
+===============
+DEBUG()
+
+Crash handlers
+==============
+void smb_panic(const char *why);
+
+Signal handling
+========================
+void BlockSignals(BOOL block,int signum);
+void (*CatchSignal(int signum,void (*handler)(int )))(int);
+void CatchChild(void);
+void CatchChildLeaveStatus(void);
+
+Wrappers
+========
+struct hostent *sys_gethostbyname(const char *name);
+const char *sys_inet_ntoa(struct ipv4_addr in);
+struct ipv4_addr sys_inet_makeaddr(int net, int host);
+void sys_select_signal(void);
+int sys_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval);
+int sys_select_intr(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval);
+
+Time datastructures
+===================
+time_t get_time_t_max(void);
+void GetTimeOfDay(struct timeval *tval);
+time_t nt_time_to_unix(NTTIME nt);
+void unix_to_nt_time(NTTIME *nt, time_t t);
+BOOL null_time(time_t t);
+BOOL null_nttime(NTTIME t);
+void push_dos_date(uint8_t *buf, int offset, time_t unixdate, int zone_offset);
+void push_dos_date2(uint8_t *buf,int offset,time_t unixdate, int zone_offset);
+void push_dos_date3(uint8_t *buf,int offset,time_t unixdate, int zone_offset);
+time_t pull_dos_date(const uint8_t *date_ptr, int zone_offset);
+time_t pull_dos_date2(const uint8_t *date_ptr, int zone_offset);
+time_t pull_dos_date3(const uint8_t *date_ptr, int zone_offset);
+char *http_timestring(TALLOC_CTX *mem_ctx, time_t t);
+char *timestring(TALLOC_CTX *mem_ctx, time_t t);
+const char *nt_time_string(TALLOC_CTX *mem_ctx, NTTIME nt);
+void push_nttime(uint8_t *base, uint16_t offset, NTTIME t);
+NTTIME pull_nttime(uint8_t *base, uint16_t offset);
+NTTIME nttime_from_string(const char *s);
+int64_t usec_time_diff(struct timeval *tv1, struct timeval *tv2);
+struct timeval timeval_zero(void);
+BOOL timeval_is_zero(const struct timeval *tv);
+struct timeval timeval_current(void);
+struct timeval timeval_set(uint32_t secs, uint32_t usecs);
+struct timeval timeval_add(const struct timeval *tv,
+ uint32_t secs, uint32_t usecs);
+struct timeval timeval_sum(const struct timeval *tv1,
+ const struct timeval *tv2);
+struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs);
+int timeval_compare(const struct timeval *tv1, const struct timeval *tv2);
+BOOL timeval_expired(const struct timeval *tv);
+double timeval_elapsed2(const struct timeval *tv1, const struct timeval *tv2);
+double timeval_elapsed(const struct timeval *tv);
+struct timeval timeval_min(const struct timeval *tv1,
+ const struct timeval *tv2);
+struct timeval timeval_max(const struct timeval *tv1,
+ const struct timeval *tv2);
+struct timeval timeval_until(const struct timeval *tv1,
+ const struct timeval *tv2);
+NTTIME timeval_to_nttime(const struct timeval *tv);
+int get_time_zone(time_t t);
+
+Random number generation
+========================
+void set_rand_reseed_callback(void (*fn)(int *));
+void set_need_random_reseed(void);
+void generate_random_buffer(uint8_t *out, int len);
+uint32_t generate_random(void);
+BOOL check_password_quality(const char *s);
+char *generate_random_str_list(TALLOC_CTX *mem_ctx, size_t len, const char *list);
+char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len);
+
+String manipulation
+===================
+BOOL next_token(const char **ptr,char *buff, const char *sep, size_t bufsize);
+int strcasecmp_m(const char *s1, const char *s2);
+BOOL strequal(const char *s1, const char *s2);
+BOOL strcsequal(const char *s1,const char *s2);
+int strwicmp(const char *psz1, const char *psz2);
+void string_replace(char *s, char oldc, char newc);
+BOOL trim_string(char *s,const char *front,const char *back);
+size_t count_chars(const char *s, char c);
+char *safe_strcpy(char *dest,const char *src, size_t maxlength);
+char *safe_strcat(char *dest, const char *src, size_t maxlength);
+char *alpha_strcpy(char *dest, const char *src, const char *other_safe_chars, size_t maxlength);
+char *StrnCpy(char *dest,const char *src,size_t n);
+size_t strhex_to_str(char *p, size_t len, const char *strhex);
+DATA_BLOB strhex_to_data_blob(const char *strhex) ;
+void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer);
+BOOL in_list(const char *s, const char *list, BOOL casesensitive);
+void string_free(char **s);
+BOOL string_set(char **dest, const char *src);
+void string_sub(char *s,const char *pattern, const char *insert, size_t len);
+void all_string_sub(char *s,const char *pattern,const char *insert, size_t len);
+char *strchr_m(const char *s, char c);
+char *strrchr_m(const char *s, char c);
+BOOL strhaslower(const char *string);
+BOOL strhasupper(const char *string);
+char *strlower_talloc(TALLOC_CTX *ctx, const char *src);
+char *strupper_talloc(TALLOC_CTX *ctx, const char *src);
+void strlower_m(char *s);
+void strupper_m(char *s);
+size_t strlen_m(const char *s);
+size_t strlen_m_term(const char *s);
+void rfc1738_unescape(char *buf);
+DATA_BLOB base64_decode_data_blob(TALLOC_CTX *mem_ctx, const char *s);
+void base64_decode_inplace(char *s);
+char *base64_encode_data_blob(TALLOC_CTX *mem_ctx, DATA_BLOB data);
+size_t valgrind_strlen(const char *s);
+const char *str_format_nbt_domain(TALLOC_CTX *mem_ctx, const char *s);
+BOOL add_string_to_array(TALLOC_CTX *mem_ctx,
+ const char *str, const char ***strings, int *num);
+int strcmp_safe(const char *s1, const char *s2);
+size_t ascii_len_n(const char *src, size_t n);
+char *attrib_string(TALLOC_CTX *mem_ctx, uint32_t attrib);
+BOOL set_boolean(const char *boolean_string, BOOL *boolean);
+BOOL conv_str_bool(const char * str, BOOL * val);
+BOOL conv_str_size(const char * str, uint64_t * val);
+BOOL conv_str_u64(const char * str, uint64_t * val);
+
+String list manipulation
+========================
+const char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const char *sep);
+const char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep);
+char *str_list_join(TALLOC_CTX *mem_ctx, const char **list, char seperator);
+char *str_list_join_shell(TALLOC_CTX *mem_ctx, const char **list, char sep);
+size_t str_list_length(const char **list);
+const char **str_list_copy(TALLOC_CTX *mem_ctx, const char **list);
+BOOL str_list_equal(const char **list1, const char **list2);
+const char **str_list_add(const char **list, const char *s);
+void str_list_remove(const char **list, const char *s);
+BOOL str_list_check(const char **list, const char *s);
+BOOL str_list_check_ci(const char **list, const char *s);
+
+Unicode string manipulation
+===========================
+codepoint_t toupper_w(codepoint_t val);
+codepoint_t tolower_w(codepoint_t val);
+size_t utf16_len(const void *buf);
+size_t utf16_len_n(const void *src, size_t n);
+size_t ucs2_align(const void *base_ptr, const void *p, int flags);
+int codepoint_cmpi(codepoint_t c1, codepoint_t c2);
+
+File manipulation
+=================
+char *fgets_slash(char *s2,int maxlen,XFILE *f);
+char *afdgets(int fd, TALLOC_CTX *mem_ctx, size_t hint);
+char *fd_load(int fd, size_t *size, TALLOC_CTX *mem_ctx);
+char *file_load(const char *fname, size_t *size, TALLOC_CTX *mem_ctx);
+void *map_file(const char *fname, size_t size);
+char **file_lines_load(const char *fname, int *numlines, TALLOC_CTX *mem_ctx);
+char **fd_lines_load(int fd, int *numlines, TALLOC_CTX *mem_ctx);
+void file_lines_slashcont(char **lines);
+BOOL file_save(const char *fname, const void *packet, size_t length);
+BOOL file_exists(const char *path);
+int vfdprintf(int fd, const char *format, va_list ap) _PRINTF_ATTRIBUTE(2,0);
+int fdprintf(int fd, const char *format, ...) _PRINTF_ATTRIBUTE(2,3);
+
+Data Blob
+=========
+DATA_BLOB data_blob_named(const void *p, size_t length, const char *name);
+DATA_BLOB data_blob_talloc_named(TALLOC_CTX *mem_ctx, const void *p, size_t length, const char *name);
+DATA_BLOB data_blob_talloc_reference(TALLOC_CTX *mem_ctx, DATA_BLOB *blob);
+DATA_BLOB data_blob_talloc_zero(TALLOC_CTX *mem_ctx, size_t length);
+void data_blob_free(DATA_BLOB *d);
+void data_blob_clear(DATA_BLOB *d);
+void data_blob_clear_free(DATA_BLOB *d);
+BOOL data_blob_equal(const DATA_BLOB *d1, const DATA_BLOB *d2);
+char *data_blob_hex_string(TALLOC_CTX *mem_ctx, DATA_BLOB *blob);
+DATA_BLOB data_blob_string_const(const char *str);
+DATA_BLOB data_blob_const(const void *p, size_t length);
+NTSTATUS data_blob_realloc(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, size_t length);
+NTSTATUS data_blob_append(TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
+ const void *p, size_t length);
+
+Random Utility functions
+========================
+const char *tmpdir(void);
+BOOL file_exist(const char *fname);
+time_t file_modtime(const char *fname);
+BOOL directory_exist(const char *dname);
+BOOL directory_create_or_exist(const char *dname, uid_t uid,
+ mode_t dir_perms);
+int set_blocking(int fd, BOOL set);
+void msleep(uint_t t);
+void become_daemon(BOOL Fork);
+void safe_free(void *p);
+BOOL is_myname(const char *name);
+char* get_myname(void);
+BOOL is_ipaddress(const char *str);
+uint32_t interpret_addr(const char *str);
+struct ipv4_addr interpret_addr2(const char *str);
+BOOL is_zero_ip(struct ipv4_addr ip);
+BOOL same_net(struct ipv4_addr ip1,struct ipv4_addr ip2,struct ipv4_addr mask);
+BOOL process_exists(pid_t pid);
+BOOL fcntl_lock(int fd, int op, off_t offset, off_t count, int type);
+void dump_data(int level, const uint8_t *buf,int len);
+void *smb_xmalloc(size_t size);
+void *smb_xmemdup(const void *p, size_t size);
+char *smb_xstrdup(const char *s);
+void *memdup(const void *p, size_t size);
+char *lock_path(TALLOC_CTX* mem_ctx, const char *name);
+char *lib_path(TALLOC_CTX* mem_ctx, const char *name);
+char *private_path(TALLOC_CTX* mem_ctx, const char *name);
+char *smbd_tmp_path(TALLOC_CTX *mem_ctx, const char *name);
+init_module_fn *load_samba_modules(TALLOC_CTX *mem_ctx, const char *subsystem);
+void dump_data_pw(const char *msg, const uint8_t * data, size_t len);
+BOOL all_zero(const uint8_t *ptr, uint_t size);
+void *realloc_array(void *ptr, size_t el_size, unsigned count);
+
+/* The following definitions come from lib/util/util_sock.c */
+
+void set_socket_options(int fd, const char *options);
+
+Variable substitution
+=====================
+void sub_set_context(struct substitute_context *subptr);
+void sub_set_remote_proto(const char *str);
+void sub_set_remote_arch(const char *str);
+void sub_set_user_name(const char *name);
+void standard_sub_basic(char *str,size_t len);
+char *talloc_sub_basic(TALLOC_CTX *mem_ctx, const char *smb_name, const char *str);
+char *alloc_sub_basic(const char *smb_name, const char *str);
+char *talloc_sub_specified(TALLOC_CTX *mem_ctx,
+ const char *input_string,
+ const char *username,
+ const char *domain,
+ uid_t uid,
+ gid_t gid);
+char *alloc_sub_specified(const char *input_string,
+ const char *username,
+ const char *domain,
+ uid_t uid,
+ gid_t gid);
+char *talloc_sub_advanced(TALLOC_CTX *mem_ctx,
+ int snum,
+ const char *user,
+ const char *connectpath,
+ gid_t gid,
+ const char *smb_name,
+ char *str);
+char *alloc_sub_advanced(int snum, const char *user,
+ const char *connectpath, gid_t gid,
+ const char *smb_name, char *str);
+void standard_sub_tcon(struct smbsrv_tcon *tcon, char *str, size_t len);
+char *talloc_sub_tcon(TALLOC_CTX *mem_ctx, struct smbsrv_tcon *tcon, char *str);
+char *alloc_sub_tcon(struct smbsrv_tcon *tcon, char *str);
+void standard_sub_snum(int snum, char *str, size_t len);
+
+/* The following definitions come from lib/util/fsusage.c */
+
+int sys_fsusage(const char *path, uint64_t *dfree, uint64_t *dsize);
+
+Microsoft-style filename matching
+=================================
+int ms_fnmatch(const char *pattern, const char *string, enum protocol_types protocol);
+int gen_fnmatch(const char *pattern, const char *string);
+
+Mutexes
+=======
+BOOL register_mutex_handlers(const char *name, struct mutex_ops *ops);
+
+Idtree
+======
+very efficient functions to manage mapping a id (such as a fnum) to
+a pointer. This is used for fnum and search id allocation.
+
+struct idr_context *idr_init(TALLOC_CTX *mem_ctx);
+int idr_get_new(struct idr_context *idp, void *ptr, int limit);
+int idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id, int limit);
+int idr_get_new_random(struct idr_context *idp, void *ptr, int limit);
+void *idr_find(struct idr_context *idp, int id);
+int idr_remove(struct idr_context *idp, int id);
+
+Module loading
+==============
+init_module_fn *load_modules(TALLOC_CTX *mem_ctx, const char *path);
+BOOL run_init_functions(NTSTATUS (**fns) (void));
diff --git a/source4/lib/util/byteorder.h b/source4/lib/util/byteorder.h
new file mode 100644
index 0000000000..941dee9e88
--- /dev/null
+++ b/source4/lib/util/byteorder.h
@@ -0,0 +1,224 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Byte handling
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _BYTEORDER_H
+#define _BYTEORDER_H
+
+/*
+ This file implements macros for machine independent short and
+ int manipulation
+
+Here is a description of this file that I emailed to the samba list once:
+
+> I am confused about the way that byteorder.h works in Samba. I have
+> looked at it, and I would have thought that you might make a distinction
+> between LE and BE machines, but you only seem to distinguish between 386
+> and all other architectures.
+>
+> Can you give me a clue?
+
+sure.
+
+The distinction between 386 and other architectures is only there as
+an optimisation. You can take it out completely and it will make no
+difference. The routines (macros) in byteorder.h are totally byteorder
+independent. The 386 optimsation just takes advantage of the fact that
+the x86 processors don't care about alignment, so we don't have to
+align ints on int boundaries etc. If there are other processors out
+there that aren't alignment sensitive then you could also define
+CAREFUL_ALIGNMENT=0 on those processors as well.
+
+Ok, now to the macros themselves. I'll take a simple example, say we
+want to extract a 2 byte integer from a SMB packet and put it into a
+type called uint16_t that is in the local machines byte order, and you
+want to do it with only the assumption that uint16_t is _at_least_ 16
+bits long (this last condition is very important for architectures
+that don't have any int types that are 2 bytes long)
+
+You do this:
+
+#define CVAL(buf,pos) (((uint8_t *)(buf))[pos])
+#define PVAL(buf,pos) ((uint_t)CVAL(buf,pos))
+#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
+
+then to extract a uint16_t value at offset 25 in a buffer you do this:
+
+char *buffer = foo_bar();
+uint16_t xx = SVAL(buffer,25);
+
+We are using the byteoder independence of the ANSI C bitshifts to do
+the work. A good optimising compiler should turn this into efficient
+code, especially if it happens to have the right byteorder :-)
+
+I know these macros can be made a bit tidier by removing some of the
+casts, but you need to look at byteorder.h as a whole to see the
+reasoning behind them. byteorder.h defines the following macros:
+
+SVAL(buf,pos) - extract a 2 byte SMB value
+IVAL(buf,pos) - extract a 4 byte SMB value
+SVALS(buf,pos) signed version of SVAL()
+IVALS(buf,pos) signed version of IVAL()
+
+SSVAL(buf,pos,val) - put a 2 byte SMB value into a buffer
+SIVAL(buf,pos,val) - put a 4 byte SMB value into a buffer
+SSVALS(buf,pos,val) - signed version of SSVAL()
+SIVALS(buf,pos,val) - signed version of SIVAL()
+
+RSVAL(buf,pos) - like SVAL() but for NMB byte ordering
+RSVALS(buf,pos) - like SVALS() but for NMB byte ordering
+RIVAL(buf,pos) - like IVAL() but for NMB byte ordering
+RIVALS(buf,pos) - like IVALS() but for NMB byte ordering
+RSSVAL(buf,pos,val) - like SSVAL() but for NMB ordering
+RSIVAL(buf,pos,val) - like SIVAL() but for NMB ordering
+RSIVALS(buf,pos,val) - like SIVALS() but for NMB ordering
+
+it also defines lots of intermediate macros, just ignore those :-)
+
+*/
+
+
+/*
+ on powerpc we can use the magic instructions to load/store
+ in little endian
+*/
+#if (defined(__powerpc__) && defined(__GNUC__))
+static __inline__ uint16_t ld_le16(const uint16_t *addr)
+{
+ uint16_t val;
+ __asm__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr));
+ return val;
+}
+
+static __inline__ void st_le16(uint16_t *addr, const uint16_t val)
+{
+ __asm__ ("sthbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr));
+}
+
+static __inline__ uint32_t ld_le32(const uint32_t *addr)
+{
+ uint32_t val;
+ __asm__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr));
+ return val;
+}
+
+static __inline__ void st_le32(uint32_t *addr, const uint32_t val)
+{
+ __asm__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr));
+}
+#define HAVE_ASM_BYTEORDER 1
+#endif
+
+
+
+#undef CAREFUL_ALIGNMENT
+
+/* we know that the 386 can handle misalignment and has the "right"
+ byteorder */
+#if defined(__i386__)
+#define CAREFUL_ALIGNMENT 0
+#endif
+
+#ifndef CAREFUL_ALIGNMENT
+#define CAREFUL_ALIGNMENT 1
+#endif
+
+#define CVAL(buf,pos) ((uint_t)(((const uint8_t *)(buf))[pos]))
+#define CVAL_NC(buf,pos) (((uint8_t *)(buf))[pos]) /* Non-const version of CVAL */
+#define PVAL(buf,pos) (CVAL(buf,pos))
+#define SCVAL(buf,pos,val) (CVAL_NC(buf,pos) = (val))
+
+#if HAVE_ASM_BYTEORDER
+
+#define _PTRPOS(buf,pos) (((const uint8_t *)buf)+(pos))
+#define SVAL(buf,pos) ld_le16((const uint16_t *)_PTRPOS(buf,pos))
+#define IVAL(buf,pos) ld_le32((const uint32_t *)_PTRPOS(buf,pos))
+#define SSVAL(buf,pos,val) st_le16((uint16_t *)_PTRPOS(buf,pos), val)
+#define SIVAL(buf,pos,val) st_le32((uint32_t *)_PTRPOS(buf,pos), val)
+#define SVALS(buf,pos) ((int16_t)SVAL(buf,pos))
+#define IVALS(buf,pos) ((int32_t)IVAL(buf,pos))
+#define SSVALS(buf,pos,val) SSVAL((buf),(pos),((int16_t)(val)))
+#define SIVALS(buf,pos,val) SIVAL((buf),(pos),((int32_t)(val)))
+
+#elif CAREFUL_ALIGNMENT
+
+#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
+#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
+#define SSVALX(buf,pos,val) (CVAL_NC(buf,pos)=(uint8_t)((val)&0xFF),CVAL_NC(buf,pos+1)=(uint8_t)((val)>>8))
+#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
+#define SVALS(buf,pos) ((int16_t)SVAL(buf,pos))
+#define IVALS(buf,pos) ((int32_t)IVAL(buf,pos))
+#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((uint16_t)(val)))
+#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32_t)(val)))
+#define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16_t)(val)))
+#define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32_t)(val)))
+
+#else /* CAREFUL_ALIGNMENT */
+
+/* this handles things for architectures like the 386 that can handle
+ alignment errors */
+/*
+ WARNING: This section is dependent on the length of int16_t and int32_t
+ being correct
+*/
+
+/* get single value from an SMB buffer */
+#define SVAL(buf,pos) (*(const uint16_t *)((const char *)(buf) + (pos)))
+#define SVAL_NC(buf,pos) (*(uint16_t *)((char *)(buf) + (pos))) /* Non const version of above. */
+#define IVAL(buf,pos) (*(const uint32_t *)((const char *)(buf) + (pos)))
+#define IVAL_NC(buf,pos) (*(uint32_t *)((char *)(buf) + (pos))) /* Non const version of above. */
+#define SVALS(buf,pos) (*(const int16_t *)((const char *)(buf) + (pos)))
+#define SVALS_NC(buf,pos) (*(int16_t *)((char *)(buf) + (pos))) /* Non const version of above. */
+#define IVALS(buf,pos) (*(const int32_t *)((const char *)(buf) + (pos)))
+#define IVALS_NC(buf,pos) (*(int32_t *)((char *)(buf) + (pos))) /* Non const version of above. */
+
+/* store single value in an SMB buffer */
+#define SSVAL(buf,pos,val) SVAL_NC(buf,pos)=((uint16_t)(val))
+#define SIVAL(buf,pos,val) IVAL_NC(buf,pos)=((uint32_t)(val))
+#define SSVALS(buf,pos,val) SVALS_NC(buf,pos)=((int16_t)(val))
+#define SIVALS(buf,pos,val) IVALS_NC(buf,pos)=((int32_t)(val))
+
+#endif /* CAREFUL_ALIGNMENT */
+
+/* now the reverse routines - these are used in nmb packets (mostly) */
+#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
+#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
+
+#define RSVAL(buf,pos) SREV(SVAL(buf,pos))
+#define RSVALS(buf,pos) SREV(SVALS(buf,pos))
+#define RIVAL(buf,pos) IREV(IVAL(buf,pos))
+#define RIVALS(buf,pos) IREV(IVALS(buf,pos))
+#define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
+#define RSSVALS(buf,pos,val) SSVALS(buf,pos,SREV(val))
+#define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
+#define RSIVALS(buf,pos,val) SIVALS(buf,pos,IREV(val))
+
+/* Alignment macros. */
+#define ALIGN4(p,base) ((p) + ((4 - (PTR_DIFF((p), (base)) & 3)) & 3))
+#define ALIGN2(p,base) ((p) + ((2 - (PTR_DIFF((p), (base)) & 1)) & 1))
+
+
+/* macros for accessing SMB protocol elements */
+#define VWV(vwv) ((vwv)*2)
+
+/* 64 bit macros */
+#define SBVAL(p, ofs, v) (SIVAL(p,ofs,(v)&0xFFFFFFFF), SIVAL(p,(ofs)+4,((uint64_t)(v))>>32))
+#define BVAL(p, ofs) (IVAL(p,ofs) | (((uint64_t)IVAL(p,(ofs)+4)) << 32))
+
+#endif /* _BYTEORDER_H */
diff --git a/source4/lib/util/capability.c b/source4/lib/util/capability.c
new file mode 100644
index 0000000000..0cebd33303
--- /dev/null
+++ b/source4/lib/util/capability.c
@@ -0,0 +1,112 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1998-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ capabilities fns - will be needed when we enable kernel oplocks
+*/
+
+#include "includes.h"
+#include "system/network.h"
+#include "system/wait.h"
+#include "system/filesys.h"
+
+
+#if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
+/**************************************************************************
+ Try and abstract process capabilities (for systems that have them).
+****************************************************************************/
+static BOOL set_process_capability( uint32_t cap_flag, BOOL enable )
+{
+ if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
+ cap_t cap = cap_get_proc();
+
+ if (cap == NULL) {
+ DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
+ strerror(errno)));
+ return False;
+ }
+
+ if(enable)
+ cap->cap_effective |= CAP_NETWORK_MGT;
+ else
+ cap->cap_effective &= ~CAP_NETWORK_MGT;
+
+ if (cap_set_proc(cap) == -1) {
+ DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
+ strerror(errno)));
+ cap_free(cap);
+ return False;
+ }
+
+ cap_free(cap);
+
+ DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
+ }
+ return True;
+}
+
+/**************************************************************************
+ Try and abstract inherited process capabilities (for systems that have them).
+****************************************************************************/
+
+static BOOL set_inherited_process_capability( uint32_t cap_flag, BOOL enable )
+{
+ if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
+ cap_t cap = cap_get_proc();
+
+ if (cap == NULL) {
+ DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n",
+ strerror(errno)));
+ return False;
+ }
+
+ if(enable)
+ cap->cap_inheritable |= CAP_NETWORK_MGT;
+ else
+ cap->cap_inheritable &= ~CAP_NETWORK_MGT;
+
+ if (cap_set_proc(cap) == -1) {
+ DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n",
+ strerror(errno)));
+ cap_free(cap);
+ return False;
+ }
+
+ cap_free(cap);
+
+ DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
+ }
+ return True;
+}
+#endif
+
+/****************************************************************************
+ Gain the oplock capability from the kernel if possible.
+****************************************************************************/
+
+void oplock_set_capability(BOOL this_process, BOOL inherit)
+{
+#if HAVE_KERNEL_OPLOCKS_IRIX
+ set_process_capability(KERNEL_OPLOCK_CAPABILITY,this_process);
+ set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY,inherit);
+#endif
+}
+
diff --git a/source4/lib/util/config.mk b/source4/lib/util/config.mk
new file mode 100644
index 0000000000..79e145775d
--- /dev/null
+++ b/source4/lib/util/config.mk
@@ -0,0 +1,34 @@
+[SUBSYSTEM::LIBBASIC]
+PRIVATE_PROTO_HEADER = util_proto.h
+PUBLIC_HEADERS = util.h
+OBJ_FILES = xfile.o \
+ debug.o \
+ fault.o \
+ signal.o \
+ system.o \
+ time.o \
+ genrand.o \
+ dprintf.o \
+ util_str.o \
+ util_strlist.o \
+ util_unistr.o \
+ util_file.o \
+ data_blob.o \
+ util.o \
+ util_sock.o \
+ substitute.o \
+ fsusage.o \
+ ms_fnmatch.o \
+ select.o \
+ mutex.o \
+ idtree.o \
+ module.o
+REQUIRED_SUBSYSTEMS = \
+ CHARSET LIBREPLACE LIBCRYPTO EXT_LIB_DL LIBTALLOC \
+ SOCKET_WRAPPER CONFIG
+
+[SUBSYSTEM::PIDFILE]
+OBJ_FILES = pidfile.o
+
+[SUBSYSTEM::UNIX_PRIVS]
+OBJ_FILES = unix_privs.o
diff --git a/source4/lib/util/data_blob.c b/source4/lib/util/data_blob.c
new file mode 100644
index 0000000000..c6471fbf54
--- /dev/null
+++ b/source4/lib/util/data_blob.c
@@ -0,0 +1,209 @@
+/*
+ Unix SMB/CIFS implementation.
+ Easy management of byte-length data
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Andrew Bartlett 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*******************************************************************
+ 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_named(const void *p, size_t length, const char *name)
+{
+ DATA_BLOB ret;
+
+ if (p == NULL && length == 0) {
+ ZERO_STRUCT(ret);
+ return ret;
+ }
+
+ if (p) {
+ ret.data = talloc_memdup(NULL, p, length);
+ } else {
+ ret.data = talloc_size(NULL, length);
+ }
+ if (ret.data == NULL) {
+ ret.length = 0;
+ return ret;
+ }
+ talloc_set_name_const(ret.data, name);
+ ret.length = length;
+ return ret;
+}
+
+/*******************************************************************
+ construct a data blob, using supplied TALLOC_CTX
+*******************************************************************/
+DATA_BLOB data_blob_talloc_named(TALLOC_CTX *mem_ctx, const void *p, size_t length, const char *name)
+{
+ DATA_BLOB ret = data_blob_named(p, length, name);
+
+ if (ret.data) {
+ talloc_steal(mem_ctx, ret.data);
+ }
+ return ret;
+}
+
+
+/*******************************************************************
+ reference a data blob, to the supplied TALLOC_CTX.
+ Returns a NULL DATA_BLOB on failure
+*******************************************************************/
+DATA_BLOB data_blob_talloc_reference(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
+{
+ DATA_BLOB ret = *blob;
+
+ ret.data = talloc_reference(mem_ctx, blob->data);
+
+ if (!ret.data) {
+ return data_blob(NULL, 0);
+ }
+ return ret;
+}
+
+/*******************************************************************
+ construct a zero data blob, using supplied TALLOC_CTX.
+ use this sparingly as it initialises data - better to initialise
+ yourself if you want specific data in the blob
+*******************************************************************/
+DATA_BLOB data_blob_talloc_zero(TALLOC_CTX *mem_ctx, size_t length)
+{
+ DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, length);
+ data_blob_clear(&blob);
+ return blob;
+}
+
+/*******************************************************************
+free a data blob
+*******************************************************************/
+void data_blob_free(DATA_BLOB *d)
+{
+ if (d) {
+ talloc_free(d->data);
+ d->data = NULL;
+ d->length = 0;
+ }
+}
+
+/*******************************************************************
+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);
+}
+
+
+/*******************************************************************
+check if two data blobs are equal
+*******************************************************************/
+BOOL data_blob_equal(const DATA_BLOB *d1, const DATA_BLOB *d2)
+{
+ if (d1->length != d2->length) {
+ return False;
+ }
+ if (d1->data == d2->data) {
+ return True;
+ }
+ if (d1->data == NULL || d2->data == NULL) {
+ return False;
+ }
+ if (memcmp(d1->data, d2->data, d1->length) == 0) {
+ return True;
+ }
+ return False;
+}
+
+/*******************************************************************
+print the data_blob as hex string
+*******************************************************************/
+char *data_blob_hex_string(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
+{
+ int i;
+ char *hex_string;
+
+ hex_string = talloc_array(mem_ctx, char, (blob->length*2)+1);
+ if (!hex_string) {
+ return NULL;
+ }
+
+ for (i = 0; i < blob->length; i++)
+ slprintf(&hex_string[i*2], 3, "%02X", blob->data[i]);
+
+ return hex_string;
+}
+
+/*
+ useful for constructing data blobs in test suites, while
+ avoiding const warnings
+*/
+DATA_BLOB data_blob_string_const(const char *str)
+{
+ DATA_BLOB blob;
+ blob.data = discard_const(str);
+ blob.length = strlen(str);
+ return blob;
+}
+
+DATA_BLOB data_blob_const(const void *p, size_t length)
+{
+ DATA_BLOB blob;
+ blob.data = discard_const(p);
+ blob.length = length;
+ return blob;
+}
+
+
+/*
+ realloc a data_blob
+*/
+NTSTATUS data_blob_realloc(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, size_t length)
+{
+ blob->data = talloc_realloc_size(mem_ctx, blob->data, length);
+ NT_STATUS_HAVE_NO_MEMORY(blob->data);
+ blob->length = length;
+ return NT_STATUS_OK;
+}
+
+/*
+ append some data to a data blob
+*/
+NTSTATUS data_blob_append(TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
+ const void *p, size_t length)
+{
+ blob->data = talloc_realloc_size(mem_ctx, blob->data,
+ blob->length + length);
+ NT_STATUS_HAVE_NO_MEMORY(blob->data);
+ memcpy(blob->data + blob->length, p, length);
+ blob->length += length;
+ return NT_STATUS_OK;
+}
+
diff --git a/source4/lib/util/debug.c b/source4/lib/util/debug.c
new file mode 100644
index 0000000000..9df6e573b0
--- /dev/null
+++ b/source4/lib/util/debug.c
@@ -0,0 +1,205 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba debug functions
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) James J Myers 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "dynconfig.h"
+
+/* this global variable determines what messages are printed */
+int DEBUGLEVEL;
+
+
+/* the registered mutex handlers */
+static struct {
+ const char *name;
+ struct debug_ops ops;
+} debug_handlers;
+
+/* state variables for the debug system */
+static struct {
+ int fd;
+ enum debug_logtype logtype;
+ const char *prog_name;
+} state;
+
+/*
+ the backend for debug messages. Note that the DEBUG() macro has already
+ ensured that the log level has been met before this is called
+*/
+void do_debug_header(int level, const char *location, const char *func)
+{
+ log_timestring(level, location, func);
+ log_task_id();
+}
+
+/*
+ the backend for debug messages. Note that the DEBUG() macro has already
+ ensured that the log level has been met before this is called
+*/
+void do_debug(const char *format, ...)
+{
+ va_list ap;
+ char *s = NULL;
+
+ if (state.fd == 0) {
+ reopen_logs();
+ }
+
+ if (state.fd <= 0) return;
+
+ va_start(ap, format);
+ vasprintf(&s, format, ap);
+ va_end(ap);
+
+ write(state.fd, s, strlen(s));
+ free(s);
+}
+
+/*
+ reopen the log file (usually called because the log file name might have changed)
+*/
+void reopen_logs(void)
+{
+ const char *logfile = lp_logfile();
+ char *fname = NULL;
+ int old_fd = state.fd;
+
+ switch (state.logtype) {
+ case DEBUG_STDOUT:
+ state.fd = 1;
+ break;
+
+ case DEBUG_STDERR:
+ state.fd = 2;
+ break;
+
+ case DEBUG_FILE:
+ if ((*logfile) == '/') {
+ fname = strdup(logfile);
+ } else {
+ asprintf(&fname, "%s/%s.log", dyn_LOGFILEBASE, state.prog_name);
+ }
+ if (fname) {
+ int newfd = open(fname, O_CREAT|O_APPEND|O_WRONLY, 0600);
+ if (newfd == -1) {
+ DEBUG(1, ("Failed to open new logfile: %s\n", fname));
+ } else {
+ state.fd = newfd;
+ }
+ free(fname);
+ } else {
+ DEBUG(1, ("Failed to find name for file-based logfile!\n"));
+ }
+
+ break;
+ }
+
+ if (old_fd > 2) {
+ close(old_fd);
+ }
+}
+
+/*
+ control the name of the logfile and whether logging will be to stdout, stderr
+ or a file
+*/
+void setup_logging(const char *prog_name, enum debug_logtype new_logtype)
+{
+ if (state.logtype < new_logtype) {
+ state.logtype = new_logtype;
+ }
+ if (prog_name) {
+ state.prog_name = prog_name;
+ }
+ reopen_logs();
+}
+
+/*
+ return a string constant containing n tabs
+ no more than 10 tabs are returned
+*/
+const char *do_debug_tab(uint_t n)
+{
+ const char *tabs[] = {"", "\t", "\t\t", "\t\t\t", "\t\t\t\t", "\t\t\t\t\t",
+ "\t\t\t\t\t\t", "\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t",
+ "\t\t\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t\t\t"};
+ return tabs[MIN(n, 10)];
+}
+
+
+/*
+ log/print suspicious usage - print comments and backtrace
+*/
+void log_suspicious_usage(const char *from, const char *info)
+{
+ if (debug_handlers.ops.log_suspicious_usage) {
+ debug_handlers.ops.log_suspicious_usage(from, info);
+ }
+}
+void print_suspicious_usage(const char* from, const char* info)
+{
+ if (debug_handlers.ops.print_suspicious_usage) {
+ debug_handlers.ops.print_suspicious_usage(from, info);
+ }
+}
+
+void log_timestring(int level, const char *location, const char *func)
+{
+ char *t = NULL;
+ char *s = NULL;
+
+ if (state.logtype != DEBUG_FILE) return;
+
+ t = timestring(NULL, time(NULL));
+ if (!t) return;
+
+ asprintf(&s, "[%s, %d %s:%s()]\n", t, level, location, func);
+ talloc_free(t);
+ if (!s) return;
+
+ write(state.fd, s, strlen(s));
+ free(s);
+}
+
+uint32_t get_task_id(void)
+{
+ if (debug_handlers.ops.get_task_id) {
+ return debug_handlers.ops.get_task_id();
+ }
+ return getpid();
+}
+
+void log_task_id(void)
+{
+ if (debug_handlers.ops.log_task_id) {
+ debug_handlers.ops.log_task_id(state.fd);
+ }
+}
+
+/*
+ register a set of debug handlers.
+*/
+void register_debug_handlers(const char *name, struct debug_ops *ops)
+{
+ debug_handlers.name = name;
+ debug_handlers.ops = *ops;
+}
diff --git a/source4/lib/util/debug.h b/source4/lib/util/debug.h
new file mode 100644
index 0000000000..8ff937e7b9
--- /dev/null
+++ b/source4/lib/util/debug.h
@@ -0,0 +1,66 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba debug defines
+ Copyright (C) Andrew Tridgell 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* If we have these macros, we can add additional info to the header. */
+
+#ifdef HAVE_FUNCTION_MACRO
+#define FUNCTION_MACRO (__FUNCTION__)
+#else
+#define FUNCTION_MACRO ("")
+#endif
+
+/* the debug operations structure - contains function pointers to
+ various debug implementations of each operation */
+struct debug_ops {
+ /* function to log (using DEBUG) suspicious usage of data structure */
+ void (*log_suspicious_usage)(const char* from, const char* info);
+
+ /* function to log (using printf) suspicious usage of data structure.
+ * To be used in circumstances when using DEBUG would cause loop. */
+ void (*print_suspicious_usage)(const char* from, const char* info);
+
+ /* function to return process/thread id */
+ uint32_t (*get_task_id)(void);
+
+ /* function to log process/thread id */
+ void (*log_task_id)(int fd);
+};
+
+void do_debug_header(int level, const char *location, const char *func);
+void do_debug(const char *, ...) PRINTF_ATTRIBUTE(1,2);
+
+extern int DEBUGLEVEL;
+
+#define DEBUGLVL(level) ((level) <= DEBUGLEVEL)
+#define _DEBUG(level, body, header) do { \
+ if (DEBUGLVL(level)) { \
+ if (header) { \
+ do_debug_header(level, __location__, FUNCTION_MACRO); \
+ } \
+ do_debug body; \
+ } \
+} while (0)
+#define DEBUG(level, body) _DEBUG(level, body, True)
+#define DEBUGADD(level, body) _DEBUG(level, body, False)
+#define DEBUGC(class, level, body) DEBUG(level, body)
+#define DEBUGADDC(class, level, body) DEBUGADD(level, body)
+#define DEBUGTAB(n) do_debug_tab(n)
+
+enum debug_logtype {DEBUG_STDOUT = 0, DEBUG_FILE = 1, DEBUG_STDERR = 2};
diff --git a/source4/lib/util/dprintf.c b/source4/lib/util/dprintf.c
new file mode 100644
index 0000000000..64227148fd
--- /dev/null
+++ b/source4/lib/util/dprintf.c
@@ -0,0 +1,107 @@
+/*
+ Unix SMB/CIFS implementation.
+ display print functions
+ Copyright (C) Andrew Tridgell 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+/*
+ this module provides functions for printing internal strings in the "display charset"
+ This charset may be quite different from the chosen unix charset
+
+ Eventually these functions will need to take care of column count constraints
+
+ The d_ prefix on print functions in Samba refers to the display character set
+ conversion
+*/
+
+#include "includes.h"
+
+int d_vfprintf(FILE *f, const char *format, va_list ap) _PRINTF_ATTRIBUTE(2,0)
+{
+ char *p, *p2;
+ int ret, maxlen, clen;
+ va_list ap2;
+
+ /* do any message translations */
+ VA_COPY(ap2, ap);
+
+ ret = vasprintf(&p, format, ap2);
+
+ if (ret <= 0) return ret;
+
+ /* now we have the string in unix format, convert it to the display
+ charset, but beware of it growing */
+ maxlen = ret*2;
+again:
+ p2 = malloc(maxlen);
+ if (!p2) {
+ SAFE_FREE(p);
+ return -1;
+ }
+ clen = convert_string(CH_UNIX, CH_DISPLAY, p, ret, p2, maxlen);
+
+ if (clen >= maxlen) {
+ /* it didn't fit - try a larger buffer */
+ maxlen *= 2;
+ SAFE_FREE(p2);
+ goto again;
+ }
+
+ /* good, its converted OK */
+ SAFE_FREE(p);
+ ret = fwrite(p2, 1, clen, f);
+ SAFE_FREE(p2);
+
+ return ret;
+}
+
+
+int d_fprintf(FILE *f, const char *format, ...) _PRINTF_ATTRIBUTE(2,3)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, format);
+ ret = d_vfprintf(f, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+static FILE *outfile;
+
+int d_printf(const char *format, ...) _PRINTF_ATTRIBUTE(1,2)
+{
+ int ret;
+ va_list ap;
+
+ if (!outfile) outfile = stdout;
+
+ va_start(ap, format);
+ ret = d_vfprintf(outfile, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+/* interactive programs need a way of tell d_*() to write to stderr instead
+ of stdout */
+void display_set_stderr(void)
+{
+ outfile = stderr;
+}
diff --git a/source4/lib/util/fault.c b/source4/lib/util/fault.c
new file mode 100644
index 0000000000..3670575dcc
--- /dev/null
+++ b/source4/lib/util/fault.c
@@ -0,0 +1,213 @@
+/*
+ Unix SMB/CIFS implementation.
+ Critical Fault handling
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "version.h"
+#include "system/wait.h"
+#include "system/filesys.h"
+
+/* the registered fault handler */
+static struct {
+ const char *name;
+ void (*fault_handler)(int sig);
+} fault_handlers;
+
+static const char *progname;
+
+#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
+#define BACKTRACE_STACK_SIZE 64
+#elif HAVE_LIBEXC_H
+#include <libexc.h>
+#endif
+
+void call_backtrace(void)
+{
+#ifdef HAVE_BACKTRACE
+#define BACKTRACE_STACK_SIZE 64
+ void *backtrace_stack[BACKTRACE_STACK_SIZE];
+ size_t backtrace_size;
+ char **backtrace_strings;
+
+ /* 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++)
+ DEBUGADD(0, (" #%u %s\n", i, backtrace_strings[i]));
+
+ /* Leak the backtrace_strings, rather than risk what free() might do */
+ }
+
+#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
+}
+
+/*******************************************************************
+ Something really nasty happened - panic !
+********************************************************************/
+void smb_panic(const char *why)
+{
+ const char *cmd = lp_panic_action();
+ int result;
+
+ if (cmd && *cmd) {
+ char pidstr[20];
+ char cmdstring[200];
+ safe_strcpy(cmdstring, cmd, sizeof(cmdstring));
+ snprintf(pidstr, sizeof(pidstr), "%u", getpid());
+ all_string_sub(cmdstring, "%PID%", pidstr, sizeof(cmdstring));
+ if (progname) {
+ all_string_sub(cmdstring, "%PROG%", progname, sizeof(cmdstring));
+ }
+ DEBUG(0, ("smb_panic(): calling panic action [%s]\n", cmdstring));
+ result = system(cmdstring);
+
+ if (result == -1)
+ DEBUG(0, ("smb_panic(): fork failed in panic action: %s\n",
+ strerror(errno)));
+ else
+ DEBUG(0, ("smb_panic(): action returned status %d\n",
+ WEXITSTATUS(result)));
+ }
+ DEBUG(0,("PANIC: %s\n", why));
+
+ call_backtrace();
+
+#ifdef SIGABRT
+ CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
+#endif
+ abort();
+}
+
+/*******************************************************************
+report a fault
+********************************************************************/
+static void fault_report(int sig)
+{
+ static int counter;
+
+ if (counter) _exit(1);
+
+ DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"));
+ DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)getpid(),SAMBA_VERSION_STRING));
+ DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n"));
+ DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"));
+
+ smb_panic("internal error");
+
+ exit(1);
+}
+
+/****************************************************************************
+catch serious errors
+****************************************************************************/
+static void sig_fault(int sig)
+{
+ if (fault_handlers.fault_handler) {
+ /* we have a fault handler, call it. It may not return. */
+ fault_handlers.fault_handler(sig);
+ }
+ /* If it returns or doean't exist, use regular reporter */
+ fault_report(sig);
+}
+
+/*******************************************************************
+setup our fault handlers
+********************************************************************/
+void fault_setup(const char *pname)
+{
+ if (progname == NULL) {
+ progname = pname;
+ }
+#ifdef SIGSEGV
+ CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault);
+#endif
+#ifdef SIGBUS
+ CatchSignal(SIGBUS,SIGNAL_CAST sig_fault);
+#endif
+#ifdef SIGABRT
+ CatchSignal(SIGABRT,SIGNAL_CAST sig_fault);
+#endif
+#ifdef SIGFPE
+ CatchSignal(SIGFPE,SIGNAL_CAST sig_fault);
+#endif
+}
+
+/*
+ register a fault handler.
+ Should only be called once in the execution of smbd.
+*/
+BOOL register_fault_handler(const char *name, void (*fault_handler)(int sig))
+{
+ if (fault_handlers.name != NULL) {
+ /* it's already registered! */
+ DEBUG(2,("fault handler '%s' already registered - failed '%s'\n",
+ fault_handlers.name, name));
+ return False;
+ }
+
+ fault_handlers.name = name;
+ fault_handlers.fault_handler = fault_handler;
+
+ DEBUG(2,("fault handler '%s' registered\n", name));
+ return True;
+}
diff --git a/source4/lib/util/fsusage.c b/source4/lib/util/fsusage.c
new file mode 100644
index 0000000000..f817672544
--- /dev/null
+++ b/source4/lib/util/fsusage.c
@@ -0,0 +1,149 @@
+/*
+ Unix SMB/CIFS implementation.
+ functions to calculate the free disk space
+ Copyright (C) Andrew Tridgell 1998-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+
+
+/* Return the number of TOSIZE-byte blocks used by
+ BLOCKS FROMSIZE-byte blocks, rounding away from zero.
+*/
+static uint64_t adjust_blocks(uint64_t blocks, uint64_t fromsize, uint64_t tosize)
+{
+ if (fromsize == tosize) /* e.g., from 512 to 512 */
+ return blocks;
+ else if (fromsize > tosize) /* e.g., from 2048 to 512 */
+ return blocks * (fromsize / tosize);
+ else /* e.g., from 256 to 512 */
+ return (blocks + 1) / (tosize / fromsize);
+}
+
+/* this does all of the system specific guff to get the free disk space.
+ It is derived from code in the GNU fileutils package, but has been
+ considerably mangled for use here
+
+ results are returned in *dfree and *dsize, in 512 byte units
+*/
+int sys_fsusage(const char *path, uint64_t *dfree, uint64_t *dsize)
+{
+#ifdef STAT_STATFS3_OSF1
+#define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_fsize, (uint64_t)512)
+ struct statfs fsd;
+
+ if (statfs (path, &fsd, sizeof (struct statfs)) != 0)
+ return -1;
+#endif /* STAT_STATFS3_OSF1 */
+
+#ifdef STAT_STATFS2_FS_DATA /* Ultrix */
+#define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)1024, (uint64_t)512)
+ struct fs_data fsd;
+
+ if (statfs (path, &fsd) != 1)
+ return -1;
+
+ (*dsize) = CONVERT_BLOCKS (fsd.fd_req.btot);
+ (*dfree) = CONVERT_BLOCKS (fsd.fd_req.bfreen);
+#endif /* STAT_STATFS2_FS_DATA */
+
+#ifdef STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX */
+#define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_bsize, (uint64_t)512)
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+
+#ifdef STATFS_TRUNCATES_BLOCK_COUNTS
+ /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
+ struct statfs are truncated to 2GB. These conditions detect that
+ truncation, presumably without botching the 4.1.1 case, in which
+ the values are not truncated. The correct counts are stored in
+ undocumented spare fields. */
+ if (fsd.f_blocks == 0x1fffff && fsd.f_spare[0] > 0) {
+ fsd.f_blocks = fsd.f_spare[0];
+ fsd.f_bfree = fsd.f_spare[1];
+ fsd.f_bavail = fsd.f_spare[2];
+ }
+#endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
+#endif /* STAT_STATFS2_BSIZE */
+
+
+#ifdef STAT_STATFS2_FSIZE /* 4.4BSD */
+#define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_fsize, (uint64_t)512)
+
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+#endif /* STAT_STATFS2_FSIZE */
+
+#ifdef STAT_STATFS4 /* SVR3, Dynix, Irix, AIX */
+# if _AIX || defined(_CRAY)
+# define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_bsize, (uint64_t)512)
+# ifdef _CRAY
+# define f_bavail f_bfree
+# endif
+# else
+# define CONVERT_BLOCKS(B) ((uint64_t)B)
+# ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx */
+# ifndef DOLPHIN /* DOLPHIN 3.8.alfa/7.18 has f_bavail */
+# define f_bavail f_bfree
+# endif
+# endif
+# endif
+
+ struct statfs fsd;
+
+ if (statfs (path, &fsd, sizeof fsd, 0) < 0)
+ return -1;
+ /* Empirically, the block counts on most SVR3 and SVR3-derived
+ systems seem to always be in terms of 512-byte blocks,
+ no matter what value f_bsize has. */
+
+#endif /* STAT_STATFS4 */
+
+#if defined(STAT_STATVFS) || defined(STAT_STATVFS64) /* SVR4 */
+# define CONVERT_BLOCKS(B) \
+ adjust_blocks ((uint64_t)(B), fsd.f_frsize ? (uint64_t)fsd.f_frsize : (uint64_t)fsd.f_bsize, (uint64_t)512)
+
+#ifdef STAT_STATVFS64
+ struct statvfs64 fsd;
+ if (statvfs64(path, &fsd) < 0) return -1;
+#else
+ struct statvfs fsd;
+ if (statvfs(path, &fsd) < 0) return -1;
+#endif
+
+ /* f_frsize isn't guaranteed to be supported. */
+
+#endif /* STAT_STATVFS */
+
+#ifndef CONVERT_BLOCKS
+ /* we don't have any dfree code! */
+ return -1;
+#else
+#if !defined(STAT_STATFS2_FS_DATA)
+ /* !Ultrix */
+ (*dsize) = CONVERT_BLOCKS (fsd.f_blocks);
+ (*dfree) = CONVERT_BLOCKS (fsd.f_bavail);
+#endif /* not STAT_STATFS2_FS_DATA */
+#endif
+
+ return 0;
+}
diff --git a/source4/lib/util/genrand.c b/source4/lib/util/genrand.c
new file mode 100644
index 0000000000..1149314d0b
--- /dev/null
+++ b/source4/lib/util/genrand.c
@@ -0,0 +1,314 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Functions to create reasonable random numbers for crypto use.
+
+ Copyright (C) Jeremy Allison 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "system/iconv.h"
+#include "system/filesys.h"
+#include "lib/crypto/crypto.h"
+
+static unsigned char hash[258];
+static uint32_t counter;
+
+static BOOL done_reseed = False;
+static void (*reseed_callback)(int *newseed);
+
+/****************************************************************
+ Copy any user given reseed data.
+*****************************************************************/
+
+void set_rand_reseed_callback(void (*fn)(int *))
+{
+ reseed_callback = fn;
+ set_need_random_reseed();
+}
+
+void set_need_random_reseed(void)
+{
+ done_reseed = False;
+}
+
+static void get_rand_reseed_data(int *reseed_data)
+{
+ if (reseed_callback) {
+ reseed_callback(reseed_data);
+ } else {
+ *reseed_data = 0;
+ }
+}
+
+/****************************************************************
+ Setup the seed.
+*****************************************************************/
+
+static void seed_random_stream(unsigned char *seedval, size_t seedlen)
+{
+ unsigned char j = 0;
+ size_t ind;
+
+ for (ind = 0; ind < 256; ind++)
+ hash[ind] = (unsigned char)ind;
+
+ for( ind = 0; ind < 256; ind++) {
+ unsigned char tc;
+
+ j += (hash[ind] + seedval[ind%seedlen]);
+
+ tc = hash[ind];
+ hash[ind] = hash[j];
+ hash[j] = tc;
+ }
+
+ hash[256] = 0;
+ hash[257] = 0;
+}
+
+/****************************************************************
+ Get datasize bytes worth of random data.
+*****************************************************************/
+
+static void get_random_stream(unsigned char *data, size_t datasize)
+{
+ unsigned char index_i = hash[256];
+ unsigned char index_j = hash[257];
+ size_t ind;
+
+ for( ind = 0; ind < datasize; ind++) {
+ unsigned char tc;
+ unsigned char t;
+
+ index_i++;
+ index_j += hash[index_i];
+
+ tc = hash[index_i];
+ hash[index_i] = hash[index_j];
+ hash[index_j] = tc;
+
+ t = hash[index_i] + hash[index_j];
+ data[ind] = hash[t];
+ }
+
+ hash[256] = index_i;
+ hash[257] = index_j;
+}
+
+/****************************************************************
+ Get a 16 byte hash from the contents of a file.
+
+ Note that the hash is initialised, because the extra entropy is not
+ worth the valgrind pain.
+*****************************************************************/
+
+static void do_filehash(const char *fname, unsigned char *the_hash)
+{
+ unsigned char buf[1011]; /* deliberate weird size */
+ unsigned char tmp_md4[16];
+ int fd, n;
+
+ ZERO_STRUCT(tmp_md4);
+
+ fd = open(fname,O_RDONLY,0);
+ if (fd == -1)
+ return;
+
+ while ((n = read(fd, (char *)buf, sizeof(buf))) > 0) {
+ mdfour(tmp_md4, buf, n);
+ for (n=0;n<16;n++)
+ the_hash[n] ^= tmp_md4[n];
+ }
+ close(fd);
+}
+
+/**************************************************************
+ Try and get a good random number seed. Try a number of
+ different factors. Firstly, try /dev/urandom - use if exists.
+
+ We use /dev/urandom as a read of /dev/random can block if
+ the entropy pool dries up. This leads clients to timeout
+ or be very slow on connect.
+
+ If we can't use /dev/urandom then seed the stream random generator
+ above...
+**************************************************************/
+
+static int do_reseed(BOOL use_fd, int fd)
+{
+ unsigned char seed_inbuf[40];
+ uint32_t v1, v2; struct timeval tval; pid_t mypid;
+ int reseed_data = 0;
+
+ if (use_fd) {
+ if (fd != -1)
+ return fd;
+
+ fd = open( "/dev/urandom", O_RDONLY,0);
+ if(fd >= 0)
+ return fd;
+ }
+
+ /* Add in some secret file contents */
+
+ do_filehash("/etc/shadow", &seed_inbuf[0]);
+
+ /*
+ * Add the counter, time of day, and pid.
+ */
+
+ GetTimeOfDay(&tval);
+ mypid = getpid();
+ v1 = (counter++) + mypid + tval.tv_sec;
+ v2 = (counter++) * mypid + tval.tv_usec;
+
+ SIVAL(seed_inbuf, 32, v1 ^ IVAL(seed_inbuf, 32));
+ SIVAL(seed_inbuf, 36, v2 ^ IVAL(seed_inbuf, 36));
+
+ /*
+ * Add any user-given reseed data.
+ */
+
+ get_rand_reseed_data(&reseed_data);
+ if (reseed_data) {
+ size_t i;
+ for (i = 0; i < sizeof(seed_inbuf); i++)
+ seed_inbuf[i] ^= ((char *)(&reseed_data))[i % sizeof(reseed_data)];
+ }
+
+ seed_random_stream(seed_inbuf, sizeof(seed_inbuf));
+
+ return -1;
+}
+
+/*
+ Interface to the (hopefully) good crypto random number generator.
+*/
+void generate_random_buffer(uint8_t *out, int len)
+{
+ static int urand_fd = -1;
+ unsigned char md4_buf[64];
+ unsigned char tmp_buf[16];
+ unsigned char *p;
+
+ if(!done_reseed) {
+ urand_fd = do_reseed(True, urand_fd);
+ done_reseed = True;
+ }
+
+ if (urand_fd != -1 && len > 0) {
+
+ if (read(urand_fd, out, len) == len)
+ return; /* len bytes of random data read from urandom. */
+
+ /* Read of urand error, drop back to non urand method. */
+ close(urand_fd);
+ urand_fd = -1;
+ do_reseed(False, -1);
+ done_reseed = True;
+ }
+
+ /*
+ * Generate random numbers in chunks of 64 bytes,
+ * then md4 them & copy to the output buffer.
+ * This way the raw state of the stream is never externally
+ * seen.
+ */
+
+ p = out;
+ while(len > 0) {
+ int copy_len = len > 16 ? 16 : len;
+
+ get_random_stream(md4_buf, sizeof(md4_buf));
+ mdfour(tmp_buf, md4_buf, sizeof(md4_buf));
+ memcpy(p, tmp_buf, copy_len);
+ p += copy_len;
+ len -= copy_len;
+ }
+}
+
+/*
+ generate a single random uint32_t
+*/
+uint32_t generate_random(void)
+{
+ uint8_t v[4];
+ generate_random_buffer(v, 4);
+ return IVAL(v, 0);
+}
+
+
+/*
+ very basic password quality checker
+*/
+BOOL check_password_quality(const char *s)
+{
+ int has_digit=0, has_capital=0, has_lower=0;
+ while (*s) {
+ if (isdigit((unsigned char)*s)) {
+ has_digit++;
+ } else if (isupper((unsigned char)*s)) {
+ has_capital++;
+ } else if (islower((unsigned char)*s)) {
+ has_lower++;
+ }
+ s++;
+ }
+
+ return has_digit && has_lower && has_capital;
+}
+
+/*******************************************************************
+ Use the random number generator to generate a random string.
+********************************************************************/
+
+char *generate_random_str_list(TALLOC_CTX *mem_ctx, size_t len, const char *list)
+{
+ size_t i;
+ size_t list_len = strlen(list);
+
+ char *retstr = talloc_array(mem_ctx, char, len + 1);
+ if (!retstr) return NULL;
+
+ generate_random_buffer((uint8_t *)retstr, len);
+ for (i = 0; i < len; i++) {
+ retstr[i] = list[retstr[i] % list_len];
+ }
+ retstr[i] = '\0';
+
+ return retstr;
+}
+
+char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len)
+{
+ char *retstr;
+ const char *c_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
+
+again:
+ retstr = generate_random_str_list(mem_ctx, len, c_list);
+ if (!retstr) return NULL;
+
+ /* we need to make sure the random string passes basic quality tests
+ or it might be rejected by windows as a password */
+ if (len >= 7 && !check_password_quality(retstr)) {
+ talloc_free(retstr);
+ goto again;
+ }
+
+ return retstr;
+}
diff --git a/source4/lib/util/idtree.c b/source4/lib/util/idtree.c
new file mode 100644
index 0000000000..a67a80940a
--- /dev/null
+++ b/source4/lib/util/idtree.c
@@ -0,0 +1,384 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ very efficient functions to manage mapping a id (such as a fnum) to
+ a pointer. This is used for fnum and search id allocation.
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This code is derived from lib/idr.c in the 2.6 Linux kernel, which was
+ written by Jim Houston jim.houston@ccur.com, and is
+ Copyright (C) 2002 by Concurrent Computer Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ see the section marked "public interface" below for documentation
+*/
+
+#include "includes.h"
+
+#define IDR_BITS 5
+#define IDR_FULL 0xfffffffful
+#define TOP_LEVEL_FULL (IDR_FULL >> 30)
+#define IDR_SIZE (1 << IDR_BITS)
+#define IDR_MASK ((1 << IDR_BITS)-1)
+#define MAX_ID_SHIFT (sizeof(int)*8 - 1)
+#define MAX_ID_BIT (1U << MAX_ID_SHIFT)
+#define MAX_ID_MASK (MAX_ID_BIT - 1)
+#define MAX_LEVEL (MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS
+#define IDR_FREE_MAX MAX_LEVEL + MAX_LEVEL
+
+#define set_bit(bit, v) (v) |= (1<<(bit))
+#define clear_bit(bit, v) (v) &= ~(1<<(bit))
+#define test_bit(bit, v) ((v) & (1<<(bit)))
+
+struct idr_layer {
+ uint32_t bitmap;
+ struct idr_layer *ary[IDR_SIZE];
+ int count;
+};
+
+struct idr_context {
+ struct idr_layer *top;
+ struct idr_layer *id_free;
+ int layers;
+ int id_free_cnt;
+};
+
+static struct idr_layer *alloc_layer(struct idr_context *idp)
+{
+ struct idr_layer *p;
+
+ if (!(p = idp->id_free))
+ return NULL;
+ idp->id_free = p->ary[0];
+ idp->id_free_cnt--;
+ p->ary[0] = NULL;
+ return p;
+}
+
+static int find_next_bit(uint32_t bm, int maxid, int n)
+{
+ while (n<maxid && !test_bit(n, bm)) n++;
+ return n;
+}
+
+static void free_layer(struct idr_context *idp, struct idr_layer *p)
+{
+ p->ary[0] = idp->id_free;
+ idp->id_free = p;
+ idp->id_free_cnt++;
+}
+
+static int idr_pre_get(struct idr_context *idp)
+{
+ while (idp->id_free_cnt < IDR_FREE_MAX) {
+ struct idr_layer *new = talloc_zero(idp, struct idr_layer);
+ if(new == NULL)
+ return (0);
+ free_layer(idp, new);
+ }
+ return 1;
+}
+
+static int sub_alloc(struct idr_context *idp, void *ptr, int *starting_id)
+{
+ int n, m, sh;
+ struct idr_layer *p, *new;
+ struct idr_layer *pa[MAX_LEVEL];
+ int l, id;
+ uint32_t bm;
+
+ id = *starting_id;
+ p = idp->top;
+ l = idp->layers;
+ pa[l--] = NULL;
+ while (1) {
+ /*
+ * We run around this while until we reach the leaf node...
+ */
+ n = (id >> (IDR_BITS*l)) & IDR_MASK;
+ bm = ~p->bitmap;
+ m = find_next_bit(bm, IDR_SIZE, n);
+ if (m == IDR_SIZE) {
+ /* no space available go back to previous layer. */
+ l++;
+ id = (id | ((1 << (IDR_BITS*l))-1)) + 1;
+ if (!(p = pa[l])) {
+ *starting_id = id;
+ return -2;
+ }
+ continue;
+ }
+ if (m != n) {
+ sh = IDR_BITS*l;
+ id = ((id >> sh) ^ n ^ m) << sh;
+ }
+ if ((id >= MAX_ID_BIT) || (id < 0))
+ return -1;
+ if (l == 0)
+ break;
+ /*
+ * Create the layer below if it is missing.
+ */
+ if (!p->ary[m]) {
+ if (!(new = alloc_layer(idp)))
+ return -1;
+ p->ary[m] = new;
+ p->count++;
+ }
+ pa[l--] = p;
+ p = p->ary[m];
+ }
+ /*
+ * We have reached the leaf node, plant the
+ * users pointer and return the raw id.
+ */
+ p->ary[m] = (struct idr_layer *)ptr;
+ set_bit(m, p->bitmap);
+ p->count++;
+ /*
+ * If this layer is full mark the bit in the layer above
+ * to show that this part of the radix tree is full.
+ * This may complete the layer above and require walking
+ * up the radix tree.
+ */
+ n = id;
+ while (p->bitmap == IDR_FULL) {
+ if (!(p = pa[++l]))
+ break;
+ n = n >> IDR_BITS;
+ set_bit((n & IDR_MASK), p->bitmap);
+ }
+ return(id);
+}
+
+static int idr_get_new_above_int(struct idr_context *idp, void *ptr, int starting_id)
+{
+ struct idr_layer *p, *new;
+ int layers, v, id;
+
+ idr_pre_get(idp);
+
+ id = starting_id;
+build_up:
+ p = idp->top;
+ layers = idp->layers;
+ if (!p) {
+ if (!(p = alloc_layer(idp)))
+ return -1;
+ layers = 1;
+ }
+ /*
+ * Add a new layer to the top of the tree if the requested
+ * id is larger than the currently allocated space.
+ */
+ while ((layers < MAX_LEVEL) && (id >= (1 << (layers*IDR_BITS)))) {
+ layers++;
+ if (!p->count)
+ continue;
+ if (!(new = alloc_layer(idp))) {
+ /*
+ * The allocation failed. If we built part of
+ * the structure tear it down.
+ */
+ for (new = p; p && p != idp->top; new = p) {
+ p = p->ary[0];
+ new->ary[0] = NULL;
+ new->bitmap = new->count = 0;
+ free_layer(idp, new);
+ }
+ return -1;
+ }
+ new->ary[0] = p;
+ new->count = 1;
+ if (p->bitmap == IDR_FULL)
+ set_bit(0, new->bitmap);
+ p = new;
+ }
+ idp->top = p;
+ idp->layers = layers;
+ v = sub_alloc(idp, ptr, &id);
+ if (v == -2)
+ goto build_up;
+ return(v);
+}
+
+static int sub_remove(struct idr_context *idp, int shift, int id)
+{
+ struct idr_layer *p = idp->top;
+ struct idr_layer **pa[MAX_LEVEL];
+ struct idr_layer ***paa = &pa[0];
+ int n;
+
+ *paa = NULL;
+ *++paa = &idp->top;
+
+ while ((shift > 0) && p) {
+ n = (id >> shift) & IDR_MASK;
+ clear_bit(n, p->bitmap);
+ *++paa = &p->ary[n];
+ p = p->ary[n];
+ shift -= IDR_BITS;
+ }
+ n = id & IDR_MASK;
+ if (p != NULL && test_bit(n, p->bitmap)) {
+ clear_bit(n, p->bitmap);
+ p->ary[n] = NULL;
+ while(*paa && ! --((**paa)->count)){
+ free_layer(idp, **paa);
+ **paa-- = NULL;
+ }
+ if ( ! *paa )
+ idp->layers = 0;
+ return 0;
+ }
+ return -1;
+}
+
+static void *_idr_find(struct idr_context *idp, int id)
+{
+ int n;
+ struct idr_layer *p;
+
+ n = idp->layers * IDR_BITS;
+ p = idp->top;
+ /*
+ * This tests to see if bits outside the current tree are
+ * present. If so, tain't one of ours!
+ */
+ if ((id & ~(~0 << MAX_ID_SHIFT)) >> (n + IDR_BITS))
+ return NULL;
+
+ /* Mask off upper bits we don't use for the search. */
+ id &= MAX_ID_MASK;
+
+ while (n > 0 && p) {
+ n -= IDR_BITS;
+ p = p->ary[(id >> n) & IDR_MASK];
+ }
+ return((void *)p);
+}
+
+static int _idr_remove(struct idr_context *idp, int id)
+{
+ struct idr_layer *p;
+
+ /* Mask off upper bits we don't use for the search. */
+ id &= MAX_ID_MASK;
+
+ if (sub_remove(idp, (idp->layers - 1) * IDR_BITS, id) == -1) {
+ return -1;
+ }
+
+ if ( idp->top && idp->top->count == 1 &&
+ (idp->layers > 1) &&
+ idp->top->ary[0]) {
+ /* We can drop a layer */
+ p = idp->top->ary[0];
+ idp->top->bitmap = idp->top->count = 0;
+ free_layer(idp, idp->top);
+ idp->top = p;
+ --idp->layers;
+ }
+ while (idp->id_free_cnt >= IDR_FREE_MAX) {
+ p = alloc_layer(idp);
+ talloc_free(p);
+ }
+ return 0;
+}
+
+/************************************************************************
+ this is the public interface
+**************************************************************************/
+
+/*
+ initialise a idr tree. The context return value must be passed to
+ all subsequent idr calls. To destroy the idr tree use talloc_free()
+ on this context
+ */
+struct idr_context *idr_init(TALLOC_CTX *mem_ctx)
+{
+ return talloc_zero(mem_ctx, struct idr_context);
+}
+
+/*
+ allocate the next available id, and assign 'ptr' into its slot.
+ you can retrieve later this pointer using idr_find()
+*/
+int idr_get_new(struct idr_context *idp, void *ptr, int limit)
+{
+ int ret = idr_get_new_above_int(idp, ptr, 0);
+ if (ret > limit) {
+ idr_remove(idp, ret);
+ return -1;
+ }
+ return ret;
+}
+
+/*
+ allocate a new id, giving the first available value greater than or
+ equal to the given starting id
+*/
+int idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id, int limit)
+{
+ int ret = idr_get_new_above_int(idp, ptr, starting_id);
+ if (ret > limit) {
+ idr_remove(idp, ret);
+ return -1;
+ }
+ return ret;
+}
+
+/*
+ allocate a new id randomly in the given range
+*/
+int idr_get_new_random(struct idr_context *idp, void *ptr, int limit)
+{
+ int id;
+
+ /* first try a random starting point in the whole range, and if that fails,
+ then start randomly in the bottom half of the range. This can only
+ fail if the range is over half full */
+ id = idr_get_new_above(idp, ptr, 1+(generate_random() % limit), limit);
+ if (id == -1) {
+ id = idr_get_new_above(idp, ptr, 1+(generate_random()%(limit/2)), limit);
+ }
+
+ return id;
+}
+
+/*
+ find a pointer value previously set with idr_get_new given an id
+*/
+void *idr_find(struct idr_context *idp, int id)
+{
+ return _idr_find(idp, id);
+}
+
+/*
+ remove an id from the idr tree
+*/
+int idr_remove(struct idr_context *idp, int id)
+{
+ int ret;
+ ret = _idr_remove((struct idr_context *)idp, id);
+ if (ret != 0) {
+ DEBUG(0,("WARNING: attempt to remove unset id %d in idtree\n", id));
+ }
+ return ret;
+}
diff --git a/source4/lib/util/module.c b/source4/lib/util/module.c
new file mode 100644
index 0000000000..672d8df7ce
--- /dev/null
+++ b/source4/lib/util/module.c
@@ -0,0 +1,97 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Jelmer Vernooij 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "system/dir.h"
+
+static void *load_module(TALLOC_CTX *mem_ctx, const char *dir, const char *name)
+{
+ char *path;
+ void *handle;
+ void *init_fn;
+
+ path = talloc_asprintf(mem_ctx, "%s/%s", dir, name);
+
+ handle = dlopen(path, RTLD_NOW);
+ if (handle == NULL) {
+ DEBUG(0, ("Unable to open %s: %s\n", path, dlerror()));
+ talloc_free(path);
+ return NULL;
+ }
+
+ init_fn = dlsym(handle, "init_module");
+
+ if (init_fn == NULL) {
+ DEBUG(0, ("Unable to find init_module() in %s: %s\n", path, dlerror()));
+ DEBUG(1, ("Loading module '%s' failed\n", path));
+ dlclose(handle);
+ talloc_free(path);
+ return NULL;
+ }
+
+ talloc_free(path);
+
+ return init_fn;
+}
+
+init_module_fn *load_modules(TALLOC_CTX *mem_ctx, const char *path)
+{
+ DIR *dir;
+ struct dirent *entry;
+ int success = 0;
+ init_module_fn *ret = talloc_array(mem_ctx, init_module_fn, 2);
+
+ ret[0] = NULL;
+
+ dir = opendir(path);
+ if (dir == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+
+ while((entry = readdir(dir))) {
+ if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
+ continue;
+
+ ret[success] = load_module(mem_ctx, path, entry->d_name);
+ if (ret[success]) {
+ ret = talloc_realloc(mem_ctx, ret, init_module_fn, success+2);
+ success++;
+ ret[success] = NULL;
+ }
+ }
+
+ closedir(dir);
+
+ return ret;
+}
+
+BOOL run_init_functions(NTSTATUS (**fns) (void))
+{
+ int i;
+ BOOL ret;
+
+ if (fns == NULL)
+ return True;
+
+ for (i = 0; fns[i]; i++) { ret &= NT_STATUS_IS_OK(fns[i]()); }
+
+ return ret;
+}
diff --git a/source4/lib/util/ms_fnmatch.c b/source4/lib/util/ms_fnmatch.c
new file mode 100644
index 0000000000..699341bede
--- /dev/null
+++ b/source4/lib/util/ms_fnmatch.c
@@ -0,0 +1,219 @@
+/*
+ Unix SMB/CIFS implementation.
+ filename matching routine
+ Copyright (C) Andrew Tridgell 1992-2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ This module was originally based on fnmatch.c copyright by the Free
+ Software Foundation. It bears little (if any) resemblence to that
+ code now
+*/
+
+
+#include "includes.h"
+
+static int null_match(const char *p)
+{
+ for (;*p;p++) {
+ if (*p != '*' &&
+ *p != '<' &&
+ *p != '"' &&
+ *p != '>') return -1;
+ }
+ return 0;
+}
+
+/*
+ the max_n structure is purely for efficiency, it doesn't contribute
+ to the matching algorithm except by ensuring that the algorithm does
+ not grow exponentially
+*/
+struct max_n {
+ const char *predot;
+ const char *postdot;
+};
+
+
+/*
+ p and n are the pattern and string being matched. The max_n array is
+ an optimisation only. The ldot pointer is NULL if the string does
+ not contain a '.', otherwise it points at the last dot in 'n'.
+*/
+static int ms_fnmatch_core(const char *p, const char *n,
+ struct max_n *max_n, const char *ldot)
+{
+ codepoint_t c, c2;
+ int i;
+ size_t size, size_n;
+
+ while ((c = next_codepoint(p, &size))) {
+ p += size;
+
+ switch (c) {
+ case '*':
+ /* a '*' matches zero or more characters of any type */
+ if (max_n->predot && max_n->predot <= n) {
+ return null_match(p);
+ }
+ for (i=0; n[i]; i += size_n) {
+ next_codepoint(n+i, &size_n);
+ if (ms_fnmatch_core(p, n+i, max_n+1, ldot) == 0) {
+ return 0;
+ }
+ }
+ if (!max_n->predot || max_n->predot > n) max_n->predot = n;
+ return null_match(p);
+
+ case '<':
+ /* a '<' matches zero or more characters of
+ any type, but stops matching at the last
+ '.' in the string. */
+ if (max_n->predot && max_n->predot <= n) {
+ return null_match(p);
+ }
+ if (max_n->postdot && max_n->postdot <= n && n <= ldot) {
+ return -1;
+ }
+ for (i=0; n[i]; i += size_n) {
+ next_codepoint(n+i, &size_n);
+ if (ms_fnmatch_core(p, n+i, max_n+1, ldot) == 0) return 0;
+ if (n+i == ldot) {
+ if (ms_fnmatch_core(p, n+i+size_n, max_n+1, ldot) == 0) return 0;
+ if (!max_n->postdot || max_n->postdot > n) max_n->postdot = n;
+ return -1;
+ }
+ }
+ if (!max_n->predot || max_n->predot > n) max_n->predot = n;
+ return null_match(p);
+
+ case '?':
+ /* a '?' matches any single character */
+ if (! *n) {
+ return -1;
+ }
+ next_codepoint(n, &size_n);
+ n += size_n;
+ break;
+
+ case '>':
+ /* a '?' matches any single character, but
+ treats '.' specially */
+ if (n[0] == '.') {
+ if (! n[1] && null_match(p) == 0) {
+ return 0;
+ }
+ break;
+ }
+ if (! *n) return null_match(p);
+ next_codepoint(n, &size_n);
+ n += size_n;
+ break;
+
+ case '"':
+ /* a bit like a soft '.' */
+ if (*n == 0 && null_match(p) == 0) {
+ return 0;
+ }
+ if (*n != '.') return -1;
+ next_codepoint(n, &size_n);
+ n += size_n;
+ break;
+
+ default:
+ c2 = next_codepoint(n, &size_n);
+ if (c != c2 && codepoint_cmpi(c, c2) != 0) {
+ return -1;
+ }
+ n += size_n;
+ break;
+ }
+ }
+
+ if (! *n) {
+ return 0;
+ }
+
+ return -1;
+}
+
+int ms_fnmatch(const char *pattern, const char *string, enum protocol_types protocol)
+{
+ int ret, count, i;
+ struct max_n *max_n = NULL;
+
+ if (strcmp(string, "..") == 0) {
+ string = ".";
+ }
+
+ if (strpbrk(pattern, "<>*?\"") == NULL) {
+ /* this is not just an optmisation - it is essential
+ for LANMAN1 correctness */
+ return strcasecmp_m(pattern, string);
+ }
+
+ if (protocol <= PROTOCOL_LANMAN2) {
+ char *p = talloc_strdup(NULL, pattern);
+ if (p == NULL) {
+ return -1;
+ }
+ /*
+ for older negotiated protocols it is possible to
+ translate the pattern to produce a "new style"
+ pattern that exactly matches w2k behaviour
+ */
+ for (i=0;p[i];i++) {
+ if (p[i] == '?') {
+ p[i] = '>';
+ } else if (p[i] == '.' &&
+ (p[i+1] == '?' ||
+ p[i+1] == '*' ||
+ p[i+1] == 0)) {
+ p[i] = '"';
+ } else if (p[i] == '*' &&
+ p[i+1] == '.') {
+ p[i] = '<';
+ }
+ }
+ ret = ms_fnmatch(p, string, PROTOCOL_NT1);
+ talloc_free(p);
+ return ret;
+ }
+
+ for (count=i=0;pattern[i];i++) {
+ if (pattern[i] == '*' || pattern[i] == '<') count++;
+ }
+
+ max_n = talloc_array(NULL, struct max_n, count);
+ if (!max_n) {
+ return -1;
+ }
+ memset(max_n, 0, sizeof(struct max_n) * count);
+
+ ret = ms_fnmatch_core(pattern, string, max_n, strrchr(string, '.'));
+
+ talloc_free(max_n);
+
+ return ret;
+}
+
+
+/* a generic fnmatch function - uses for non-CIFS pattern matching */
+int gen_fnmatch(const char *pattern, const char *string)
+{
+ return ms_fnmatch(pattern, string, PROTOCOL_NT1);
+}
diff --git a/source4/lib/util/mutex.c b/source4/lib/util/mutex.c
new file mode 100644
index 0000000000..480ba92cc0
--- /dev/null
+++ b/source4/lib/util/mutex.c
@@ -0,0 +1,52 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba mutex/lock functions
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) James J Myers 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#include "includes.h"
+#include "mutex.h"
+
+/* the registered mutex handlers */
+static struct {
+ const char *name;
+ struct mutex_ops ops;
+} mutex_handlers;
+
+/* read/write lock routines */
+
+
+/*
+ register a set of mutex/rwlock handlers.
+ Should only be called once in the execution of smbd.
+*/
+BOOL register_mutex_handlers(const char *name, struct mutex_ops *ops)
+{
+ if (mutex_handlers.name != NULL) {
+ /* it's already registered! */
+ DEBUG(2,("mutex handler '%s' already registered - failed '%s'\n",
+ mutex_handlers.name, name));
+ return False;
+ }
+
+ mutex_handlers.name = name;
+ mutex_handlers.ops = *ops;
+
+ DEBUG(2,("mutex handler '%s' registered\n", name));
+ return True;
+}
+
diff --git a/source4/lib/util/mutex.h b/source4/lib/util/mutex.h
new file mode 100644
index 0000000000..018c134bcb
--- /dev/null
+++ b/source4/lib/util/mutex.h
@@ -0,0 +1,71 @@
+#ifndef _MUTEX_H_
+#define _MUTEX_H_
+/*
+ Unix SMB/CIFS implementation.
+ Samba mutex functions
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) James J Myers 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+struct mutex_ops;
+
+/* To add a new read/write lock, add it to enum rwlock_id
+ */
+enum rwlock_id { RWLOCK_SMBD, /* global smbd lock */
+
+ RWLOCK_MAX /* this MUST be kept last */
+};
+
+#define MUTEX_LOCK_BY_ID(mutex_index) smb_mutex_lock_by_id(mutex_index, #mutex_index)
+#define MUTEX_UNLOCK_BY_ID(mutex_index) smb_mutex_unlock_by_id(mutex_index, #mutex_index)
+#define MUTEX_INIT(mutex, name) smb_mutex_init(mutex, #name)
+#define MUTEX_DESTROY(mutex, name) smb_mutex_destroy(mutex, #name)
+#define MUTEX_LOCK(mutex, name) smb_mutex_lock(mutex, #name)
+#define MUTEX_UNLOCK(mutex, name) smb_mutex_unlock(mutex, #name)
+
+#define RWLOCK_INIT(rwlock, name) smb_rwlock_init(rwlock, #name)
+#define RWLOCK_DESTROY(rwlock, name) smb_rwlock_destroy(rwlock, #name)
+#define RWLOCK_LOCK_WRITE(rwlock, name) smb_rwlock_lock_write(rwlock, #name)
+#define RWLOCK_LOCK_READ(rwlock, name) smb_rwlock_lock_read(rwlock, #name)
+#define RWLOCK_UNLOCK(rwlock, name) smb_rwlock_unlock(rwlock, #name)
+
+
+
+/* this null typedef ensures we get the types right and avoids the
+ pitfalls of void* */
+typedef struct smb_mutex {
+ void *mutex;
+} smb_mutex_t;
+typedef struct {
+ void *rwlock;
+} smb_rwlock_t;
+
+/* the mutex model operations structure - contains function pointers to
+ the model-specific implementations of each operation */
+struct mutex_ops {
+ int (*mutex_init)(smb_mutex_t *mutex, const char *name);
+ int (*mutex_lock)(smb_mutex_t *mutex, const char *name);
+ int (*mutex_unlock)(smb_mutex_t *mutex, const char *name);
+ int (*mutex_destroy)(smb_mutex_t *mutex, const char *name);
+ int (*rwlock_init)(smb_rwlock_t *rwlock, const char *name);
+ int (*rwlock_lock_write)(smb_rwlock_t *rwlock, const char *name);
+ int (*rwlock_lock_read)(smb_rwlock_t *rwlock, const char *name);
+ int (*rwlock_unlock)(smb_rwlock_t *rwlock, const char *name);
+ int (*rwlock_destroy)(smb_rwlock_t *rwlock, const char *name);
+};
+
+#endif /* endif _MUTEX_H_ */
diff --git a/source4/lib/util/pidfile.c b/source4/lib/util/pidfile.c
new file mode 100644
index 0000000000..9a7c197f70
--- /dev/null
+++ b/source4/lib/util/pidfile.c
@@ -0,0 +1,116 @@
+/* this code is broken - there is a race condition with the unlink (tridge) */
+
+/*
+ Unix SMB/CIFS implementation.
+ pidfile handling
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK
+#endif
+
+/* return the pid in a pidfile. return 0 if the process (or pidfile)
+ does not exist */
+pid_t pidfile_pid(const char *name)
+{
+ int fd;
+ char pidstr[20];
+ uint_t ret;
+ char *pidFile;
+
+ asprintf(&pidFile, "%s/%s.pid", lp_piddir(), name);
+
+ fd = open(pidFile, O_NONBLOCK | O_RDONLY, 0644);
+
+ if (fd == -1) {
+ SAFE_FREE(pidFile);
+ return 0;
+ }
+
+ ZERO_STRUCT(pidstr);
+
+ if (read(fd, pidstr, sizeof(pidstr)-1) <= 0) {
+ goto noproc;
+ }
+
+ ret = atoi(pidstr);
+
+ if (!process_exists((pid_t)ret)) {
+ goto noproc;
+ }
+
+ if (fcntl_lock(fd,F_SETLK,0,1,F_RDLCK)) {
+ /* we could get the lock - it can't be a Samba process */
+ goto noproc;
+ }
+
+ close(fd);
+ SAFE_FREE(pidFile);
+ return (pid_t)ret;
+
+ noproc:
+ close(fd);
+ unlink(pidFile);
+ SAFE_FREE(pidFile);
+ return 0;
+}
+
+/* create a pid file in the pid directory. open it and leave it locked */
+void pidfile_create(const char *name)
+{
+ int fd;
+ char buf[20];
+ char *pidFile;
+ pid_t pid;
+
+ asprintf(&pidFile, "%s/%s.pid", lp_piddir(), name);
+
+ pid = pidfile_pid(name);
+ if (pid != 0) {
+ DEBUG(0,("ERROR: %s is already running. File %s exists and process id %d is running.\n",
+ name, pidFile, (int)pid));
+ exit(1);
+ }
+
+ fd = open(pidFile, O_NONBLOCK | O_CREAT | O_WRONLY | O_EXCL, 0644);
+ if (fd == -1) {
+ DEBUG(0,("ERROR: can't open %s: Error was %s\n", pidFile,
+ strerror(errno)));
+ exit(1);
+ }
+
+ if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)==False) {
+ DEBUG(0,("ERROR: %s : fcntl lock of file %s failed. Error was %s\n",
+ name, pidFile, strerror(errno)));
+ exit(1);
+ }
+
+ memset(buf, 0, sizeof(buf));
+ slprintf(buf, sizeof(buf) - 1, "%u\n", (uint_t) getpid());
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) {
+ DEBUG(0,("ERROR: can't write to file %s: %s\n",
+ pidFile, strerror(errno)));
+ exit(1);
+ }
+
+ /* Leave pid file open & locked for the duration... */
+ SAFE_FREE(pidFile);
+}
diff --git a/source4/lib/util/safe_string.h b/source4/lib/util/safe_string.h
new file mode 100644
index 0000000000..43e094467c
--- /dev/null
+++ b/source4/lib/util/safe_string.h
@@ -0,0 +1,55 @@
+/*
+ Unix SMB/CIFS implementation.
+ Safe string handling routines.
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _SAFE_STRING_H
+#define _SAFE_STRING_H
+
+#ifndef _SPLINT_ /* http://www.splint.org */
+/* Some macros to ensure people don't use buffer overflow vulnerable string
+ functions. */
+
+#ifdef bcopy
+#undef bcopy
+#endif /* bcopy */
+#define bcopy(src,dest,size) __ERROR__XX__NEVER_USE_BCOPY___;
+
+#ifdef strcpy
+#undef strcpy
+#endif /* strcpy */
+#define strcpy(dest,src) __ERROR__XX__NEVER_USE_STRCPY___;
+
+#ifdef strcat
+#undef strcat
+#endif /* strcat */
+#define strcat(dest,src) __ERROR__XX__NEVER_USE_STRCAT___;
+
+#ifdef sprintf
+#undef sprintf
+#endif /* sprintf */
+#define sprintf __ERROR__XX__NEVER_USE_SPRINTF__;
+
+#endif /* !_SPLINT_ */
+
+/* replace some string functions with multi-byte
+ versions */
+#define strlower(s) strlower_m(s)
+#define strupper(s) strupper_m(s)
+
+#endif
diff --git a/source4/lib/util/select.c b/source4/lib/util/select.c
new file mode 100644
index 0000000000..a1b2e04065
--- /dev/null
+++ b/source4/lib/util/select.c
@@ -0,0 +1,169 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba select/poll implementation
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+
+/* This is here because it allows us to avoid a nasty race in signal handling.
+ We need to guarantee that when we get a signal we get out of a select immediately
+ but doing that involves a race condition. We can avoid the race by getting the
+ signal handler to write to a pipe that is in the select/poll list
+
+ This means all Samba signal handlers should call sys_select_signal().
+*/
+
+static pid_t initialised;
+static int select_pipe[2];
+static VOLATILE unsigned pipe_written, pipe_read;
+
+/*******************************************************************
+ Call this from all Samba signal handlers if you want to avoid a
+ nasty signal race condition.
+********************************************************************/
+
+void sys_select_signal(void)
+{
+ char c = 1;
+ if (!initialised) return;
+
+ if (pipe_written > pipe_read+256) return;
+
+ if (write(select_pipe[1], &c, 1) == 1) pipe_written++;
+}
+
+/*******************************************************************
+ Like select() but avoids the signal race using a pipe
+ it also guarantees that fds on return only ever contains bits set
+ for file descriptors that were readable.
+********************************************************************/
+
+int sys_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval)
+{
+ int ret, saved_errno;
+ fd_set *readfds2, readfds_buf;
+
+ if (initialised != getpid()) {
+ pipe(select_pipe);
+
+ /*
+ * These next two lines seem to fix a bug with the Linux
+ * 2.0.x kernel (and probably other UNIXes as well) where
+ * the one byte read below can block even though the
+ * select returned that there is data in the pipe and
+ * the pipe_written variable was incremented. Thanks to
+ * HP for finding this one. JRA.
+ */
+
+ if(set_blocking(select_pipe[0],0)==-1)
+ smb_panic("select_pipe[0]: O_NONBLOCK failed.\n");
+ if(set_blocking(select_pipe[1],0)==-1)
+ smb_panic("select_pipe[1]: O_NONBLOCK failed.\n");
+
+ initialised = getpid();
+ }
+
+ maxfd = MAX(select_pipe[0]+1, maxfd);
+
+ /* If readfds is NULL we need to provide our own set. */
+ if (readfds) {
+ readfds2 = readfds;
+ } else {
+ readfds2 = &readfds_buf;
+ FD_ZERO(readfds2);
+ }
+ FD_SET(select_pipe[0], readfds2);
+
+ errno = 0;
+ ret = select(maxfd,readfds2,writefds,errorfds,tval);
+
+ if (ret <= 0) {
+ FD_ZERO(readfds2);
+ if (writefds)
+ FD_ZERO(writefds);
+ if (errorfds)
+ FD_ZERO(errorfds);
+ } else if (FD_ISSET(select_pipe[0], readfds2)) {
+ char c;
+ saved_errno = errno;
+ if (read(select_pipe[0], &c, 1) == 1) {
+ pipe_read++;
+ /* Mark Weaver <mark-clist@npsl.co.uk> pointed out a critical
+ fix to ensure we don't lose signals. We must always
+ return -1 when the select pipe is set, otherwise if another
+ fd is also ready (so ret == 2) then we used to eat the
+ byte in the pipe and lose the signal. JRA.
+ */
+ ret = -1;
+ errno = EINTR;
+ } else {
+ FD_CLR(select_pipe[0], readfds2);
+ ret--;
+ errno = saved_errno;
+ }
+ }
+
+ return ret;
+}
+
+/*******************************************************************
+ Similar to sys_select() but catch EINTR and continue.
+ This is what sys_select() used to do in Samba.
+********************************************************************/
+
+int sys_select_intr(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval)
+{
+ int ret;
+ fd_set *readfds2, readfds_buf, *writefds2, writefds_buf, *errorfds2, errorfds_buf;
+ struct timeval tval2, *ptval;
+
+ readfds2 = (readfds ? &readfds_buf : NULL);
+ writefds2 = (writefds ? &writefds_buf : NULL);
+ errorfds2 = (errorfds ? &errorfds_buf : NULL);
+ ptval = (tval ? &tval2 : NULL);
+
+ do {
+ if (readfds)
+ readfds_buf = *readfds;
+ if (writefds)
+ writefds_buf = *writefds;
+ if (errorfds)
+ errorfds_buf = *errorfds;
+ if (tval)
+ tval2 = *tval;
+
+ /* We must use select and not sys_select here. If we use
+ sys_select we'd lose the fact a signal occurred when sys_select
+ read a byte from the pipe. Fix from Mark Weaver
+ <mark-clist@npsl.co.uk>
+ */
+
+ ret = select(maxfd, readfds2, writefds2, errorfds2, ptval);
+ } while (ret == -1 && errno == EINTR);
+
+ if (readfds)
+ *readfds = readfds_buf;
+ if (writefds)
+ *writefds = writefds_buf;
+ if (errorfds)
+ *errorfds = errorfds_buf;
+
+ return ret;
+}
diff --git a/source4/lib/util/signal.c b/source4/lib/util/signal.c
new file mode 100644
index 0000000000..6c0bb4007a
--- /dev/null
+++ b/source4/lib/util/signal.c
@@ -0,0 +1,140 @@
+/*
+ Unix SMB/CIFS implementation.
+ signal handling functions
+
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "system/wait.h"
+
+/****************************************************************************
+ Catch child exits and reap the child zombie status.
+****************************************************************************/
+
+static void sig_cld(int signum)
+{
+ while (waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0)
+ ;
+
+ /*
+ * Turns out it's *really* important not to
+ * restore the signal handler here if we have real POSIX
+ * signal handling. If we do, then we get the signal re-delivered
+ * immediately - hey presto - instant loop ! JRA.
+ */
+
+#if !defined(HAVE_SIGACTION)
+ CatchSignal(SIGCLD, sig_cld);
+#endif
+}
+
+/****************************************************************************
+catch child exits - leave status;
+****************************************************************************/
+
+static void sig_cld_leave_status(int signum)
+{
+ /*
+ * Turns out it's *really* important not to
+ * restore the signal handler here if we have real POSIX
+ * signal handling. If we do, then we get the signal re-delivered
+ * immediately - hey presto - instant loop ! JRA.
+ */
+
+#if !defined(HAVE_SIGACTION)
+ CatchSignal(SIGCLD, sig_cld_leave_status);
+#endif
+}
+
+/*******************************************************************
+ Block sigs.
+********************************************************************/
+
+void BlockSignals(BOOL block,int signum)
+{
+#ifdef HAVE_SIGPROCMASK
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set,signum);
+ sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL);
+#elif defined(HAVE_SIGBLOCK)
+ if (block) {
+ sigblock(sigmask(signum));
+ } else {
+ sigsetmask(siggetmask() & ~sigmask(signum));
+ }
+#else
+ /* yikes! This platform can't block signals? */
+ static int done;
+ if (!done) {
+ DEBUG(0,("WARNING: No signal blocking available\n"));
+ done=1;
+ }
+#endif
+}
+
+/*******************************************************************
+ Catch a signal. This should implement the following semantics:
+
+ 1) The handler remains installed after being called.
+ 2) The signal should be blocked during handler execution.
+********************************************************************/
+
+void (*CatchSignal(int signum,void (*handler)(int )))(int)
+{
+#ifdef HAVE_SIGACTION
+ struct sigaction act;
+ struct sigaction oldact;
+
+ ZERO_STRUCT(act);
+
+ act.sa_handler = handler;
+#ifdef SA_RESTART
+ /*
+ * We *want* SIGALRM to interrupt a system call.
+ */
+ if(signum != SIGALRM)
+ act.sa_flags = SA_RESTART;
+#endif
+ sigemptyset(&act.sa_mask);
+ sigaddset(&act.sa_mask,signum);
+ sigaction(signum,&act,&oldact);
+ return oldact.sa_handler;
+#else /* !HAVE_SIGACTION */
+ /* FIXME: need to handle sigvec and systems with broken signal() */
+ return signal(signum, handler);
+#endif
+}
+
+/*******************************************************************
+ Ignore SIGCLD via whatever means is necessary for this OS.
+********************************************************************/
+
+void CatchChild(void)
+{
+ CatchSignal(SIGCLD, sig_cld);
+}
+
+/*******************************************************************
+ Catch SIGCLD but leave the child around so it's status can be reaped.
+********************************************************************/
+
+void CatchChildLeaveStatus(void)
+{
+ CatchSignal(SIGCLD, sig_cld_leave_status);
+}
diff --git a/source4/lib/util/substitute.c b/source4/lib/util/substitute.c
new file mode 100644
index 0000000000..34a2ad9f82
--- /dev/null
+++ b/source4/lib/util/substitute.c
@@ -0,0 +1,165 @@
+/*
+ Unix SMB/CIFS implementation.
+ string substitution functions
+ Copyright (C) Andrew Tridgell 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#include "includes.h"
+#include "smb_server/smb_server.h"
+
+/* oh bugger - I really didn't want to have a top-level context
+ anywhere, but until we change all lp_*() calls to take a context
+ argument this is needed */
+static struct substitute_context *sub;
+
+void sub_set_context(struct substitute_context *subptr)
+{
+ sub = subptr;
+}
+
+/*
+ setup a string in the negotiate structure, using alpha_strcpy with SAFE_NETBIOS_CHARS
+*/
+static void setup_string(char **dest, const char *str)
+{
+#define SAFE_NETBIOS_CHARS ". -_"
+ char *s;
+
+ s = strdup(str);
+ if (!s) {
+ return;
+ }
+
+ alpha_strcpy(s, str, SAFE_NETBIOS_CHARS, strlen(s)+1);
+
+ trim_string(s," "," ");
+ strlower(s);
+
+ SAFE_FREE(*dest);
+ (*dest) = s;
+}
+
+void sub_set_remote_proto(const char *str)
+{
+ if (!sub) return;
+ setup_string(&sub->remote_proto, str);
+}
+
+void sub_set_remote_arch(const char *str)
+{
+ if (!sub) return;
+ setup_string(&sub->remote_arch, str);
+}
+
+/*
+ setup the string used by %U substitution
+*/
+void sub_set_user_name(const char *name)
+{
+ if (!sub) return;
+ setup_string(&sub->user_name, name);
+}
+
+/****************************************************************************
+FOO
+****************************************************************************/
+void standard_sub_basic(char *str,size_t len)
+{
+}
+
+/****************************************************************************
+ Do some standard substitutions in a string.
+ This function will return an allocated string that have to be freed.
+****************************************************************************/
+char *talloc_sub_basic(TALLOC_CTX *mem_ctx, const char *smb_name, const char *str)
+{
+ return talloc_strdup(mem_ctx, str);
+}
+
+char *alloc_sub_basic(const char *smb_name, const char *str)
+{
+ return strdup(str);
+}
+
+/****************************************************************************
+ Do some specific substitutions in a string.
+ This function will return an allocated string that have to be freed.
+****************************************************************************/
+
+char *talloc_sub_specified(TALLOC_CTX *mem_ctx,
+ const char *input_string,
+ const char *username,
+ const char *domain,
+ uid_t uid,
+ gid_t gid)
+{
+ return talloc_strdup(mem_ctx, input_string);
+}
+
+char *alloc_sub_specified(const char *input_string,
+ const char *username,
+ const char *domain,
+ uid_t uid,
+ gid_t gid)
+{
+ return strdup(input_string);
+}
+
+char *talloc_sub_advanced(TALLOC_CTX *mem_ctx,
+ int snum,
+ const char *user,
+ const char *connectpath,
+ gid_t gid,
+ const char *smb_name,
+ char *str)
+{
+ return talloc_strdup(mem_ctx, str);
+}
+
+char *alloc_sub_advanced(int snum, const char *user,
+ const char *connectpath, gid_t gid,
+ const char *smb_name, char *str)
+{
+ return strdup(str);
+}
+
+/****************************************************************************
+ Do some standard substitutions in a string.
+****************************************************************************/
+
+void standard_sub_tcon(struct smbsrv_tcon *tcon, char *str, size_t len)
+{
+}
+
+char *talloc_sub_tcon(TALLOC_CTX *mem_ctx, struct smbsrv_tcon *tcon, char *str)
+{
+ return talloc_strdup(mem_ctx, str);
+}
+
+char *alloc_sub_tcon(struct smbsrv_tcon *tcon, char *str)
+{
+ return strdup(str);
+}
+
+/****************************************************************************
+ Like standard_sub but by snum.
+****************************************************************************/
+
+void standard_sub_snum(int snum, char *str, size_t len)
+{
+}
diff --git a/source4/lib/util/system.c b/source4/lib/util/system.c
new file mode 100644
index 0000000000..655b4a1054
--- /dev/null
+++ b/source4/lib/util/system.c
@@ -0,0 +1,98 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba system utilities
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1998-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "system/network.h"
+#include "system/filesys.h"
+
+/*
+ The idea is that this file will eventually have wrappers around all
+ important system calls in samba. The aims are:
+
+ - to enable easier porting by putting OS dependent stuff in here
+
+ - to allow for hooks into other "pseudo-filesystems"
+
+ - to allow easier integration of things like the japanese extensions
+
+ - to support the philosophy of Samba to expose the features of
+ the OS within the SMB model. In general whatever file/printer/variable
+ expansions/etc make sense to the OS should be acceptable to Samba.
+*/
+
+/**************************************************************************
+A wrapper for gethostbyname() that tries avoids looking up hostnames
+in the root domain, which can cause dial-on-demand links to come up for no
+apparent reason.
+****************************************************************************/
+
+struct hostent *sys_gethostbyname(const char *name)
+{
+#ifdef REDUCE_ROOT_DNS_LOOKUPS
+ char query[256], hostname[256];
+ char *domain;
+
+ /* Does this name have any dots in it? If so, make no change */
+
+ if (strchr_m(name, '.'))
+ return(gethostbyname(name));
+
+ /* Get my hostname, which should have domain name
+ attached. If not, just do the gethostname on the
+ original string.
+ */
+
+ gethostname(hostname, sizeof(hostname) - 1);
+ hostname[sizeof(hostname) - 1] = 0;
+ if ((domain = strchr_m(hostname, '.')) == NULL)
+ return(gethostbyname(name));
+
+ /* Attach domain name to query and do modified query.
+ If names too large, just do gethostname on the
+ original string.
+ */
+
+ if((strlen(name) + strlen(domain)) >= sizeof(query))
+ return(gethostbyname(name));
+
+ slprintf(query, sizeof(query)-1, "%s%s", name, domain);
+ return(gethostbyname(query));
+#else /* REDUCE_ROOT_DNS_LOOKUPS */
+ return(gethostbyname(name));
+#endif /* REDUCE_ROOT_DNS_LOOKUPS */
+}
+
+const char *sys_inet_ntoa(struct ipv4_addr in)
+{
+ struct in_addr in2;
+ in2.s_addr = in.addr;
+ return inet_ntoa(in2);
+}
+
+struct ipv4_addr sys_inet_makeaddr(int net, int host)
+{
+ struct in_addr in;
+ struct ipv4_addr in2;
+ in = inet_makeaddr(net, host);
+ in2.addr = in.s_addr;
+ return in2;
+}
+
diff --git a/source4/lib/util/time.c b/source4/lib/util/time.c
new file mode 100644
index 0000000000..7721a2c456
--- /dev/null
+++ b/source4/lib/util/time.c
@@ -0,0 +1,596 @@
+/*
+ Unix SMB/CIFS implementation.
+ time handling functions
+
+ Copyright (C) Andrew Tridgell 1992-2004
+ Copyright (C) Stefan (metze) Metzmacher 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "system/time.h"
+
+#ifndef TIME_T_MIN
+/* we use 0 here, because (time_t)-1 means error */
+#define TIME_T_MIN 0
+#endif
+
+/*
+ * we use the INT32_MAX here as on 64 bit systems,
+ * gmtime() fails with INT64_MAX
+ */
+
+#ifndef TIME_T_MAX
+#define TIME_T_MAX MIN(INT32_MAX,_TYPE_MAXIMUM(time_t))
+#endif
+
+/*******************************************************************
+ External access to time_t_min and time_t_max.
+********************************************************************/
+time_t get_time_t_max(void)
+{
+ return TIME_T_MAX;
+}
+
+/*******************************************************************
+a gettimeofday wrapper
+********************************************************************/
+void GetTimeOfDay(struct timeval *tval)
+{
+#ifdef HAVE_GETTIMEOFDAY_TZ
+ gettimeofday(tval,NULL);
+#else
+ gettimeofday(tval);
+#endif
+}
+
+
+#define TIME_FIXUP_CONSTANT 11644473600LL
+
+/****************************************************************************
+interpret an 8 byte "filetime" structure to a time_t
+It's originally in "100ns units since jan 1st 1601"
+****************************************************************************/
+time_t nt_time_to_unix(NTTIME nt)
+{
+ if (nt == 0) {
+ return 0;
+ }
+ if (nt == -1LL) {
+ return (time_t)-1;
+ }
+ nt += 1000*1000*10/2;
+ nt /= 1000*1000*10;
+ nt -= TIME_FIXUP_CONSTANT;
+
+ if (TIME_T_MIN > nt || nt > TIME_T_MAX) {
+ return 0;
+ }
+
+ return (time_t)nt;
+}
+
+
+/****************************************************************************
+put a 8 byte filetime from a time_t
+This takes GMT as input
+****************************************************************************/
+void unix_to_nt_time(NTTIME *nt, time_t t)
+{
+ uint64_t t2;
+
+ if (t == (time_t)-1) {
+ *nt = (NTTIME)-1LL;
+ return;
+ }
+ if (t == 0) {
+ *nt = 0;
+ return;
+ }
+
+ t2 = t;
+ t2 += TIME_FIXUP_CONSTANT;
+ t2 *= 1000*1000*10;
+
+ *nt = t2;
+}
+
+
+/****************************************************************************
+check if it's a null unix time
+****************************************************************************/
+BOOL null_time(time_t t)
+{
+ return t == 0 ||
+ t == (time_t)0xFFFFFFFF ||
+ t == (time_t)-1;
+}
+
+
+/****************************************************************************
+check if it's a null NTTIME
+****************************************************************************/
+BOOL null_nttime(NTTIME t)
+{
+ return t == 0 || t == (NTTIME)-1;
+}
+
+/*******************************************************************
+ create a 16 bit dos packed date
+********************************************************************/
+static uint16_t make_dos_date1(struct tm *t)
+{
+ uint16_t ret=0;
+ ret = (((uint_t)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1);
+ ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5));
+ return ret;
+}
+
+/*******************************************************************
+ create a 16 bit dos packed time
+********************************************************************/
+static uint16_t make_dos_time1(struct tm *t)
+{
+ uint16_t ret=0;
+ ret = ((((uint_t)t->tm_min >> 3)&0x7) | (((uint_t)t->tm_hour) << 3));
+ ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5));
+ return ret;
+}
+
+/*******************************************************************
+ create a 32 bit dos packed date/time from some parameters
+ This takes a GMT time and returns a packed localtime structure
+********************************************************************/
+static uint32_t make_dos_date(time_t unixdate, int zone_offset)
+{
+ struct tm *t;
+ uint32_t ret=0;
+
+ if (unixdate == 0) {
+ return 0;
+ }
+
+ unixdate -= zone_offset;
+
+ t = gmtime(&unixdate);
+ if (!t) {
+ return 0xFFFFFFFF;
+ }
+
+ ret = make_dos_date1(t);
+ ret = ((ret&0xFFFF)<<16) | make_dos_time1(t);
+
+ return ret;
+}
+
+/*******************************************************************
+put a dos date into a buffer (time/date format)
+This takes GMT time and puts local time in the buffer
+********************************************************************/
+void push_dos_date(uint8_t *buf, int offset, time_t unixdate, int zone_offset)
+{
+ uint32_t x = make_dos_date(unixdate, zone_offset);
+ SIVAL(buf,offset,x);
+}
+
+/*******************************************************************
+put a dos date into a buffer (date/time format)
+This takes GMT time and puts local time in the buffer
+********************************************************************/
+void push_dos_date2(uint8_t *buf,int offset,time_t unixdate, int zone_offset)
+{
+ uint32_t x;
+ x = make_dos_date(unixdate, zone_offset);
+ x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+ SIVAL(buf,offset,x);
+}
+
+/*******************************************************************
+put a dos 32 bit "unix like" date into a buffer. This routine takes
+GMT and converts it to LOCAL time before putting it (most SMBs assume
+localtime for this sort of date)
+********************************************************************/
+void push_dos_date3(uint8_t *buf,int offset,time_t unixdate, int zone_offset)
+{
+ if (!null_time(unixdate)) {
+ unixdate -= zone_offset;
+ }
+ SIVAL(buf,offset,unixdate);
+}
+
+/*******************************************************************
+ interpret a 32 bit dos packed date/time to some parameters
+********************************************************************/
+static void interpret_dos_date(uint32_t date,int *year,int *month,int *day,int *hour,int *minute,int *second)
+{
+ uint32_t p0,p1,p2,p3;
+
+ p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF;
+ p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF;
+
+ *second = 2*(p0 & 0x1F);
+ *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3);
+ *hour = (p1>>3)&0xFF;
+ *day = (p2&0x1F);
+ *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1;
+ *year = ((p3>>1)&0xFF) + 80;
+}
+
+/*******************************************************************
+ create a unix date (int GMT) from a dos date (which is actually in
+ localtime)
+********************************************************************/
+time_t pull_dos_date(const uint8_t *date_ptr, int zone_offset)
+{
+ uint32_t dos_date=0;
+ struct tm t;
+ time_t ret;
+
+ dos_date = IVAL(date_ptr,0);
+
+ if (dos_date == 0) return (time_t)0;
+
+ interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
+ &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
+ t.tm_isdst = -1;
+
+ ret = timegm(&t);
+
+ ret += zone_offset;
+
+ return ret;
+}
+
+/*******************************************************************
+like make_unix_date() but the words are reversed
+********************************************************************/
+time_t pull_dos_date2(const uint8_t *date_ptr, int zone_offset)
+{
+ uint32_t x,x2;
+
+ x = IVAL(date_ptr,0);
+ x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+ SIVAL(&x,0,x2);
+
+ return pull_dos_date((void *)&x, zone_offset);
+}
+
+/*******************************************************************
+ create a unix GMT date from a dos date in 32 bit "unix like" format
+ these generally arrive as localtimes, with corresponding DST
+ ******************************************************************/
+time_t pull_dos_date3(const uint8_t *date_ptr, int zone_offset)
+{
+ time_t t = (time_t)IVAL(date_ptr,0);
+ if (!null_time(t)) {
+ t += zone_offset;
+ }
+ return t;
+}
+
+
+/***************************************************************************
+return a HTTP/1.0 time string
+ ***************************************************************************/
+char *http_timestring(TALLOC_CTX *mem_ctx, time_t t)
+{
+ char *buf;
+ char tempTime[60];
+ struct tm *tm = localtime(&t);
+
+ if (!tm) {
+ return talloc_asprintf(mem_ctx,"%ld seconds since the Epoch",(long)t);
+ }
+
+#ifndef HAVE_STRFTIME
+ buf = talloc_strdup(mem_ctx, asctime(tm));
+ if (buf[strlen(buf)-1] == '\n') {
+ buf[strlen(buf)-1] = 0;
+ }
+#else
+ strftime(tempTime, sizeof(tempTime)-1, "%a, %d %b %Y %H:%M:%S %Z", tm);
+ buf = talloc_strdup(mem_ctx, tempTime);
+#endif /* !HAVE_STRFTIME */
+
+ return buf;
+}
+
+/****************************************************************************
+ Return the date and time as a string
+****************************************************************************/
+char *timestring(TALLOC_CTX *mem_ctx, time_t t)
+{
+ char *TimeBuf;
+ char tempTime[80];
+ struct tm *tm;
+
+ tm = localtime(&t);
+ if (!tm) {
+ return talloc_asprintf(mem_ctx,
+ "%ld seconds since the Epoch",
+ (long)t);
+ }
+
+#ifdef HAVE_STRFTIME
+ /* some versions of gcc complain about using %c. This is a bug
+ in the gcc warning, not a bug in this code. See a recent
+ strftime() manual page for details.
+ */
+ strftime(tempTime,sizeof(tempTime)-1,"%c %Z",tm);
+ TimeBuf = talloc_strdup(mem_ctx, tempTime);
+#else
+ TimeBuf = talloc_strdup(mem_ctx, asctime(tm));
+#endif
+
+ return TimeBuf;
+}
+
+/*
+ return a talloced string representing a NTTIME for human consumption
+*/
+const char *nt_time_string(TALLOC_CTX *mem_ctx, NTTIME nt)
+{
+ time_t t;
+ if (nt == 0) {
+ return "NTTIME(0)";
+ }
+ t = nt_time_to_unix(nt);
+ return timestring(mem_ctx, t);
+}
+
+
+/*
+ put a NTTIME into a packet
+*/
+void push_nttime(uint8_t *base, uint16_t offset, NTTIME t)
+{
+ SBVAL(base, offset, t);
+}
+
+/*
+ pull a NTTIME from a packet
+*/
+NTTIME pull_nttime(uint8_t *base, uint16_t offset)
+{
+ NTTIME ret = BVAL(base, offset);
+ return ret;
+}
+
+/*
+ parse a nttime as a large integer in a string and return a NTTIME
+*/
+NTTIME nttime_from_string(const char *s)
+{
+ return strtoull(s, NULL, 0);
+}
+
+/*
+ return (tv1 - tv2) in microseconds
+*/
+int64_t usec_time_diff(struct timeval *tv1, struct timeval *tv2)
+{
+ int64_t sec_diff = tv1->tv_sec - tv2->tv_sec;
+ return (sec_diff * 1000000) + (int64_t)(tv1->tv_usec - tv2->tv_usec);
+}
+
+
+/*
+ return a zero timeval
+*/
+struct timeval timeval_zero(void)
+{
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ return tv;
+}
+
+/*
+ return True if a timeval is zero
+*/
+BOOL timeval_is_zero(const struct timeval *tv)
+{
+ return tv->tv_sec == 0 && tv->tv_usec == 0;
+}
+
+/*
+ return a timeval for the current time
+*/
+struct timeval timeval_current(void)
+{
+ struct timeval tv;
+ GetTimeOfDay(&tv);
+ return tv;
+}
+
+/*
+ return a timeval struct with the given elements
+*/
+struct timeval timeval_set(uint32_t secs, uint32_t usecs)
+{
+ struct timeval tv;
+ tv.tv_sec = secs;
+ tv.tv_usec = usecs;
+ return tv;
+}
+
+
+/*
+ return a timeval ofs microseconds after tv
+*/
+struct timeval timeval_add(const struct timeval *tv,
+ uint32_t secs, uint32_t usecs)
+{
+ struct timeval tv2 = *tv;
+ const uint_t million = 1000000;
+ tv2.tv_sec += secs;
+ tv2.tv_usec += usecs;
+ tv2.tv_sec += tv2.tv_usec / million;
+ tv2.tv_usec = tv2.tv_usec % million;
+ return tv2;
+}
+
+/*
+ return the sum of two timeval structures
+*/
+struct timeval timeval_sum(const struct timeval *tv1,
+ const struct timeval *tv2)
+{
+ return timeval_add(tv1, tv2->tv_sec, tv2->tv_usec);
+}
+
+/*
+ return a timeval secs/usecs into the future
+*/
+struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs)
+{
+ struct timeval tv = timeval_current();
+ return timeval_add(&tv, secs, usecs);
+}
+
+/*
+ compare two timeval structures.
+ Return -1 if tv1 < tv2
+ Return 0 if tv1 == tv2
+ Return 1 if tv1 > tv2
+*/
+int timeval_compare(const struct timeval *tv1, const struct timeval *tv2)
+{
+ if (tv1->tv_sec > tv2->tv_sec) return 1;
+ if (tv1->tv_sec < tv2->tv_sec) return -1;
+ if (tv1->tv_usec > tv2->tv_usec) return 1;
+ if (tv1->tv_usec < tv2->tv_usec) return -1;
+ return 0;
+}
+
+/*
+ return True if a timer is in the past
+*/
+BOOL timeval_expired(const struct timeval *tv)
+{
+ struct timeval tv2 = timeval_current();
+ if (tv2.tv_sec > tv->tv_sec) return True;
+ if (tv2.tv_sec < tv->tv_sec) return False;
+ return (tv2.tv_usec >= tv->tv_usec);
+}
+
+/*
+ return the number of seconds elapsed between two times
+*/
+double timeval_elapsed2(const struct timeval *tv1, const struct timeval *tv2)
+{
+ return (tv2->tv_sec - tv1->tv_sec) +
+ (tv2->tv_usec - tv1->tv_usec)*1.0e-6;
+}
+
+/*
+ return the number of seconds elapsed since a given time
+*/
+double timeval_elapsed(const struct timeval *tv)
+{
+ struct timeval tv2 = timeval_current();
+ return timeval_elapsed2(tv, &tv2);
+}
+
+/*
+ return the lesser of two timevals
+*/
+struct timeval timeval_min(const struct timeval *tv1,
+ const struct timeval *tv2)
+{
+ if (tv1->tv_sec < tv2->tv_sec) return *tv1;
+ if (tv1->tv_sec > tv2->tv_sec) return *tv2;
+ if (tv1->tv_usec < tv2->tv_usec) return *tv1;
+ return *tv2;
+}
+
+/*
+ return the greater of two timevals
+*/
+struct timeval timeval_max(const struct timeval *tv1,
+ const struct timeval *tv2)
+{
+ if (tv1->tv_sec > tv2->tv_sec) return *tv1;
+ if (tv1->tv_sec < tv2->tv_sec) return *tv2;
+ if (tv1->tv_usec > tv2->tv_usec) return *tv1;
+ return *tv2;
+}
+
+/*
+ return the difference between two timevals as a timeval
+ if tv1 comes after tv2, then return a zero timeval
+ (this is *tv2 - *tv1)
+*/
+struct timeval timeval_until(const struct timeval *tv1,
+ const struct timeval *tv2)
+{
+ struct timeval t;
+ if (timeval_compare(tv1, tv2) >= 0) {
+ return timeval_zero();
+ }
+ t.tv_sec = tv2->tv_sec - tv1->tv_sec;
+ if (tv1->tv_usec > tv2->tv_usec) {
+ t.tv_sec--;
+ t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec);
+ } else {
+ t.tv_usec = tv2->tv_usec - tv1->tv_usec;
+ }
+ return t;
+}
+
+
+/*
+ convert a timeval to a NTTIME
+*/
+NTTIME timeval_to_nttime(const struct timeval *tv)
+{
+ return 10*(tv->tv_usec +
+ ((TIME_FIXUP_CONSTANT + (uint64_t)tv->tv_sec) * 1000000));
+}
+
+/*******************************************************************
+yield the difference between *A and *B, in seconds, ignoring leap seconds
+********************************************************************/
+static int tm_diff(struct tm *a, struct tm *b)
+{
+ int ay = a->tm_year + (1900 - 1);
+ int by = b->tm_year + (1900 - 1);
+ int intervening_leap_days =
+ (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
+ int years = ay - by;
+ int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday);
+ int hours = 24*days + (a->tm_hour - b->tm_hour);
+ int minutes = 60*hours + (a->tm_min - b->tm_min);
+ int seconds = 60*minutes + (a->tm_sec - b->tm_sec);
+
+ return seconds;
+}
+
+/*******************************************************************
+ return the UTC offset in seconds west of UTC, or 0 if it cannot be determined
+ ******************************************************************/
+int get_time_zone(time_t t)
+{
+ struct tm *tm = gmtime(&t);
+ struct tm tm_utc;
+ if (!tm)
+ return 0;
+ tm_utc = *tm;
+ tm = localtime(&t);
+ if (!tm)
+ return 0;
+ return tm_diff(&tm_utc,tm);
+}
diff --git a/source4/lib/util/unix_privs.c b/source4/lib/util/unix_privs.c
new file mode 100644
index 0000000000..3c0f319776
--- /dev/null
+++ b/source4/lib/util/unix_privs.c
@@ -0,0 +1,68 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ gain/lose root privileges
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+
+/*
+ there are times when smbd needs to temporarily gain root privileges
+ to do some operation. To do this you call root_privileges(), which
+ returns a talloc handle. To restore your previous privileges
+ talloc_free() this pointer.
+
+ Note that this call is considered successful even if it does not
+ manage to gain root privileges, but it will call smb_abort() if it
+ fails to restore the privileges afterwards. The logic is that
+ failing to gain root access can be caught by whatever operation
+ needs to be run as root failing, but failing to lose the root
+ privileges is dangerous.
+
+ This also means that this code is safe to be called from completely
+ unprivileged processes.
+*/
+
+struct saved_state {
+ uid_t uid;
+};
+
+static int privileges_destructor(void *ptr)
+{
+ struct saved_state *s = ptr;
+ if (geteuid() != s->uid &&
+ seteuid(s->uid) != 0) {
+ smb_panic("Failed to restore privileges");
+ }
+ return 0;
+}
+
+void *root_privileges(void)
+{
+ struct saved_state *s;
+ s = talloc(NULL, struct saved_state);
+ if (!s) return NULL;
+ s->uid = geteuid();
+ if (s->uid != 0) {
+ seteuid(0);
+ }
+ talloc_set_destructor(s, privileges_destructor);
+ return s;
+}
diff --git a/source4/lib/util/util.c b/source4/lib/util/util.c
new file mode 100644
index 0000000000..17dde332e1
--- /dev/null
+++ b/source4/lib/util/util.c
@@ -0,0 +1,737 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2001-2002
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003.
+ Copyright (C) James J Myers 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "dynconfig.h"
+#include "system/network.h"
+#include "system/iconv.h"
+#include "system/filesys.h"
+
+/***************************************************************************
+ Find a suitable temporary directory. The result should be copied immediately
+ as it may be overwritten by a subsequent call.
+****************************************************************************/
+const char *tmpdir(void)
+{
+ char *p;
+ if ((p = getenv("TMPDIR")))
+ return p;
+ return "/tmp";
+}
+
+
+/*******************************************************************
+ Check if a file exists - call vfs_file_exist for samba files.
+********************************************************************/
+BOOL file_exist(const char *fname)
+{
+ struct stat st;
+
+ if (stat(fname, &st) != 0) {
+ return False;
+ }
+
+ return ((S_ISREG(st.st_mode)) || (S_ISFIFO(st.st_mode)));
+}
+
+/*******************************************************************
+ Check a files mod time.
+********************************************************************/
+
+time_t file_modtime(const char *fname)
+{
+ struct stat st;
+
+ if (stat(fname,&st) != 0)
+ return(0);
+
+ return(st.st_mtime);
+}
+
+/*******************************************************************
+ Check if a directory exists.
+********************************************************************/
+
+BOOL directory_exist(const char *dname)
+{
+ struct stat st;
+ BOOL ret;
+
+ if (stat(dname,&st) != 0) {
+ return False;
+ }
+
+ ret = S_ISDIR(st.st_mode);
+ if(!ret)
+ errno = ENOTDIR;
+ return ret;
+}
+
+BOOL directory_create_or_exist(const char *dname, uid_t uid,
+ mode_t dir_perms)
+{
+ mode_t old_umask;
+ struct stat st;
+
+ old_umask = umask(0);
+ if (lstat(dname, &st) == -1) {
+ if (errno == ENOENT) {
+ /* Create directory */
+ if (mkdir(dname, dir_perms) == -1) {
+ DEBUG(0, ("error creating directory "
+ "%s: %s\n", dname,
+ strerror(errno)));
+ umask(old_umask);
+ return False;
+ }
+ } else {
+ DEBUG(0, ("lstat failed on directory %s: %s\n",
+ dname, strerror(errno)));
+ umask(old_umask);
+ return False;
+ }
+ } else {
+ /* Check ownership and permission on existing directory */
+ if (!S_ISDIR(st.st_mode)) {
+ DEBUG(0, ("directory %s isn't a directory\n",
+ dname));
+ umask(old_umask);
+ return False;
+ }
+ if ((st.st_uid != uid) ||
+ ((st.st_mode & 0777) != dir_perms)) {
+ DEBUG(0, ("invalid permissions on directory "
+ "%s\n", dname));
+ umask(old_umask);
+ return False;
+ }
+ }
+ return True;
+}
+
+
+/*******************************************************************
+ Close the low 3 fd's and open dev/null in their place.
+********************************************************************/
+static void close_low_fds(BOOL stderr_too)
+{
+#ifndef VALGRIND
+ int fd;
+ int i;
+
+ close(0);
+ close(1);
+
+ if (stderr_too)
+ close(2);
+
+ /* try and use up these file descriptors, so silly
+ library routines writing to stdout etc won't cause havoc */
+ for (i=0;i<3;i++) {
+ if (i == 2 && !stderr_too)
+ continue;
+
+ fd = open("/dev/null",O_RDWR,0);
+ if (fd < 0)
+ fd = open("/dev/null",O_WRONLY,0);
+ if (fd < 0) {
+ DEBUG(0,("Can't open /dev/null\n"));
+ return;
+ }
+ if (fd != i) {
+ DEBUG(0,("Didn't get file descriptor %d\n",i));
+ return;
+ }
+ }
+#endif
+}
+
+/****************************************************************************
+ Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
+ else
+ if SYSV use O_NDELAY
+ if BSD use FNDELAY
+****************************************************************************/
+
+int set_blocking(int fd, BOOL set)
+{
+ int val;
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+
+ if((val = fcntl(fd, F_GETFL, 0)) == -1)
+ return -1;
+ if(set) /* Turn blocking on - ie. clear nonblock flag */
+ val &= ~FLAG_TO_SET;
+ else
+ val |= FLAG_TO_SET;
+ return fcntl( fd, F_SETFL, val);
+#undef FLAG_TO_SET
+}
+
+
+/*******************************************************************
+ Sleep for a specified number of milliseconds.
+********************************************************************/
+
+void msleep(uint_t t)
+{
+ struct timeval tval;
+
+ tval.tv_sec = t/1000;
+ tval.tv_usec = 1000*(t%1000);
+ /* this should be the real select - do NOT replace
+ with sys_select() */
+ select(0,NULL,NULL,NULL,&tval);
+}
+
+/****************************************************************************
+ Become a daemon, discarding the controlling terminal.
+****************************************************************************/
+
+void become_daemon(BOOL Fork)
+{
+ if (Fork) {
+ if (fork()) {
+ _exit(0);
+ }
+ }
+
+ /* detach from the terminal */
+#ifdef HAVE_SETSID
+ setsid();
+#elif defined(TIOCNOTTY)
+ {
+ int i = open("/dev/tty", O_RDWR, 0);
+ if (i != -1) {
+ ioctl(i, (int) TIOCNOTTY, (char *)0);
+ close(i);
+ }
+ }
+#endif /* HAVE_SETSID */
+
+ /* Close fd's 0,1,2. Needed if started by rsh */
+ close_low_fds(False); /* Don't close stderr, let the debug system
+ attach it to the logfile */
+}
+
+
+/****************************************************************************
+ Free memory, checks for NULL.
+ Use directly SAFE_FREE()
+ Exists only because we need to pass a function pointer somewhere --SSS
+****************************************************************************/
+
+void safe_free(void *p)
+{
+ SAFE_FREE(p);
+}
+
+
+/*
+ see if a string matches either our primary or one of our secondary
+ netbios aliases. do a case insensitive match
+*/
+BOOL is_myname(const char *name)
+{
+ const char **aliases;
+ int i;
+
+ if (strcasecmp(name, lp_netbios_name()) == 0) {
+ return True;
+ }
+
+ aliases = lp_netbios_aliases();
+ for (i=0; aliases && aliases[i]; i++) {
+ if (strcasecmp(name, aliases[i]) == 0) {
+ return True;
+ }
+ }
+
+ return False;
+}
+
+
+/****************************************************************************
+ Get my own name, return in malloc'ed storage.
+****************************************************************************/
+
+char* get_myname(void)
+{
+ char *hostname;
+ const int host_name_max = 255;
+ char *p;
+
+ hostname = malloc(host_name_max+1);
+ *hostname = 0;
+
+ /* get my host name */
+ if (gethostname(hostname, host_name_max+1) == -1) {
+ DEBUG(0,("gethostname failed\n"));
+ return NULL;
+ }
+
+ /* Ensure null termination. */
+ hostname[host_name_max] = '\0';
+
+ /* split off any parts after an initial . */
+ p = strchr_m(hostname,'.');
+
+ if (p)
+ *p = 0;
+
+ return hostname;
+}
+
+/****************************************************************************
+ Return true if a string could be a pure IP address.
+****************************************************************************/
+
+BOOL is_ipaddress(const char *str)
+{
+ BOOL pure_address = True;
+ int i;
+
+ for (i=0; pure_address && str[i]; i++)
+ if (!(isdigit((int)str[i]) || str[i] == '.'))
+ pure_address = False;
+
+ /* Check that a pure number is not misinterpreted as an IP */
+ pure_address = pure_address && (strchr_m(str, '.') != NULL);
+
+ return pure_address;
+}
+
+/****************************************************************************
+ Interpret an internet address or name into an IP address in 4 byte form.
+****************************************************************************/
+uint32_t interpret_addr(const char *str)
+{
+ struct hostent *hp;
+ uint32_t res;
+
+ if (str == NULL || *str == 0 ||
+ strcmp(str,"0.0.0.0") == 0) {
+ return 0;
+ }
+ if (strcmp(str,"255.255.255.255") == 0) {
+ return 0xFFFFFFFF;
+ }
+ /* recognise 'localhost' as a special name. This fixes problems with
+ some hosts that don't have localhost in /etc/hosts */
+ if (strcasecmp(str,"localhost") == 0) {
+ str = "127.0.0.1";
+ }
+
+ /* if it's in the form of an IP address then get the lib to interpret it */
+ if (is_ipaddress(str)) {
+ res = inet_addr(str);
+ } else {
+ /* otherwise assume it's a network name of some sort and use
+ sys_gethostbyname */
+ if ((hp = sys_gethostbyname(str)) == 0) {
+ DEBUG(3,("sys_gethostbyname: Unknown host. %s\n",str));
+ return 0;
+ }
+
+ if(hp->h_addr == NULL) {
+ DEBUG(3,("sys_gethostbyname: host address is invalid for host %s\n",str));
+ return 0;
+ }
+ memcpy((char *)&res,(char *)hp->h_addr, 4);
+ }
+
+ if (res == (uint32_t)-1)
+ return(0);
+
+ return(res);
+}
+
+/*******************************************************************
+ A convenient addition to interpret_addr().
+******************************************************************/
+struct ipv4_addr interpret_addr2(const char *str)
+{
+ struct ipv4_addr ret;
+ uint32_t a = interpret_addr(str);
+ ret.addr = a;
+ return ret;
+}
+
+/*******************************************************************
+ Check if an IP is the 0.0.0.0.
+******************************************************************/
+
+BOOL is_zero_ip(struct ipv4_addr ip)
+{
+ return ip.addr == 0;
+}
+
+/*******************************************************************
+ Are two IPs on the same subnet?
+********************************************************************/
+
+BOOL same_net(struct ipv4_addr ip1,struct ipv4_addr ip2,struct ipv4_addr mask)
+{
+ uint32_t net1,net2,nmask;
+
+ nmask = ntohl(mask.addr);
+ net1 = ntohl(ip1.addr);
+ net2 = ntohl(ip2.addr);
+
+ return((net1 & nmask) == (net2 & nmask));
+}
+
+
+/****************************************************************************
+ Check if a process exists. Does this work on all unixes?
+****************************************************************************/
+
+BOOL process_exists(pid_t pid)
+{
+ /* Doing kill with a non-positive pid causes messages to be
+ * sent to places we don't want. */
+ SMB_ASSERT(pid > 0);
+ return(kill(pid,0) == 0 || errno != ESRCH);
+}
+
+/****************************************************************************
+ Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping
+ is dealt with in posix.c
+****************************************************************************/
+
+BOOL fcntl_lock(int fd, int op, off_t offset, off_t count, int type)
+{
+ struct flock lock;
+ int ret;
+
+ DEBUG(8,("fcntl_lock %d %d %.0f %.0f %d\n",fd,op,(double)offset,(double)count,type));
+
+ lock.l_type = type;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = offset;
+ lock.l_len = count;
+ lock.l_pid = 0;
+
+ ret = fcntl(fd,op,&lock);
+
+ if (ret == -1 && errno != 0)
+ DEBUG(3,("fcntl_lock: fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
+
+ /* a lock query */
+ if (op == F_GETLK) {
+ if ((ret != -1) &&
+ (lock.l_type != F_UNLCK) &&
+ (lock.l_pid != 0) &&
+ (lock.l_pid != getpid())) {
+ DEBUG(3,("fcntl_lock: fd %d is locked by pid %d\n",fd,(int)lock.l_pid));
+ return(True);
+ }
+
+ /* it must be not locked or locked by me */
+ return(False);
+ }
+
+ /* a lock set or unset */
+ if (ret == -1) {
+ DEBUG(3,("fcntl_lock: lock failed at offset %.0f count %.0f op %d type %d (%s)\n",
+ (double)offset,(double)count,op,type,strerror(errno)));
+ return(False);
+ }
+
+ /* everything went OK */
+ DEBUG(8,("fcntl_lock: Lock call successful\n"));
+
+ return(True);
+}
+
+
+static void print_asc(int level, const uint8_t *buf,int len)
+{
+ int i;
+ for (i=0;i<len;i++)
+ DEBUGADD(level,("%c", isprint(buf[i])?buf[i]:'.'));
+}
+
+void dump_data(int level, const uint8_t *buf,int len)
+{
+ int i=0;
+ if (len<=0) return;
+
+ if (!DEBUGLVL(level)) return;
+
+ DEBUGADD(level,("[%03X] ",i));
+ for (i=0;i<len;) {
+ DEBUGADD(level,("%02X ",(int)buf[i]));
+ i++;
+ if (i%8 == 0) DEBUGADD(level,(" "));
+ if (i%16 == 0) {
+ print_asc(level,&buf[i-16],8); DEBUGADD(level,(" "));
+ print_asc(level,&buf[i-8],8); DEBUGADD(level,("\n"));
+ if (i<len) DEBUGADD(level,("[%03X] ",i));
+ }
+ }
+ if (i%16) {
+ int n;
+ n = 16 - (i%16);
+ DEBUGADD(level,(" "));
+ if (n>8) DEBUGADD(level,(" "));
+ while (n--) DEBUGADD(level,(" "));
+ n = MIN(8,i%16);
+ print_asc(level,&buf[i-(i%16)],n); DEBUGADD(level,( " " ));
+ n = (i%16) - n;
+ if (n>0) print_asc(level,&buf[i-n],n);
+ DEBUGADD(level,("\n"));
+ }
+}
+
+/*****************************************************************
+ 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;
+}
+
+
+/*****************************************************************
+ Like strdup but for memory.
+*****************************************************************/
+
+void *memdup(const void *p, size_t size)
+{
+ void *p2;
+ if (size == 0)
+ return NULL;
+ p2 = malloc(size);
+ if (!p2)
+ return NULL;
+ memcpy(p2, p, size);
+ return p2;
+}
+
+/*****************************************************************
+ A useful function for returning a path in the Samba lock directory.
+*****************************************************************/
+char *lock_path(TALLOC_CTX* mem_ctx, const char *name)
+{
+ char *fname, *dname;
+ if (name == NULL) {
+ return NULL;
+ }
+ if (name[0] == 0 || name[0] == '/' || strstr(name, ":/")) {
+ return talloc_strdup(mem_ctx, name);
+ }
+
+ dname = talloc_strdup(mem_ctx, lp_lockdir());
+ trim_string(dname,"","/");
+
+ if (!directory_exist(dname)) {
+ mkdir(dname,0755);
+ }
+
+ fname = talloc_asprintf(mem_ctx, "%s/%s", dname, name);
+
+ talloc_free(dname);
+
+ return fname;
+}
+
+
+/*****************************************************************
+ A useful function for returning a path in the Samba piddir directory.
+*****************************************************************/
+static char *pid_path(TALLOC_CTX* mem_ctx, const char *name)
+{
+ char *fname, *dname;
+
+ dname = talloc_strdup(mem_ctx, lp_piddir());
+ trim_string(dname,"","/");
+
+ if (!directory_exist(dname)) {
+ mkdir(dname,0755);
+ }
+
+ fname = talloc_asprintf(mem_ctx, "%s/%s", dname, name);
+
+ talloc_free(dname);
+
+ 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 talloc'ed string containing the full path.
+ **/
+
+char *lib_path(TALLOC_CTX* mem_ctx, const char *name)
+{
+ char *fname;
+ fname = talloc_asprintf(mem_ctx, "%s/%s", dyn_LIBDIR, name);
+ return fname;
+}
+
+/**
+ * @brief Returns an absolute path to a file in the Samba private directory.
+ *
+ * @param name File to find, relative to PRIVATEDIR.
+ * if name is not relative, then use it as-is
+ *
+ * @retval Pointer to a talloc'ed string containing the full path.
+ **/
+char *private_path(TALLOC_CTX* mem_ctx, const char *name)
+{
+ char *fname;
+ if (name == NULL) {
+ return NULL;
+ }
+ if (name[0] == 0 || name[0] == '/' || strstr(name, ":/")) {
+ return talloc_strdup(mem_ctx, name);
+ }
+ fname = talloc_asprintf(mem_ctx, "%s/%s", lp_private_dir(), name);
+ return fname;
+}
+
+/*
+ return a path in the smbd.tmp directory, where all temporary file
+ for smbd go. If NULL is passed for name then return the directory
+ path itself
+*/
+char *smbd_tmp_path(TALLOC_CTX *mem_ctx, const char *name)
+{
+ char *fname, *dname;
+
+ dname = pid_path(mem_ctx, "smbd.tmp");
+ if (!directory_exist(dname)) {
+ mkdir(dname,0755);
+ }
+
+ if (name == NULL) {
+ return dname;
+ }
+
+ fname = talloc_asprintf(mem_ctx, "%s/%s", dname, name);
+ talloc_free(dname);
+
+ return fname;
+}
+
+static char *modules_path(TALLOC_CTX* mem_ctx, const char *name)
+{
+ return talloc_asprintf(mem_ctx, "%s/%s", dyn_MODULESDIR, name);
+}
+
+init_module_fn *load_samba_modules(TALLOC_CTX *mem_ctx, const char *subsystem)
+{
+ char *path = modules_path(mem_ctx, subsystem);
+ init_module_fn *ret;
+
+ ret = load_modules(mem_ctx, path);
+
+ talloc_free(path);
+
+ return ret;
+}
+
+void dump_data_pw(const char *msg, const uint8_t * data, size_t len)
+{
+#ifdef DEBUG_PASSWORD
+ DEBUG(11, ("%s", msg));
+ if (data != NULL && len > 0)
+ {
+ dump_data(11, data, len);
+ }
+#endif
+}
+
+
+/* see if a range of memory is all zero. A NULL pointer is considered
+ to be all zero */
+BOOL all_zero(const uint8_t *ptr, uint_t size)
+{
+ int i;
+ if (!ptr) return True;
+ for (i=0;i<size;i++) {
+ if (ptr[i]) return False;
+ }
+ return True;
+}
+
+/*
+ realloc an array, checking for integer overflow in the array size
+*/
+void *realloc_array(void *ptr, size_t el_size, unsigned count)
+{
+#define MAX_MALLOC_SIZE 0x7fffffff
+ if (count == 0 ||
+ count >= MAX_MALLOC_SIZE/el_size) {
+ return NULL;
+ }
+ if (!ptr) {
+ return malloc(el_size * count);
+ }
+ return realloc(ptr, el_size * count);
+}
+
diff --git a/source4/lib/util/util.h b/source4/lib/util/util.h
new file mode 100644
index 0000000000..55d775e25c
--- /dev/null
+++ b/source4/lib/util/util.h
@@ -0,0 +1,81 @@
+/*
+ Unix SMB/CIFS implementation.
+ Utility functions for Samba
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) John H Terpstra 1996-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1999
+ Copyright (C) Paul Ashton 1998 - 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _SAMBA_UTIL_H_
+#define _SAMBA_UTIL_H_
+
+struct substitute_context;
+
+#include "util/xfile.h"
+#include "util/debug.h"
+#include "util/mutex.h"
+#include "util/byteorder.h"
+#include "util/util_proto.h"
+
+/* zero a structure */
+#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
+
+/* zero a structure given a pointer to the structure */
+#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
+
+/* zero a structure given a pointer to the structure - no zero check */
+#define ZERO_STRUCTPN(x) memset((char *)(x), 0, sizeof(*(x)))
+
+/* pointer difference macro */
+#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((const char *)(p1)) - (const char *)(p2)))
+
+/* work out how many elements there are in a static array */
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+/* assert macros */
+#define SMB_ASSERT(b) do { if (!(b)) { \
+ DEBUG(0,("PANIC: assert failed at %s(%d)\n", __FILE__, __LINE__)); \
+ smb_panic("assert failed"); }} while (0)
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+#ifndef ABS
+#define ABS(a) ((a)>0?(a):(-(a)))
+#endif
+
+#ifndef SAFE_FREE /* Oh no this is also defined in tdb.h */
+/**
+ * Free memory if the pointer and zero the pointer.
+ *
+ * @note You are explicitly allowed to pass NULL pointers -- they will
+ * always be ignored.
+ **/
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(discard_const_p(void *, (x))); (x)=NULL;} } while(0)
+#endif
+
+#define malloc_p(type) (type *)malloc(sizeof(type))
+#define malloc_array_p(type, count) (type *)realloc_array(NULL, sizeof(type), count)
+#define realloc_p(p, type, count) (type *)realloc_array(p, sizeof(type), count)
+
+#endif /* _SAMBA_UTIL_H_ */
diff --git a/source4/lib/util/util_file.c b/source4/lib/util/util_file.c
new file mode 100644
index 0000000000..246b03b4aa
--- /dev/null
+++ b/source4/lib/util/util_file.c
@@ -0,0 +1,385 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
+ *
+ * Added afdgets() Jelmer Vernooij 2005
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+#include "system/shmem.h"
+#include "system/filesys.h"
+
+/****************************************************************************
+read a line from a file with possible \ continuation chars.
+Blanks at the start or end of a line are stripped.
+The string will be allocated if s2 is NULL
+****************************************************************************/
+char *fgets_slash(char *s2,int maxlen,XFILE *f)
+{
+ char *s=s2;
+ int len = 0;
+ int c;
+ BOOL start_of_line = True;
+
+ if (x_feof(f))
+ return(NULL);
+
+ if (maxlen <2) return(NULL);
+
+ if (!s2)
+ {
+ maxlen = MIN(maxlen,8);
+ s = (char *)malloc(maxlen);
+ }
+
+ if (!s) return(NULL);
+
+ *s = 0;
+
+ while (len < maxlen-1)
+ {
+ c = x_getc(f);
+ switch (c)
+ {
+ case '\r':
+ break;
+ case '\n':
+ while (len > 0 && s[len-1] == ' ')
+ {
+ s[--len] = 0;
+ }
+ if (len > 0 && s[len-1] == '\\')
+ {
+ s[--len] = 0;
+ start_of_line = True;
+ break;
+ }
+ return(s);
+ case EOF:
+ if (len <= 0 && !s2)
+ SAFE_FREE(s);
+ return(len>0?s:NULL);
+ case ' ':
+ if (start_of_line)
+ break;
+ default:
+ start_of_line = False;
+ s[len++] = c;
+ s[len] = 0;
+ }
+ if (!s2 && len > maxlen-3)
+ {
+ char *t;
+
+ maxlen *= 2;
+ t = realloc_p(s, char, maxlen);
+ if (!t) {
+ DEBUG(0,("fgets_slash: failed to expand buffer!\n"));
+ SAFE_FREE(s);
+ return(NULL);
+ } else s = t;
+ }
+ }
+ return(s);
+}
+
+/* Read one line (data until next newline or eof) and allocate it */
+char *afdgets(int fd, TALLOC_CTX *mem_ctx, size_t hint)
+{
+ char *data = NULL;
+ ssize_t alloc_size = 0, offset = 0, ret;
+ int p;
+
+ if (hint <= 0) hint = 0x100;
+
+ do {
+ alloc_size += hint;
+
+ data = talloc_realloc(mem_ctx, data, char, alloc_size);
+
+ if (!data)
+ return NULL;
+
+ ret = read(fd, data + offset, hint);
+
+ if (ret == -1) {
+ talloc_free(data);
+ return NULL;
+ }
+
+ /* Find newline */
+ for (p = 0; p < ret; p++) {
+ if (data[offset + p] == '\n')
+ break;
+ }
+
+ if (p < ret) {
+ data[offset + p] = '\0';
+
+ /* Go back to position of newline */
+ lseek(fd, p - ret + 1, SEEK_CUR);
+ return data;
+ }
+
+ offset += ret;
+
+ } while (ret == hint);
+
+ data[offset] = '\0';
+
+ return data;
+}
+
+
+/****************************************************************************
+load a file into memory from a fd.
+****************************************************************************/
+
+char *fd_load(int fd, size_t *size, TALLOC_CTX *mem_ctx)
+{
+ struct stat sbuf;
+ char *p;
+
+ if (fstat(fd, &sbuf) != 0) return NULL;
+
+ p = (char *)talloc_size(mem_ctx, sbuf.st_size+1);
+ if (!p) return NULL;
+
+ if (read(fd, p, sbuf.st_size) != sbuf.st_size) {
+ talloc_free(p);
+ return NULL;
+ }
+ p[sbuf.st_size] = 0;
+
+ if (size) *size = sbuf.st_size;
+
+ return p;
+}
+
+/****************************************************************************
+load a file into memory
+****************************************************************************/
+char *file_load(const char *fname, size_t *size, TALLOC_CTX *mem_ctx)
+{
+ int fd;
+ char *p;
+
+ if (!fname || !*fname) return NULL;
+
+ fd = open(fname,O_RDONLY);
+ if (fd == -1) return NULL;
+
+ p = fd_load(fd, size, mem_ctx);
+
+ close(fd);
+
+ return p;
+}
+
+
+/*******************************************************************
+mmap (if possible) or read a file
+********************************************************************/
+void *map_file(const char *fname, size_t size)
+{
+ size_t s2 = 0;
+ void *p = NULL;
+#ifdef HAVE_MMAP
+ int fd;
+ fd = open(fname, O_RDONLY, 0);
+ if (fd == -1) {
+ DEBUG(2,("Failed to load %s - %s\n", fname, strerror(errno)));
+ return NULL;
+ }
+ p = mmap(NULL, size, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
+ close(fd);
+ if (p == MAP_FAILED) {
+ DEBUG(1,("Failed to mmap %s - %s\n", fname, strerror(errno)));
+ return NULL;
+ }
+#endif
+ if (!p) {
+ p = file_load(fname, &s2, talloc_autofree_context());
+ if (!p) return NULL;
+ if (s2 != size) {
+ DEBUG(1,("incorrect size for %s - got %d expected %d\n",
+ fname, (int)s2, (int)size));
+ talloc_free(p);
+ return NULL;
+ }
+ }
+
+ return p;
+}
+
+
+/****************************************************************************
+parse a buffer into lines
+****************************************************************************/
+static char **file_lines_parse(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx)
+{
+ int i;
+ char *s, **ret;
+
+ if (!p) return NULL;
+
+ for (s = p, i=0; s < p+size; s++) {
+ if (s[0] == '\n') i++;
+ }
+
+ ret = talloc_array(mem_ctx, char *, i+2);
+ if (!ret) {
+ talloc_free(p);
+ return NULL;
+ }
+
+ talloc_reference(ret, p);
+
+ memset(ret, 0, sizeof(ret[0])*(i+2));
+ if (numlines) *numlines = i;
+
+ ret[0] = p;
+ for (s = p, i=0; s < p+size; s++) {
+ if (s[0] == '\n') {
+ s[0] = 0;
+ i++;
+ ret[i] = s+1;
+ }
+ if (s[0] == '\r') s[0] = 0;
+ }
+
+ return ret;
+}
+
+
+/****************************************************************************
+load a file into memory and return an array of pointers to lines in the file
+must be freed with talloc_free().
+****************************************************************************/
+char **file_lines_load(const char *fname, int *numlines, TALLOC_CTX *mem_ctx)
+{
+ char *p;
+ char **lines;
+ size_t size;
+
+ p = file_load(fname, &size, mem_ctx);
+ if (!p) return NULL;
+
+ lines = file_lines_parse(p, size, numlines, mem_ctx);
+
+ talloc_free(p);
+
+ return lines;
+}
+
+/****************************************************************************
+load a fd into memory and return an array of pointers to lines in the file
+must be freed with talloc_free(). If convert is true calls unix_to_dos on
+the list.
+****************************************************************************/
+char **fd_lines_load(int fd, int *numlines, TALLOC_CTX *mem_ctx)
+{
+ char *p;
+ char **lines;
+ size_t size;
+
+ p = fd_load(fd, &size, mem_ctx);
+ if (!p) return NULL;
+
+ lines = file_lines_parse(p, size, numlines, mem_ctx);
+
+ talloc_free(p);
+
+ return lines;
+}
+
+
+/****************************************************************************
+take a list of lines and modify them to produce a list where \ continues
+a line
+****************************************************************************/
+void file_lines_slashcont(char **lines)
+{
+ int i, j;
+
+ for (i=0; lines[i];) {
+ int len = strlen(lines[i]);
+ if (lines[i][len-1] == '\\') {
+ lines[i][len-1] = ' ';
+ if (lines[i+1]) {
+ char *p = &lines[i][len];
+ while (p < lines[i+1]) *p++ = ' ';
+ for (j = i+1; lines[j]; j++) lines[j] = lines[j+1];
+ }
+ } else {
+ i++;
+ }
+ }
+}
+
+/*
+ save a lump of data into a file. Mostly used for debugging
+*/
+BOOL file_save(const char *fname, const void *packet, size_t length)
+{
+ int fd;
+ fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (fd == -1) {
+ return False;
+ }
+ if (write(fd, packet, length) != (size_t)length) {
+ return False;
+ }
+ close(fd);
+ return True;
+}
+
+/*
+ see if a file exists
+*/
+BOOL file_exists(const char *path)
+{
+ struct stat st;
+ return (stat(path, &st) == 0);
+}
+
+int vfdprintf(int fd, const char *format, va_list ap) _PRINTF_ATTRIBUTE(2,0)
+{
+ char *p;
+ int len, ret;
+ va_list ap2;
+
+ VA_COPY(ap2, ap);
+
+ len = vasprintf(&p, format, ap2);
+ if (len <= 0) return len;
+ ret = write(fd, p, len);
+ SAFE_FREE(p);
+ return ret;
+}
+
+int fdprintf(int fd, const char *format, ...) _PRINTF_ATTRIBUTE(2,3)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = vfdprintf(fd, format, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/source4/lib/util/util_getent.c b/source4/lib/util/util_getent.c
new file mode 100644
index 0000000000..9f58472fb8
--- /dev/null
+++ b/source4/lib/util/util_getent.c
@@ -0,0 +1,284 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Jeremy Allison 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+
+/****************************************************************
+ Returns a single linked list of group entries.
+ Use grent_free() to free it after use.
+****************************************************************/
+
+struct sys_grent * getgrent_list(void)
+{
+ struct sys_grent *glist;
+ struct sys_grent *gent;
+ struct group *grp;
+
+ gent = malloc_p(struct sys_grent);
+ if (gent == NULL) {
+ DEBUG (0, ("Out of memory in getgrent_list!\n"));
+ return NULL;
+ }
+ memset(gent, '\0', sizeof(struct sys_grent));
+ glist = gent;
+
+ setgrent();
+ grp = getgrent();
+ if (grp == NULL) {
+ endgrent();
+ SAFE_FREE(glist);
+ return NULL;
+ }
+
+ while (grp != NULL) {
+ int i,num;
+
+ if (grp->gr_name) {
+ if ((gent->gr_name = strdup(grp->gr_name)) == NULL)
+ goto err;
+ }
+ if (grp->gr_passwd) {
+ if ((gent->gr_passwd = strdup(grp->gr_passwd)) == NULL)
+ goto err;
+ }
+ gent->gr_gid = grp->gr_gid;
+
+ /* number of strings in gr_mem */
+ for (num = 0; grp->gr_mem[num]; num++)
+ ;
+
+ /* alloc space for gr_mem string pointers */
+ if ((gent->gr_mem = malloc_array_p(char *, num+1)) == NULL)
+ goto err;
+
+ memset(gent->gr_mem, '\0', (num+1) * sizeof(char *));
+
+ for (i=0; i < num; i++) {
+ if ((gent->gr_mem[i] = strdup(grp->gr_mem[i])) == NULL)
+ goto err;
+ }
+ gent->gr_mem[num] = NULL;
+
+ grp = getgrent();
+ if (grp) {
+ gent->next = malloc_p(struct sys_grent);
+ if (gent->next == NULL)
+ goto err;
+ gent = gent->next;
+ memset(gent, '\0', sizeof(struct sys_grent));
+ }
+ }
+
+ endgrent();
+ return glist;
+
+ err:
+
+ endgrent();
+ DEBUG(0, ("Out of memory in getgrent_list!\n"));
+ grent_free(glist);
+ return NULL;
+}
+
+/****************************************************************
+ Free the single linked list of group entries made by
+ getgrent_list()
+****************************************************************/
+
+void grent_free (struct sys_grent *glist)
+{
+ while (glist) {
+ struct sys_grent *prev;
+
+ SAFE_FREE(glist->gr_name);
+ SAFE_FREE(glist->gr_passwd);
+ if (glist->gr_mem) {
+ int i;
+ for (i = 0; glist->gr_mem[i]; i++)
+ SAFE_FREE(glist->gr_mem[i]);
+ SAFE_FREE(glist->gr_mem);
+ }
+ prev = glist;
+ glist = glist->next;
+ SAFE_FREE(prev);
+ }
+}
+
+/****************************************************************
+ Returns a single linked list of passwd entries.
+ Use pwent_free() to free it after use.
+****************************************************************/
+
+struct sys_pwent * getpwent_list(void)
+{
+ struct sys_pwent *plist;
+ struct sys_pwent *pent;
+ struct passwd *pwd;
+
+ pent = malloc_p(struct sys_pwent);
+ if (pent == NULL) {
+ DEBUG (0, ("Out of memory in getpwent_list!\n"));
+ return NULL;
+ }
+ plist = pent;
+
+ setpwent();
+ pwd = getpwent();
+ while (pwd != NULL) {
+ memset(pent, '\0', sizeof(struct sys_pwent));
+ if (pwd->pw_name) {
+ if ((pent->pw_name = strdup(pwd->pw_name)) == NULL)
+ goto err;
+ }
+ if (pwd->pw_passwd) {
+ if ((pent->pw_passwd = strdup(pwd->pw_passwd)) == NULL)
+ goto err;
+ }
+ pent->pw_uid = pwd->pw_uid;
+ pent->pw_gid = pwd->pw_gid;
+ if (pwd->pw_gecos) {
+ if ((pent->pw_name = strdup(pwd->pw_gecos)) == NULL)
+ goto err;
+ }
+ if (pwd->pw_dir) {
+ if ((pent->pw_name = strdup(pwd->pw_dir)) == NULL)
+ goto err;
+ }
+ if (pwd->pw_shell) {
+ if ((pent->pw_name = strdup(pwd->pw_shell)) == NULL)
+ goto err;
+ }
+
+ pwd = getpwent();
+ if (pwd) {
+ pent->next = malloc_p(struct sys_pwent);
+ if (pent->next == NULL)
+ goto err;
+ pent = pent->next;
+ }
+ }
+
+ endpwent();
+ return plist;
+
+ err:
+
+ endpwent();
+ DEBUG(0, ("Out of memory in getpwent_list!\n"));
+ pwent_free(plist);
+ return NULL;
+}
+
+/****************************************************************
+ Free the single linked list of passwd entries made by
+ getpwent_list()
+****************************************************************/
+
+void pwent_free (struct sys_pwent *plist)
+{
+ while (plist) {
+ struct sys_pwent *prev;
+
+ SAFE_FREE(plist->pw_name);
+ SAFE_FREE(plist->pw_passwd);
+ SAFE_FREE(plist->pw_gecos);
+ SAFE_FREE(plist->pw_dir);
+ SAFE_FREE(plist->pw_shell);
+
+ prev = plist;
+ plist = plist->next;
+ SAFE_FREE(prev);
+ }
+}
+
+/****************************************************************
+ Add the individual group users onto the list.
+****************************************************************/
+
+static struct sys_userlist *add_members_to_userlist(struct sys_userlist *list_head, const struct group *grp)
+{
+ size_t num_users, i;
+
+ /* Count the number of users. */
+ for (num_users = 0; grp->gr_mem[num_users]; num_users++)
+ ;
+
+ for (i = 0; i < num_users; i++) {
+ struct sys_userlist *entry = malloc_p(struct sys_userlist);
+ if (entry == NULL) {
+ free_userlist(list_head);
+ return NULL;
+ }
+ entry->unix_name = (char *)strdup(grp->gr_mem[i]);
+ if (entry->unix_name == NULL) {
+ SAFE_FREE(entry);
+ free_userlist(list_head);
+ return NULL;
+ }
+ DLIST_ADD(list_head, entry);
+ }
+ return list_head;
+}
+
+/****************************************************************
+ Get the list of UNIX users in a group.
+ We have to enumerate the /etc/group file as some UNIX getgrnam()
+ calls won't do that for us (notably Tru64 UNIX).
+****************************************************************/
+
+struct sys_userlist *get_users_in_group(const char *gname)
+{
+ struct sys_userlist *list_head = NULL;
+ struct group *gptr;
+
+#if !defined(BROKEN_GETGRNAM)
+ if ((gptr = (struct group *)getgrnam(gname)) == NULL)
+ return NULL;
+ return add_members_to_userlist(list_head, gptr);
+#else
+ /* BROKEN_GETGRNAM - True64 */
+ setgrent();
+ while((gptr = getgrent()) != NULL) {
+ if (strequal(gname, gptr->gr_name)) {
+ list_head = add_members_to_userlist(list_head, gptr);
+ if (list_head == NULL)
+ return NULL;
+ }
+ }
+ endgrent();
+ return list_head;
+#endif
+}
+
+/****************************************************************
+ Free list allocated above.
+****************************************************************/
+
+void free_userlist(struct sys_userlist *list_head)
+{
+ while (list_head) {
+ struct sys_userlist *old_head = list_head;
+ DLIST_REMOVE(list_head, list_head);
+ SAFE_FREE(old_head->unix_name);
+ SAFE_FREE(old_head);
+ }
+}
diff --git a/source4/lib/util/util_pw.c b/source4/lib/util/util_pw.c
new file mode 100644
index 0000000000..19893e396f
--- /dev/null
+++ b/source4/lib/util/util_pw.c
@@ -0,0 +1,89 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Safe versions of getpw* calls
+
+ Copyright (C) Andrew Bartlett 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static struct passwd *alloc_copy_passwd(const struct passwd *from)
+{
+ struct passwd *ret = smb_xmalloc_p(struct passwd);
+ ZERO_STRUCTP(ret);
+ ret->pw_name = smb_xstrdup(from->pw_name);
+ ret->pw_passwd = smb_xstrdup(from->pw_passwd);
+ ret->pw_uid = from->pw_uid;
+ ret->pw_gid = from->pw_gid;
+ ret->pw_gecos = smb_xstrdup(from->pw_gecos);
+ ret->pw_dir = smb_xstrdup(from->pw_dir);
+ ret->pw_shell = smb_xstrdup(from->pw_shell);
+ return ret;
+}
+
+void passwd_free (struct passwd **buf)
+{
+ if (!*buf) {
+ DEBUG(0, ("attempted double-free of allocated passwd\n"));
+ return;
+ }
+
+ SAFE_FREE((*buf)->pw_name);
+ SAFE_FREE((*buf)->pw_passwd);
+ SAFE_FREE((*buf)->pw_gecos);
+ SAFE_FREE((*buf)->pw_dir);
+ SAFE_FREE((*buf)->pw_shell);
+
+ SAFE_FREE(*buf);
+}
+
+struct passwd *getpwnam_alloc(const char *name)
+{
+ struct passwd *temp;
+
+ temp = sys_getpwnam(name);
+
+ if (!temp) {
+#if 0
+ if (errno == ENOMEM) {
+ /* what now? */
+ }
+#endif
+ return NULL;
+ }
+
+ return alloc_copy_passwd(temp);
+}
+
+struct passwd *getpwuid_alloc(uid_t uid)
+{
+ struct passwd *temp;
+
+ temp = sys_getpwuid(uid);
+
+ if (!temp) {
+#if 0
+ if (errno == ENOMEM) {
+ /* what now? */
+ }
+#endif
+ return NULL;
+ }
+
+ return alloc_copy_passwd(temp);
+}
diff --git a/source4/lib/util/util_sock.c b/source4/lib/util/util_sock.c
new file mode 100644
index 0000000000..8a65a27d02
--- /dev/null
+++ b/source4/lib/util/util_sock.c
@@ -0,0 +1,128 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Tim Potter 2000-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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "system/network.h"
+
+enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
+
+static const struct {
+ const char *name;
+ int level;
+ int option;
+ int value;
+ int opttype;
+} socket_options[] = {
+ {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
+ {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
+ {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
+#ifdef TCP_NODELAY
+ {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
+#endif
+#ifdef IPTOS_LOWDELAY
+ {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
+#endif
+#ifdef IPTOS_THROUGHPUT
+ {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
+#endif
+#ifdef SO_REUSEPORT
+ {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
+#endif
+#ifdef SO_SNDBUF
+ {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
+#endif
+#ifdef SO_RCVBUF
+ {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
+#endif
+#ifdef SO_SNDLOWAT
+ {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
+#endif
+#ifdef SO_RCVLOWAT
+ {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
+#endif
+#ifdef SO_SNDTIMEO
+ {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
+#endif
+#ifdef SO_RCVTIMEO
+ {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
+#endif
+ {NULL,0,0,0,0}};
+
+
+/****************************************************************************
+ Set user socket options.
+****************************************************************************/
+void set_socket_options(int fd, const char *options)
+{
+ const char **options_list = str_list_make(NULL, options, " \t,");
+ int j;
+
+ if (!options_list)
+ return;
+
+ for (j = 0; options_list[j]; j++) {
+ const char *tok = options_list[j];
+ int ret=0,i;
+ int value = 1;
+ char *p;
+ BOOL got_value = False;
+
+ if ((p = strchr_m(tok,'='))) {
+ *p = 0;
+ value = atoi(p+1);
+ got_value = True;
+ }
+
+ for (i=0;socket_options[i].name;i++)
+ if (strequal(socket_options[i].name,tok))
+ break;
+
+ if (!socket_options[i].name) {
+ DEBUG(0,("Unknown socket option %s\n",tok));
+ continue;
+ }
+
+ switch (socket_options[i].opttype) {
+ case OPT_BOOL:
+ case OPT_INT:
+ ret = setsockopt(fd,socket_options[i].level,
+ socket_options[i].option,(char *)&value,sizeof(int));
+ break;
+
+ case OPT_ON:
+ if (got_value)
+ DEBUG(0,("syntax error - %s does not take a value\n",tok));
+
+ {
+ int on = socket_options[i].value;
+ ret = setsockopt(fd,socket_options[i].level,
+ socket_options[i].option,(char *)&on,sizeof(int));
+ }
+ break;
+ }
+
+ if (ret != 0)
+ DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok, strerror(errno) ));
+ }
+
+ talloc_free(options_list);
+}
+
diff --git a/source4/lib/util/util_str.c b/source4/lib/util/util_str.c
new file mode 100644
index 0000000000..b46787e3ea
--- /dev/null
+++ b/source4/lib/util/util_str.c
@@ -0,0 +1,1209 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Simo Sorce 2001-2002
+ Copyright (C) Martin Pool 2003
+ Copyright (C) James Peach 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "system/iconv.h"
+#include "smb.h"
+#include "pstring.h"
+#include "lib/ldb/include/ldb.h"
+
+/**
+ * @file
+ * @brief String utilities.
+ **/
+
+/**
+ * Get the next token from a string, return False if none found.
+ * Handles double-quotes.
+ *
+ * Based on a routine by GJC@VILLAGE.COM.
+ * Extensively modified by Andrew.Tridgell@anu.edu.au
+ **/
+BOOL next_token(const char **ptr,char *buff, const char *sep, size_t bufsize)
+{
+ const char *s;
+ BOOL quoted;
+ size_t len=1;
+
+ if (!ptr)
+ return(False);
+
+ s = *ptr;
+
+ /* default to simple separators */
+ if (!sep)
+ sep = " \t\n\r";
+
+ /* find the first non sep char */
+ while (*s && strchr_m(sep,*s))
+ s++;
+
+ /* nothing left? */
+ if (! *s)
+ return(False);
+
+ /* copy over the token */
+ for (quoted = False; len < bufsize && *s && (quoted || !strchr_m(sep,*s)); s++) {
+ if (*s == '\"') {
+ quoted = !quoted;
+ } else {
+ len++;
+ *buff++ = *s;
+ }
+ }
+
+ *ptr = (*s) ? s+1 : s;
+ *buff = 0;
+
+ return(True);
+}
+
+/**
+ Case insensitive string compararison
+**/
+int strcasecmp_m(const char *s1, const char *s2)
+{
+ codepoint_t c1=0, c2=0;
+ size_t size1, size2;
+
+ while (*s1 && *s2) {
+ c1 = next_codepoint(s1, &size1);
+ c2 = next_codepoint(s2, &size2);
+
+ s1 += size1;
+ s2 += size2;
+
+ if (c1 == c2) {
+ continue;
+ }
+
+ if (c1 == INVALID_CODEPOINT ||
+ c2 == INVALID_CODEPOINT) {
+ /* what else can we do?? */
+ return c1 - c2;
+ }
+
+ if (toupper_w(c1) != toupper_w(c2)) {
+ return c1 - c2;
+ }
+ }
+
+ return *s1 - *s2;
+}
+
+/**
+ * Compare 2 strings.
+ *
+ * @note The comparison is case-insensitive.
+ **/
+BOOL strequal(const char *s1, const char *s2)
+{
+ if (s1 == s2)
+ return(True);
+ if (!s1 || !s2)
+ return(False);
+
+ return strcasecmp_m(s1,s2) == 0;
+}
+
+/**
+ Compare 2 strings (case sensitive).
+**/
+BOOL strcsequal(const char *s1,const char *s2)
+{
+ if (s1 == s2)
+ return(True);
+ if (!s1 || !s2)
+ return(False);
+
+ return strcmp(s1,s2) == 0;
+}
+
+
+/**
+Do a case-insensitive, whitespace-ignoring string compare.
+**/
+int strwicmp(const char *psz1, const char *psz2)
+{
+ /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
+ /* appropriate value. */
+ if (psz1 == psz2)
+ return (0);
+ else if (psz1 == NULL)
+ return (-1);
+ else if (psz2 == NULL)
+ return (1);
+
+ /* sync the strings on first non-whitespace */
+ while (1) {
+ while (isspace((int)*psz1))
+ psz1++;
+ while (isspace((int)*psz2))
+ psz2++;
+ if (toupper((unsigned char)*psz1) != toupper((unsigned char)*psz2)
+ || *psz1 == '\0'
+ || *psz2 == '\0')
+ break;
+ psz1++;
+ psz2++;
+ }
+ return (*psz1 - *psz2);
+}
+
+/**
+ String replace.
+ NOTE: oldc and newc must be 7 bit characters
+**/
+void string_replace(char *s, char oldc, char newc)
+{
+ while (*s) {
+ size_t size;
+ codepoint_t c = next_codepoint(s, &size);
+ if (c == oldc) {
+ *s = newc;
+ }
+ s += size;
+ }
+}
+
+/**
+ Trim the specified elements off the front and back of a string.
+**/
+BOOL trim_string(char *s,const char *front,const char *back)
+{
+ BOOL ret = False;
+ size_t front_len;
+ size_t back_len;
+ size_t len;
+
+ /* Ignore null or empty strings. */
+ if (!s || (s[0] == '\0'))
+ return False;
+
+ front_len = front? strlen(front) : 0;
+ back_len = back? strlen(back) : 0;
+
+ len = strlen(s);
+
+ if (front_len) {
+ while (len && strncmp(s, front, front_len)==0) {
+ /* Must use memmove here as src & dest can
+ * easily overlap. Found by valgrind. JRA. */
+ memmove(s, s+front_len, (len-front_len)+1);
+ len -= front_len;
+ ret=True;
+ }
+ }
+
+ if (back_len) {
+ while ((len >= back_len) && strncmp(s+len-back_len,back,back_len)==0) {
+ s[len-back_len]='\0';
+ len -= back_len;
+ ret=True;
+ }
+ }
+ return ret;
+}
+
+/**
+ Find the number of 'c' chars in a string
+**/
+size_t count_chars(const char *s, char c)
+{
+ size_t count = 0;
+
+ while (*s) {
+ size_t size;
+ codepoint_t c2 = next_codepoint(s, &size);
+ if (c2 == c) count++;
+ s += size;
+ }
+
+ return count;
+}
+
+/**
+ Safe string copy into a known length string. maxlength does not
+ include the terminating zero.
+**/
+char *safe_strcpy(char *dest,const char *src, size_t maxlength)
+{
+ size_t len;
+
+ if (!dest) {
+ DEBUG(0,("ERROR: NULL dest in safe_strcpy\n"));
+ return NULL;
+ }
+
+#ifdef DEVELOPER
+ /* We intentionally write out at the extremity of the destination
+ * string. If the destination is too short (e.g. pstrcpy into mallocd
+ * or fstring) then this should cause an error under a memory
+ * checker. */
+ dest[maxlength] = '\0';
+ if (PTR_DIFF(&len, dest) > 0) { /* check if destination is on the stack, ok if so */
+ log_suspicious_usage("safe_strcpy", src);
+ }
+#endif
+
+ if (!src) {
+ *dest = 0;
+ return dest;
+ }
+
+ len = strlen(src);
+
+ if (len > maxlength) {
+ DEBUG(0,("ERROR: string overflow by %u (%u - %u) in safe_strcpy [%.50s]\n",
+ (uint_t)(len-maxlength), (unsigned)len, (unsigned)maxlength, src));
+ len = maxlength;
+ }
+
+ memmove(dest, src, len);
+ dest[len] = 0;
+ return dest;
+}
+
+/**
+ Safe string cat into a string. maxlength does not
+ include the terminating zero.
+**/
+char *safe_strcat(char *dest, const char *src, size_t maxlength)
+{
+ size_t src_len, dest_len;
+
+ if (!dest) {
+ DEBUG(0,("ERROR: NULL dest in safe_strcat\n"));
+ return NULL;
+ }
+
+ if (!src)
+ return dest;
+
+#ifdef DEVELOPER
+ if (PTR_DIFF(&src_len, dest) > 0) { /* check if destination is on the stack, ok if so */
+ log_suspicious_usage("safe_strcat", src);
+ }
+#endif
+ src_len = strlen(src);
+ dest_len = strlen(dest);
+
+ if (src_len + dest_len > maxlength) {
+ DEBUG(0,("ERROR: string overflow by %d in safe_strcat [%.50s]\n",
+ (int)(src_len + dest_len - maxlength), src));
+ if (maxlength > dest_len) {
+ memcpy(&dest[dest_len], src, maxlength - dest_len);
+ }
+ dest[maxlength] = 0;
+ return NULL;
+ }
+
+ memcpy(&dest[dest_len], src, src_len);
+ dest[dest_len + src_len] = 0;
+ return dest;
+}
+
+/**
+ Paranoid strcpy into a buffer of given length (includes terminating
+ zero. Strips out all but 'a-Z0-9' and the character in other_safe_chars
+ and replaces with '_'. Deliberately does *NOT* check for multibyte
+ characters. Don't change it !
+**/
+
+char *alpha_strcpy(char *dest, const char *src, const char *other_safe_chars, size_t maxlength)
+{
+ size_t len, i;
+
+ if (maxlength == 0) {
+ /* can't fit any bytes at all! */
+ return NULL;
+ }
+
+ if (!dest) {
+ DEBUG(0,("ERROR: NULL dest in alpha_strcpy\n"));
+ return NULL;
+ }
+
+ if (!src) {
+ *dest = 0;
+ return dest;
+ }
+
+ len = strlen(src);
+ if (len >= maxlength)
+ len = maxlength - 1;
+
+ if (!other_safe_chars)
+ other_safe_chars = "";
+
+ for(i = 0; i < len; i++) {
+ int val = (src[i] & 0xff);
+ if (isupper(val) || islower(val) || isdigit(val) || strchr_m(other_safe_chars, val))
+ dest[i] = src[i];
+ else
+ dest[i] = '_';
+ }
+
+ dest[i] = '\0';
+
+ return dest;
+}
+
+/**
+ Like strncpy but always null terminates. Make sure there is room!
+ The variable n should always be one less than the available size.
+**/
+
+char *StrnCpy(char *dest,const char *src,size_t n)
+{
+ char *d = dest;
+ if (!dest)
+ return(NULL);
+ if (!src) {
+ *dest = 0;
+ return(dest);
+ }
+ while (n-- && (*d++ = *src++))
+ ;
+ *d = 0;
+ return(dest);
+}
+
+
+/**
+ Routine to get hex characters and turn them into a 16 byte array.
+ the array can be variable length, and any non-hex-numeric
+ characters are skipped. "0xnn" or "0Xnn" is specially catered
+ for.
+
+ valid examples: "0A5D15"; "0x15, 0x49, 0xa2"; "59\ta9\te3\n"
+
+
+**/
+size_t strhex_to_str(char *p, size_t len, const char *strhex)
+{
+ size_t i;
+ size_t num_chars = 0;
+ uint8_t lonybble, hinybble;
+ const char *hexchars = "0123456789ABCDEF";
+ char *p1 = NULL, *p2 = NULL;
+
+ for (i = 0; i < len && strhex[i] != 0; i++) {
+ if (strncasecmp(hexchars, "0x", 2) == 0) {
+ i++; /* skip two chars */
+ continue;
+ }
+
+ if (!(p1 = strchr_m(hexchars, toupper((unsigned char)strhex[i]))))
+ break;
+
+ i++; /* next hex digit */
+
+ if (!(p2 = strchr_m(hexchars, toupper((unsigned char)strhex[i]))))
+ break;
+
+ /* get the two nybbles */
+ hinybble = PTR_DIFF(p1, hexchars);
+ lonybble = PTR_DIFF(p2, hexchars);
+
+ p[num_chars] = (hinybble << 4) | lonybble;
+ num_chars++;
+
+ p1 = NULL;
+ p2 = NULL;
+ }
+ return num_chars;
+}
+
+DATA_BLOB strhex_to_data_blob(const char *strhex)
+{
+ DATA_BLOB ret_blob = data_blob(NULL, strlen(strhex)/2+1);
+
+ ret_blob.length = strhex_to_str((char *)ret_blob.data,
+ strlen(strhex),
+ strhex);
+
+ return ret_blob;
+}
+
+
+/**
+ * Routine to print a buffer as HEX digits, into an allocated string.
+ */
+void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer)
+{
+ int i;
+ char *hex_buffer;
+
+ *out_hex_buffer = smb_xmalloc((len*2)+1);
+ hex_buffer = *out_hex_buffer;
+
+ for (i = 0; i < len; i++)
+ slprintf(&hex_buffer[i*2], 3, "%02X", buff_in[i]);
+}
+
+/**
+ Check if a string is part of a list.
+**/
+BOOL in_list(const char *s, const char *list, BOOL casesensitive)
+{
+ pstring tok;
+ const char *p=list;
+
+ if (!list)
+ return(False);
+
+ while (next_token(&p,tok,LIST_SEP,sizeof(tok))) {
+ if (casesensitive) {
+ if (strcmp(tok,s) == 0)
+ return(True);
+ } else {
+ if (strcasecmp_m(tok,s) == 0)
+ return(True);
+ }
+ }
+ return(False);
+}
+
+/**
+ Set a string value, allocing the space for the string
+**/
+static BOOL string_init(char **dest,const char *src)
+{
+ if (!src) src = "";
+
+ (*dest) = strdup(src);
+ if ((*dest) == NULL) {
+ DEBUG(0,("Out of memory in string_init\n"));
+ return False;
+ }
+ return True;
+}
+
+/**
+ Free a string value.
+**/
+void string_free(char **s)
+{
+ if (s) SAFE_FREE(*s);
+}
+
+/**
+ Set a string value, deallocating any existing space, and allocing the space
+ for the string
+**/
+BOOL string_set(char **dest, const char *src)
+{
+ string_free(dest);
+ return string_init(dest,src);
+}
+
+/**
+ Substitute a string for a pattern in another string. Make sure there is
+ enough room!
+
+ This routine looks for pattern in s and replaces it with
+ insert. It may do multiple replacements.
+
+ Any of " ; ' $ or ` in the insert string are replaced with _
+ if len==0 then the string cannot be extended. This is different from the old
+ use of len==0 which was for no length checks to be done.
+**/
+
+void string_sub(char *s,const char *pattern, const char *insert, size_t len)
+{
+ char *p;
+ ssize_t ls,lp,li, i;
+
+ if (!insert || !pattern || !*pattern || !s)
+ return;
+
+ ls = (ssize_t)strlen(s);
+ lp = (ssize_t)strlen(pattern);
+ li = (ssize_t)strlen(insert);
+
+ if (len == 0)
+ len = ls + 1; /* len is number of *bytes* */
+
+ while (lp <= ls && (p = strstr(s,pattern))) {
+ if (ls + (li-lp) >= len) {
+ DEBUG(0,("ERROR: string overflow by %d in string_sub(%.50s, %d)\n",
+ (int)(ls + (li-lp) - len),
+ pattern, (int)len));
+ break;
+ }
+ if (li != lp) {
+ memmove(p+li,p+lp,strlen(p+lp)+1);
+ }
+ for (i=0;i<li;i++) {
+ switch (insert[i]) {
+ case '`':
+ case '"':
+ case '\'':
+ case ';':
+ case '$':
+ case '%':
+ case '\r':
+ case '\n':
+ p[i] = '_';
+ break;
+ default:
+ p[i] = insert[i];
+ }
+ }
+ s = p + li;
+ ls += (li-lp);
+ }
+}
+
+
+/**
+ Similar to string_sub() but allows for any character to be substituted.
+ Use with caution!
+ if len==0 then the string cannot be extended. This is different from the old
+ use of len==0 which was for no length checks to be done.
+**/
+
+void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
+{
+ char *p;
+ ssize_t ls,lp,li;
+
+ if (!insert || !pattern || !s)
+ return;
+
+ ls = (ssize_t)strlen(s);
+ lp = (ssize_t)strlen(pattern);
+ li = (ssize_t)strlen(insert);
+
+ if (!*pattern)
+ return;
+
+ if (len == 0)
+ len = ls + 1; /* len is number of *bytes* */
+
+ while (lp <= ls && (p = strstr(s,pattern))) {
+ if (ls + (li-lp) >= len) {
+ DEBUG(0,("ERROR: string overflow by %d in all_string_sub(%.50s, %d)\n",
+ (int)(ls + (li-lp) - len),
+ pattern, (int)len));
+ break;
+ }
+ if (li != lp) {
+ memmove(p+li,p+lp,strlen(p+lp)+1);
+ }
+ memcpy(p, insert, li);
+ s = p + li;
+ ls += (li-lp);
+ }
+}
+
+
+/**
+ Strchr and strrchr_m are a bit complex on general multi-byte strings.
+**/
+char *strchr_m(const char *s, char c)
+{
+ /* characters below 0x3F are guaranteed to not appear in
+ non-initial position in multi-byte charsets */
+ if ((c & 0xC0) == 0) {
+ return strchr(s, c);
+ }
+
+ while (*s) {
+ size_t size;
+ codepoint_t c2 = next_codepoint(s, &size);
+ if (c2 == c) {
+ return discard_const(s);
+ }
+ s += size;
+ }
+
+ return NULL;
+}
+
+char *strrchr_m(const char *s, char c)
+{
+ char *ret = NULL;
+
+ /* characters below 0x3F are guaranteed to not appear in
+ non-initial position in multi-byte charsets */
+ if ((c & 0xC0) == 0) {
+ return strrchr(s, c);
+ }
+
+ while (*s) {
+ size_t size;
+ codepoint_t c2 = next_codepoint(s, &size);
+ if (c2 == c) {
+ ret = discard_const(s);
+ }
+ s += size;
+ }
+
+ return ret;
+}
+
+/*
+ return True if any (multi-byte) character is lower case
+*/
+BOOL strhaslower(const char *string)
+{
+ while (*string) {
+ size_t c_size;
+ codepoint_t s;
+ codepoint_t t;
+
+ s = next_codepoint(string, &c_size);
+ string += c_size;
+
+ t = toupper_w(s);
+
+ if (s != t) {
+ return True; /* that means it has lower case chars */
+ }
+ }
+
+ return False;
+}
+
+/*
+ return True if any (multi-byte) character is upper case
+*/
+BOOL strhasupper(const char *string)
+{
+ while (*string) {
+ size_t c_size;
+ codepoint_t s;
+ codepoint_t t;
+
+ s = next_codepoint(string, &c_size);
+ string += c_size;
+
+ t = tolower_w(s);
+
+ if (s != t) {
+ return True; /* that means it has upper case chars */
+ }
+ }
+
+ return False;
+}
+
+/**
+ Convert a string to lower case, allocated with talloc
+**/
+char *strlower_talloc(TALLOC_CTX *ctx, const char *src)
+{
+ size_t size=0;
+ char *dest;
+
+ /* this takes advantage of the fact that upper/lower can't
+ change the length of a character by more than 1 byte */
+ dest = talloc_size(ctx, 2*(strlen(src))+1);
+ if (dest == NULL) {
+ return NULL;
+ }
+
+ while (*src) {
+ size_t c_size;
+ codepoint_t c = next_codepoint(src, &c_size);
+ src += c_size;
+
+ c = tolower_w(c);
+
+ c_size = push_codepoint(dest+size, c);
+ if (c_size == -1) {
+ talloc_free(dest);
+ return NULL;
+ }
+ size += c_size;
+ }
+
+ dest[size] = 0;
+
+ return dest;
+}
+
+/**
+ Convert a string to UPPER case, allocated with talloc
+**/
+char *strupper_talloc(TALLOC_CTX *ctx, const char *src)
+{
+ size_t size=0;
+ char *dest;
+
+ if (!src) {
+ return NULL;
+ }
+
+ /* this takes advantage of the fact that upper/lower can't
+ change the length of a character by more than 1 byte */
+ dest = talloc_size(ctx, 2*(strlen(src))+1);
+ if (dest == NULL) {
+ return NULL;
+ }
+
+ while (*src) {
+ size_t c_size;
+ codepoint_t c = next_codepoint(src, &c_size);
+ src += c_size;
+
+ c = toupper_w(c);
+
+ c_size = push_codepoint(dest+size, c);
+ if (c_size == -1) {
+ talloc_free(dest);
+ return NULL;
+ }
+ size += c_size;
+ }
+
+ dest[size] = 0;
+
+ return dest;
+}
+
+/**
+ Convert a string to lower case.
+**/
+void strlower_m(char *s)
+{
+ char *d;
+
+ /* this is quite a common operation, so we want it to be
+ fast. We optimise for the ascii case, knowing that all our
+ supported multi-byte character sets are ascii-compatible
+ (ie. they match for the first 128 chars) */
+ while (*s && !(((uint8_t)*s) & 0x80)) {
+ *s = tolower((uint8_t)*s);
+ s++;
+ }
+
+ if (!*s)
+ return;
+
+ d = s;
+
+ while (*s) {
+ size_t c_size, c_size2;
+ codepoint_t c = next_codepoint(s, &c_size);
+ c_size2 = push_codepoint(d, tolower_w(c));
+ if (c_size2 > c_size) {
+ DEBUG(0,("FATAL: codepoint 0x%x (0x%x) expanded from %d to %d bytes in strlower_m\n",
+ c, tolower_w(c), (int)c_size, (int)c_size2));
+ smb_panic("codepoint expansion in strlower_m\n");
+ }
+ s += c_size;
+ d += c_size2;
+ }
+ *d = 0;
+}
+
+/**
+ Convert a string to UPPER case.
+**/
+void strupper_m(char *s)
+{
+ char *d;
+
+ /* this is quite a common operation, so we want it to be
+ fast. We optimise for the ascii case, knowing that all our
+ supported multi-byte character sets are ascii-compatible
+ (ie. they match for the first 128 chars) */
+ while (*s && !(((uint8_t)*s) & 0x80)) {
+ *s = toupper((uint8_t)*s);
+ s++;
+ }
+
+ if (!*s)
+ return;
+
+ d = s;
+
+ while (*s) {
+ size_t c_size, c_size2;
+ codepoint_t c = next_codepoint(s, &c_size);
+ c_size2 = push_codepoint(d, toupper_w(c));
+ if (c_size2 > c_size) {
+ DEBUG(0,("FATAL: codepoint 0x%x (0x%x) expanded from %d to %d bytes in strupper_m\n",
+ c, toupper_w(c), (int)c_size, (int)c_size2));
+ smb_panic("codepoint expansion in strupper_m\n");
+ }
+ s += c_size;
+ d += c_size2;
+ }
+ *d = 0;
+}
+
+/**
+ Count the number of UCS2 characters in a string. Normally this will
+ be the same as the number of bytes in a string for single byte strings,
+ but will be different for multibyte.
+**/
+size_t strlen_m(const char *s)
+{
+ size_t count = 0;
+
+ if (!s) {
+ return 0;
+ }
+
+ while (*s && !(((uint8_t)*s) & 0x80)) {
+ s++;
+ count++;
+ }
+
+ if (!*s) {
+ return count;
+ }
+
+ while (*s) {
+ size_t c_size;
+ codepoint_t c = next_codepoint(s, &c_size);
+ if (c < 0x10000) {
+ count += 1;
+ } else {
+ count += 2;
+ }
+ s += c_size;
+ }
+
+ return count;
+}
+
+/**
+ Work out the number of multibyte chars in a string, including the NULL
+ terminator.
+**/
+size_t strlen_m_term(const char *s)
+{
+ if (!s) {
+ return 0;
+ }
+
+ return strlen_m(s) + 1;
+}
+
+/**
+ Unescape a URL encoded string, in place.
+**/
+
+void rfc1738_unescape(char *buf)
+{
+ char *p=buf;
+
+ while ((p=strchr_m(p,'+')))
+ *p = ' ';
+
+ p = buf;
+
+ while (p && *p && (p=strchr_m(p,'%'))) {
+ int c1 = p[1];
+ int c2 = p[2];
+
+ if (c1 >= '0' && c1 <= '9')
+ c1 = c1 - '0';
+ else if (c1 >= 'A' && c1 <= 'F')
+ c1 = 10 + c1 - 'A';
+ else if (c1 >= 'a' && c1 <= 'f')
+ c1 = 10 + c1 - 'a';
+ else {p++; continue;}
+
+ if (c2 >= '0' && c2 <= '9')
+ c2 = c2 - '0';
+ else if (c2 >= 'A' && c2 <= 'F')
+ c2 = 10 + c2 - 'A';
+ else if (c2 >= 'a' && c2 <= 'f')
+ c2 = 10 + c2 - 'a';
+ else {p++; continue;}
+
+ *p = (c1<<4) | c2;
+
+ memmove(p+1, p+3, strlen(p+3)+1);
+ p++;
+ }
+}
+
+/**
+ * Decode a base64 string into a DATA_BLOB - simple and slow algorithm
+ **/
+DATA_BLOB base64_decode_data_blob(TALLOC_CTX *mem_ctx, const char *s)
+{
+ DATA_BLOB ret = data_blob_talloc(mem_ctx, s, strlen(s)+1);
+ ret.length = ldb_base64_decode((char *)ret.data);
+ return ret;
+}
+
+/**
+ * Decode a base64 string in-place - wrapper for the above
+ **/
+void base64_decode_inplace(char *s)
+{
+ ldb_base64_decode(s);
+}
+
+/**
+ * Encode a base64 string into a talloc()ed string caller to free.
+ **/
+char *base64_encode_data_blob(TALLOC_CTX *mem_ctx, DATA_BLOB data)
+{
+ return ldb_base64_encode(mem_ctx, (const char *)data.data, data.length);
+}
+
+#ifdef VALGRIND
+size_t valgrind_strlen(const char *s)
+{
+ size_t count;
+ for(count = 0; *s++; count++)
+ ;
+ return count;
+}
+#endif
+
+
+/*
+ format a string into length-prefixed dotted domain format, as used in NBT
+ and in some ADS structures
+*/
+const char *str_format_nbt_domain(TALLOC_CTX *mem_ctx, const char *s)
+{
+ char *ret;
+ int i;
+ if (!s || !*s) {
+ return talloc_strdup(mem_ctx, "");
+ }
+ ret = talloc_size(mem_ctx, strlen(s)+2);
+ if (!ret) {
+ return ret;
+ }
+
+ memcpy(ret+1, s, strlen(s)+1);
+ ret[0] = '.';
+
+ for (i=0;ret[i];i++) {
+ if (ret[i] == '.') {
+ char *p = strchr(ret+i+1, '.');
+ if (p) {
+ ret[i] = p-(ret+i+1);
+ } else {
+ ret[i] = strlen(ret+i+1);
+ }
+ }
+ }
+
+ return ret;
+}
+
+BOOL add_string_to_array(TALLOC_CTX *mem_ctx,
+ const char *str, const char ***strings, int *num)
+{
+ char *dup_str = talloc_strdup(mem_ctx, str);
+
+ *strings = talloc_realloc(mem_ctx,
+ *strings,
+ const char *, ((*num)+1));
+
+ if ((*strings == NULL) || (dup_str == NULL))
+ return False;
+
+ (*strings)[*num] = dup_str;
+ *num += 1;
+
+ return True;
+}
+
+
+
+/*
+ varient of strcmp() that handles NULL ptrs
+*/
+int strcmp_safe(const char *s1, const char *s2)
+{
+ if (s1 == s2) {
+ return 0;
+ }
+ if (s1 == NULL || s2 == NULL) {
+ return s1?-1:1;
+ }
+ return strcmp(s1, s2);
+}
+
+
+/*******************************************************************
+return the number of bytes occupied by a buffer in ASCII format
+the result includes the null termination
+limited by 'n' bytes
+********************************************************************/
+size_t ascii_len_n(const char *src, size_t n)
+{
+ size_t len;
+
+ len = strnlen(src, n);
+ if (len+1 <= n) {
+ len += 1;
+ }
+
+ return len;
+}
+
+
+/*******************************************************************
+ Return a string representing a CIFS attribute for a file.
+********************************************************************/
+char *attrib_string(TALLOC_CTX *mem_ctx, uint32_t attrib)
+{
+ int i, len;
+ const struct {
+ char c;
+ uint16_t attr;
+ } attr_strs[] = {
+ {'V', FILE_ATTRIBUTE_VOLUME},
+ {'D', FILE_ATTRIBUTE_DIRECTORY},
+ {'A', FILE_ATTRIBUTE_ARCHIVE},
+ {'H', FILE_ATTRIBUTE_HIDDEN},
+ {'S', FILE_ATTRIBUTE_SYSTEM},
+ {'N', FILE_ATTRIBUTE_NORMAL},
+ {'R', FILE_ATTRIBUTE_READONLY},
+ {'d', FILE_ATTRIBUTE_DEVICE},
+ {'t', FILE_ATTRIBUTE_TEMPORARY},
+ {'s', FILE_ATTRIBUTE_SPARSE},
+ {'r', FILE_ATTRIBUTE_REPARSE_POINT},
+ {'c', FILE_ATTRIBUTE_COMPRESSED},
+ {'o', FILE_ATTRIBUTE_OFFLINE},
+ {'n', FILE_ATTRIBUTE_NONINDEXED},
+ {'e', FILE_ATTRIBUTE_ENCRYPTED}
+ };
+ char *ret;
+
+ ret = talloc_size(mem_ctx, ARRAY_SIZE(attr_strs)+1);
+ if (!ret) {
+ return NULL;
+ }
+
+ for (len=i=0; i<ARRAY_SIZE(attr_strs); i++) {
+ if (attrib & attr_strs[i].attr) {
+ ret[len++] = attr_strs[i].c;
+ }
+ }
+
+ ret[len] = 0;
+
+ return ret;
+}
+
+/***************************************************************************
+ Set a boolean variable from the text value stored in the passed string.
+ Returns True in success, False if the passed string does not correctly
+ represent a boolean.
+***************************************************************************/
+
+BOOL set_boolean(const char *boolean_string, BOOL *boolean)
+{
+ if (strwicmp(boolean_string, "yes") == 0 ||
+ strwicmp(boolean_string, "true") == 0 ||
+ strwicmp(boolean_string, "on") == 0 ||
+ strwicmp(boolean_string, "1") == 0) {
+ *boolean = True;
+ return True;
+ } else if (strwicmp(boolean_string, "no") == 0 ||
+ strwicmp(boolean_string, "false") == 0 ||
+ strwicmp(boolean_string, "off") == 0 ||
+ strwicmp(boolean_string, "0") == 0) {
+ *boolean = False;
+ return True;
+ }
+ return False;
+}
+
+BOOL conv_str_bool(const char * str, BOOL * val)
+{
+ char * end = NULL;
+ long lval;
+
+ if (str == NULL || *str == '\0') {
+ return False;
+ }
+
+ lval = strtol(str, &end, 10 /* base */);
+ if (end == NULL || *end != '\0' || end == str) {
+ return set_boolean(str, val);
+ }
+
+ *val = (lval) ? True : False;
+ return True;
+}
+
+/* Convert a size specification like 16K into an integral number of bytes. */
+BOOL conv_str_size(const char * str, uint64_t * val)
+{
+ char * end = NULL;
+ unsigned long long lval;
+
+ if (str == NULL || *str == '\0') {
+ return False;
+ }
+
+ lval = strtoull(str, &end, 10 /* base */);
+ if (end == NULL || end == str) {
+ return False;
+ }
+
+ if (*end) {
+ if (strwicmp(end, "K") == 0) {
+ lval *= 1024ULL;
+ } else if (strwicmp(end, "M") == 0) {
+ lval *= (1024ULL * 1024ULL);
+ } else if (strwicmp(end, "G") == 0) {
+ lval *= (1024ULL * 1024ULL * 1024ULL);
+ } else if (strwicmp(end, "T") == 0) {
+ lval *= (1024ULL * 1024ULL * 1024ULL * 1024ULL);
+ } else if (strwicmp(end, "P") == 0) {
+ lval *= (1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL);
+ } else {
+ return False;
+ }
+ }
+
+ *val = (uint64_t)lval;
+ return True;
+}
+
+BOOL conv_str_u64(const char * str, uint64_t * val)
+{
+ char * end = NULL;
+ unsigned long long lval;
+
+ if (str == NULL || *str == '\0') {
+ return False;
+ }
+
+ lval = strtoull(str, &end, 10 /* base */);
+ if (end == NULL || *end != '\0' || end == str) {
+ return False;
+ }
+
+ *val = (uint64_t)lval;
+ return True;
+}
diff --git a/source4/lib/util/util_strlist.c b/source4/lib/util/util_strlist.c
new file mode 100644
index 0000000000..ec6c58162f
--- /dev/null
+++ b/source4/lib/util/util_strlist.c
@@ -0,0 +1,292 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Jelmer Vernooij 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ build a null terminated list of strings from a input string and a
+ separator list. The separator list must contain characters less than
+ or equal to 0x2f for this to work correctly on multi-byte strings
+*/
+const char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
+{
+ int num_elements = 0;
+ const char **ret = NULL;
+
+ if (sep == NULL) {
+ sep = LIST_SEP;
+ }
+
+ ret = talloc_array(mem_ctx, const char *, 1);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ while (string && *string) {
+ size_t len = strcspn(string, sep);
+ const char **ret2;
+
+ if (len == 0) {
+ string += strspn(string, sep);
+ continue;
+ }
+
+ ret2 = talloc_realloc(mem_ctx, ret, const char *, num_elements+2);
+ if (ret2 == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ ret = ret2;
+
+ ret[num_elements] = talloc_strndup(ret, string, len);
+ if (ret[num_elements] == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+
+ num_elements++;
+ string += len;
+ }
+
+ ret[num_elements] = NULL;
+
+ return ret;
+}
+
+/* build a null terminated list of strings from an argv-like input string
+ Entries are seperated by spaces and can be enclosed by quotes.
+ Does NOT support escaping
+ */
+const char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
+{
+ int num_elements = 0;
+ const char **ret = NULL;
+
+ ret = talloc_array(mem_ctx, const char *, 1);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ if (sep == NULL)
+ sep = " \t\n\r";
+
+ while (string && *string) {
+ size_t len = strcspn(string, sep);
+ char *element;
+ const char **ret2;
+
+ if (len == 0) {
+ string += strspn(string, sep);
+ continue;
+ }
+
+ if (*string == '\"') {
+ string++;
+ len = strcspn(string, "\"");
+ element = talloc_strndup(ret, string, len);
+ string += len + 1;
+ } else {
+ element = talloc_strndup(ret, string, len);
+ string += len;
+ }
+
+ if (element == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+
+ ret2 = talloc_realloc(mem_ctx, ret, const char *, num_elements+2);
+ if (ret2 == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ ret = ret2;
+
+ ret[num_elements] = element;
+
+ num_elements++;
+ }
+
+ ret[num_elements] = NULL;
+
+ return ret;
+
+}
+
+/* join a list back to one string */
+char *str_list_join(TALLOC_CTX *mem_ctx, const char **list, char seperator)
+{
+ char *ret = NULL;
+ int i;
+
+ if (list[0] == NULL)
+ return talloc_strdup(mem_ctx, "");
+
+ ret = talloc_strdup(mem_ctx, list[0]);
+
+ for (i = 1; list[i]; i++) {
+ ret = talloc_asprintf_append(ret, "%c%s", seperator, list[i]);
+ }
+
+ return ret;
+}
+
+/* join a list back to one (shell-like) string; entries
+ * seperated by spaces, using quotes where necessary */
+char *str_list_join_shell(TALLOC_CTX *mem_ctx, const char **list, char sep)
+{
+ char *ret = NULL;
+ int i;
+
+ if (list[0] == NULL)
+ return talloc_strdup(mem_ctx, "");
+
+ if (strchr(list[0], ' ') || strlen(list[0]) == 0)
+ ret = talloc_asprintf(mem_ctx, "\"%s\"", list[0]);
+ else
+ ret = talloc_strdup(mem_ctx, list[0]);
+
+ for (i = 1; list[i]; i++) {
+ if (strchr(list[i], ' ') || strlen(list[i]) == 0)
+ ret = talloc_asprintf_append(ret, "%c\"%s\"", sep, list[i]);
+ else
+ ret = talloc_asprintf_append(ret, "%c%s", sep, list[i]);
+ }
+
+ return ret;
+}
+
+/*
+ return the number of elements in a string list
+*/
+size_t str_list_length(const char **list)
+{
+ size_t ret;
+ for (ret=0;list && list[ret];ret++) /* noop */ ;
+ return ret;
+}
+
+
+/*
+ copy a string list
+*/
+const char **str_list_copy(TALLOC_CTX *mem_ctx, const char **list)
+{
+ int i;
+ const char **ret = talloc_array(mem_ctx, const char *, str_list_length(list)+1);
+ if (ret == NULL) return NULL;
+
+ for (i=0;list && list[i];i++) {
+ ret[i] = talloc_strdup(ret, list[i]);
+ if (ret[i] == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ }
+ ret[i] = NULL;
+ return ret;
+}
+
+/*
+ Return true if all the elements of the list match exactly.
+ */
+BOOL str_list_equal(const char **list1, const char **list2)
+{
+ int i;
+
+ if (list1 == NULL || list2 == NULL) {
+ return (list1 == list2);
+ }
+
+ for (i=0;list1[i] && list2[i];i++) {
+ if (strcmp(list1[i], list2[i]) != 0) {
+ return False;
+ }
+ }
+ if (list1[i] || list2[i]) {
+ return False;
+ }
+ return True;
+}
+
+
+/*
+ add an entry to a string list
+*/
+const char **str_list_add(const char **list, const char *s)
+{
+ size_t len = str_list_length(list);
+ const char **ret;
+
+ ret = talloc_realloc(NULL, list, const char *, len+2);
+ if (ret == NULL) return NULL;
+
+ ret[len] = talloc_strdup(ret, s);
+ if (ret[len] == NULL) return NULL;
+
+ ret[len+1] = NULL;
+
+ return ret;
+}
+
+/*
+ remove an entry from a string list
+*/
+void str_list_remove(const char **list, const char *s)
+{
+ int i;
+
+ for (i=0;list[i];i++) {
+ if (strcmp(list[i], s) == 0) break;
+ }
+ if (!list[i]) return;
+
+ for (;list[i];i++) {
+ list[i] = list[i+1];
+ }
+}
+
+
+/*
+ return True if a string is in a list
+*/
+BOOL str_list_check(const char **list, const char *s)
+{
+ int i;
+
+ for (i=0;list[i];i++) {
+ if (strcmp(list[i], s) == 0) return True;
+ }
+ return False;
+}
+
+/*
+ return True if a string is in a list, case insensitively
+*/
+BOOL str_list_check_ci(const char **list, const char *s)
+{
+ int i;
+
+ for (i=0;list[i];i++) {
+ if (strcasecmp(list[i], s) == 0) return True;
+ }
+ return False;
+}
diff --git a/source4/lib/util/util_unistr.c b/source4/lib/util/util_unistr.c
new file mode 100644
index 0000000000..b35822877c
--- /dev/null
+++ b/source4/lib/util/util_unistr.c
@@ -0,0 +1,150 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "system/iconv.h"
+
+/* these 2 tables define the unicode case handling. They are loaded
+ at startup either via mmap() or read() from the lib directory */
+static void *upcase_table;
+static void *lowcase_table;
+
+
+/*******************************************************************
+load the case handling tables
+********************************************************************/
+static void load_case_tables(void)
+{
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("load_case_tables");
+ if (!mem_ctx) {
+ smb_panic("No memory for case_tables");
+ }
+ upcase_table = map_file(lib_path(mem_ctx, "upcase.dat"), 0x20000);
+ lowcase_table = map_file(lib_path(mem_ctx, "lowcase.dat"), 0x20000);
+ talloc_free(mem_ctx);
+ if (upcase_table == NULL) {
+ /* try also under codepages for testing purposes */
+ upcase_table = map_file("codepages/upcase.dat", 0x20000);
+ if (upcase_table == NULL) {
+ upcase_table = (void *)-1;
+ }
+ }
+ if (lowcase_table == NULL) {
+ /* try also under codepages for testing purposes */
+ lowcase_table = map_file("codepages/lowcase.dat", 0x20000);
+ if (lowcase_table == NULL) {
+ lowcase_table = (void *)-1;
+ }
+ }
+}
+
+/*******************************************************************
+ Convert a codepoint_t to upper case.
+********************************************************************/
+codepoint_t toupper_w(codepoint_t val)
+{
+ if (val < 128) {
+ return toupper(val);
+ }
+ if (upcase_table == NULL) {
+ load_case_tables();
+ }
+ if (upcase_table == (void *)-1) {
+ return val;
+ }
+ if (val & 0xFFFF0000) {
+ return val;
+ }
+ return SVAL(upcase_table, val*2);
+}
+
+/*******************************************************************
+ Convert a codepoint_t to lower case.
+********************************************************************/
+codepoint_t tolower_w(codepoint_t val)
+{
+ if (val < 128) {
+ return tolower(val);
+ }
+ if (lowcase_table == NULL) {
+ load_case_tables();
+ }
+ if (lowcase_table == (void *)-1) {
+ return val;
+ }
+ if (val & 0xFFFF0000) {
+ return val;
+ }
+ return SVAL(lowcase_table, val*2);
+}
+
+/*******************************************************************
+return the number of bytes occupied by a buffer in CH_UTF16 format
+the result includes the null termination
+********************************************************************/
+size_t utf16_len(const void *buf)
+{
+ size_t len;
+
+ for (len = 0; SVAL(buf,len); len += 2) ;
+
+ return len + 2;
+}
+
+/*******************************************************************
+return the number of bytes occupied by a buffer in CH_UTF16 format
+the result includes the null termination
+limited by 'n' bytes
+********************************************************************/
+size_t utf16_len_n(const void *src, size_t n)
+{
+ size_t len;
+
+ for (len = 0; (len+2 < n) && SVAL(src, len); len += 2) ;
+
+ if (len+2 <= n) {
+ len += 2;
+ }
+
+ return len;
+}
+
+
+size_t ucs2_align(const void *base_ptr, const void *p, int flags)
+{
+ if (flags & (STR_NOALIGN|STR_ASCII))
+ return 0;
+ return PTR_DIFF(p, base_ptr) & 1;
+}
+
+/*
+ compare two codepoints case insensitively
+*/
+int codepoint_cmpi(codepoint_t c1, codepoint_t c2)
+{
+ if (c1 == c2 ||
+ toupper_w(c1) == toupper_w(c2)) {
+ return 0;
+ }
+ return c1 - c2;
+}
diff --git a/source4/lib/util/xfile.c b/source4/lib/util/xfile.c
new file mode 100644
index 0000000000..794e3f0f5e
--- /dev/null
+++ b/source4/lib/util/xfile.c
@@ -0,0 +1,384 @@
+/*
+ Unix SMB/CIFS implementation.
+ stdio replacement
+ Copyright (C) Andrew Tridgell 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ stdio is very convenient, but on some systems the file descriptor
+ in FILE* is 8 bits, so it fails when more than 255 files are open.
+
+ XFILE replaces stdio. It is less efficient, but at least it works
+ when you have lots of files open
+
+ The main restriction on XFILE is that it doesn't support seeking,
+ and doesn't support O_RDWR. That keeps the code simple.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+
+#define XBUFSIZE BUFSIZ
+
+static XFILE _x_stdin = { 0, NULL, NULL, XBUFSIZE, 0, O_RDONLY, X_IOFBF, 0 };
+static XFILE _x_stdout = { 1, NULL, NULL, XBUFSIZE, 0, O_WRONLY, X_IOLBF, 0 };
+static XFILE _x_stderr = { 2, NULL, NULL, 0, 0, O_WRONLY, X_IONBF, 0 };
+
+XFILE *x_stdin = &_x_stdin;
+XFILE *x_stdout = &_x_stdout;
+XFILE *x_stderr = &_x_stderr;
+
+#define X_FLAG_EOF 1
+#define X_FLAG_ERROR 2
+#define X_FLAG_EINVAL 3
+
+/* simulate setvbuf() */
+int x_setvbuf(XFILE *f, char *buf, int mode, size_t size)
+{
+ x_fflush(f);
+ if (f->bufused) return -1;
+
+ /* on files being read full buffering is the only option */
+ if ((f->open_flags & O_ACCMODE) == O_RDONLY) {
+ mode = X_IOFBF;
+ }
+
+ /* destroy any earlier buffer */
+ SAFE_FREE(f->buf);
+ f->buf = 0;
+ f->bufsize = 0;
+ f->next = NULL;
+ f->bufused = 0;
+ f->buftype = mode;
+
+ if (f->buftype == X_IONBF) return 0;
+
+ /* if buffering then we need some size */
+ if (size == 0) size = XBUFSIZE;
+
+ f->bufsize = size;
+ f->bufused = 0;
+
+ return 0;
+}
+
+/* allocate the buffer */
+static int x_allocate_buffer(XFILE *f)
+{
+ if (f->buf) return 1;
+ if (f->bufsize == 0) return 0;
+ f->buf = malloc(f->bufsize);
+ if (!f->buf) return 0;
+ f->next = f->buf;
+ return 1;
+}
+
+
+/* this looks more like open() than fopen(), but that is quite deliberate.
+ I want programmers to *think* about O_EXCL, O_CREAT etc not just
+ get them magically added
+*/
+XFILE *x_fopen(const char *fname, int flags, mode_t mode)
+{
+ XFILE *ret;
+
+ ret = malloc_p(XFILE);
+ if (!ret) return NULL;
+
+ memset(ret, 0, sizeof(XFILE));
+
+ if ((flags & O_ACCMODE) == O_RDWR) {
+ /* we don't support RDWR in XFILE - use file
+ descriptors instead */
+ errno = EINVAL;
+ return NULL;
+ }
+
+ ret->open_flags = flags;
+
+ ret->fd = open(fname, flags, mode);
+ if (ret->fd == -1) {
+ SAFE_FREE(ret);
+ return NULL;
+ }
+
+ x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
+
+ return ret;
+}
+
+/* simulate fclose() */
+int x_fclose(XFILE *f)
+{
+ int ret;
+
+ /* make sure we flush any buffered data */
+ x_fflush(f);
+
+ ret = close(f->fd);
+ f->fd = -1;
+ if (f->buf) {
+ /* make sure data can't leak into a later malloc */
+ memset(f->buf, 0, f->bufsize);
+ SAFE_FREE(f->buf);
+ }
+ /* check the file descriptor given to the function is NOT one of the static
+ * descriptor of this libreary or we will free unallocated memory
+ * --sss */
+ if (f != x_stdin && f != x_stdout && f != x_stderr) {
+ SAFE_FREE(f);
+ }
+ return ret;
+}
+
+/* simulate fwrite() */
+size_t x_fwrite(const void *p, size_t size, size_t nmemb, XFILE *f)
+{
+ ssize_t ret;
+ size_t total=0;
+
+ /* we might be writing unbuffered */
+ if (f->buftype == X_IONBF ||
+ (!f->buf && !x_allocate_buffer(f))) {
+ ret = write(f->fd, p, size*nmemb);
+ if (ret == -1) return -1;
+ return ret/size;
+ }
+
+
+ while (total < size*nmemb) {
+ size_t n = f->bufsize - f->bufused;
+ n = MIN(n, (size*nmemb)-total);
+
+ if (n == 0) {
+ /* it's full, flush it */
+ x_fflush(f);
+ continue;
+ }
+
+ memcpy(f->buf + f->bufused, total+(const char *)p, n);
+ f->bufused += n;
+ total += n;
+ }
+
+ /* when line buffered we need to flush at the last linefeed. This can
+ flush a bit more than necessary, but that is harmless */
+ if (f->buftype == X_IOLBF && f->bufused) {
+ int i;
+ for (i=(size*nmemb)-1; i>=0; i--) {
+ if (*(i+(const char *)p) == '\n') {
+ x_fflush(f);
+ break;
+ }
+ }
+ }
+
+ return total/size;
+}
+
+/* thank goodness for asprintf() */
+ int x_vfprintf(XFILE *f, const char *format, va_list ap)
+{
+ char *p;
+ int len, ret;
+ va_list ap2;
+
+ VA_COPY(ap2, ap);
+
+ len = vasprintf(&p, format, ap2);
+ if (len <= 0) return len;
+ ret = x_fwrite(p, 1, len, f);
+ SAFE_FREE(p);
+ return ret;
+}
+
+ int x_fprintf(XFILE *f, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = x_vfprintf(f, format, ap);
+ va_end(ap);
+ return ret;
+}
+
+/* at least fileno() is simple! */
+int x_fileno(XFILE *f)
+{
+ return f->fd;
+}
+
+/* simulate fflush() */
+int x_fflush(XFILE *f)
+{
+ int ret;
+
+ if (f->flags & X_FLAG_ERROR) return -1;
+
+ if ((f->open_flags & O_ACCMODE) != O_WRONLY) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (f->bufused == 0) return 0;
+
+ ret = write(f->fd, f->buf, f->bufused);
+ if (ret == -1) return -1;
+
+ f->bufused -= ret;
+ if (f->bufused > 0) {
+ f->flags |= X_FLAG_ERROR;
+ memmove(f->buf, ret + (char *)f->buf, f->bufused);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* simulate setbuffer() */
+void x_setbuffer(XFILE *f, char *buf, size_t size)
+{
+ x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, size);
+}
+
+/* simulate setbuf() */
+void x_setbuf(XFILE *f, char *buf)
+{
+ x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, XBUFSIZE);
+}
+
+/* simulate setlinebuf() */
+void x_setlinebuf(XFILE *f)
+{
+ x_setvbuf(f, NULL, X_IOLBF, 0);
+}
+
+
+/* simulate feof() */
+int x_feof(XFILE *f)
+{
+ if (f->flags & X_FLAG_EOF) return 1;
+ return 0;
+}
+
+/* simulate ferror() */
+int x_ferror(XFILE *f)
+{
+ if (f->flags & X_FLAG_ERROR) return 1;
+ return 0;
+}
+
+/* fill the read buffer */
+static void x_fillbuf(XFILE *f)
+{
+ int n;
+
+ if (f->bufused) return;
+
+ if (!f->buf && !x_allocate_buffer(f)) return;
+
+ n = read(f->fd, f->buf, f->bufsize);
+ if (n <= 0) return;
+ f->bufused = n;
+ f->next = f->buf;
+}
+
+/* simulate fgetc() */
+int x_fgetc(XFILE *f)
+{
+ int ret;
+
+ if (f->flags & (X_FLAG_EOF | X_FLAG_ERROR)) return EOF;
+
+ if (f->bufused == 0) x_fillbuf(f);
+
+ if (f->bufused == 0) {
+ f->flags |= X_FLAG_EOF;
+ return EOF;
+ }
+
+ ret = *(uint8_t *)(f->next);
+ f->next++;
+ f->bufused--;
+ return ret;
+}
+
+/* simulate fread */
+size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
+{
+ size_t total = 0;
+ while (total < size*nmemb) {
+ int c = x_fgetc(f);
+ if (c == EOF) break;
+ (total+(char *)p)[0] = (char)c;
+ total++;
+ }
+ return total/size;
+}
+
+/* simulate fgets() */
+char *x_fgets(char *s, int size, XFILE *stream)
+{
+ char *s0 = s;
+ int l = size;
+ while (l>1) {
+ int c = x_fgetc(stream);
+ if (c == EOF) break;
+ *s++ = (char)c;
+ l--;
+ if (c == '\n') break;
+ }
+ if (l==size || x_ferror(stream)) {
+ return 0;
+ }
+ *s = 0;
+ return s0;
+}
+
+/* trivial seek, works only for SEEK_SET and SEEK_END if SEEK_CUR is
+ * set then an error is returned */
+off_t x_tseek(XFILE *f, off_t offset, int whence)
+{
+ if (f->flags & X_FLAG_ERROR)
+ return -1;
+
+ /* only SEEK_SET and SEEK_END are supported */
+ /* SEEK_CUR needs internal offset counter */
+ if (whence != SEEK_SET && whence != SEEK_END) {
+ f->flags |= X_FLAG_EINVAL;
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* empty the buffer */
+ switch (f->open_flags & O_ACCMODE) {
+ case O_RDONLY:
+ f->bufused = 0;
+ break;
+ case O_WRONLY:
+ if (x_fflush(f) != 0)
+ return -1;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ f->flags &= ~X_FLAG_EOF;
+ return lseek(f->fd, offset, whence);
+}
diff --git a/source4/lib/util/xfile.h b/source4/lib/util/xfile.h
new file mode 100644
index 0000000000..89fa9d1e11
--- /dev/null
+++ b/source4/lib/util/xfile.h
@@ -0,0 +1,49 @@
+/*
+ Unix SMB/CIFS implementation.
+ stdio replacement
+ Copyright (C) Andrew Tridgell 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _XFILE_H_
+#define _XFILE_H_
+/*
+ see xfile.c for explanations
+*/
+
+typedef struct {
+ int fd;
+ char *buf;
+ char *next;
+ int bufsize;
+ int bufused;
+ int open_flags;
+ int buftype;
+ int flags;
+} XFILE;
+
+extern XFILE *x_stdin, *x_stdout, *x_stderr;
+
+/* buffering type */
+#define X_IOFBF 0
+#define X_IOLBF 1
+#define X_IONBF 2
+
+#define x_getc(f) x_fgetc(f)
+
+int x_vfprintf(XFILE *f, const char *format, va_list ap) PRINTF_ATTRIBUTE(2, 0);
+int x_fprintf(XFILE *f, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
+#endif /* _XFILE_H_ */