wmi-1.3.16 from opsview.com

This commit is contained in:
Are Casilla
2019-02-16 00:16:52 +01:00
parent 163fdd3d1b
commit 17b3af2911
2146 changed files with 678824 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
PROJECT_NAME = SAMBA_UTIL
OUTPUT_DIRECTORY = apidocs
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
OPTIMIZE_OUTPUT_FOR_C = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
GENERATE_TODOLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
SHOW_USED_FILES = NO
SHOW_DIRECTORIES = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
INPUT = .
FILE_PATTERNS = *.c *.h *.dox
GENERATE_HTML = YES
HTML_OUTPUT = html
GENERATE_MAN = YES
ALWAYS_DETAILED_SEC = YES
JAVADOC_AUTOBRIEF = YES
+224
View File
@@ -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 */
+104
View File
@@ -0,0 +1,104 @@
/*
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.
*/
/**
* @file
* @brief Capabilities functions
**/
/*
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
+17
View File
@@ -0,0 +1,17 @@
AC_CACHE_CHECK([for irix specific capabilities],samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES,[
AC_TRY_RUN([#include <sys/types.h>
#include <sys/capability.h>
main() {
cap_t cap;
if ((cap = cap_get_proc()) == NULL)
exit(1);
cap->cap_effective |= CAP_NETWORK_MGT;
cap->cap_inheritable |= CAP_NETWORK_MGT;
cap_set_proc(cap);
exit(0);
}
],
samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES=yes,samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES=no,samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES=cross)])
if test x"$samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES" = x"yes"; then
AC_DEFINE(HAVE_IRIX_SPECIFIC_CAPABILITIES,1,[Whether IRIX specific capabilities are available])
fi
+58
View File
@@ -0,0 +1,58 @@
[SUBSYSTEM::LIBSAMBA-UTIL]
#VERSION = 0.0.1
#SO_VERSION = 0
#DESCRIPTION = Generic utility functions
PUBLIC_PROTO_HEADER = util_proto.h
PUBLIC_HEADERS = util.h \
byteorder.h \
debug.h \
mutex.h \
safe_string.h \
xfile.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_file.o \
data_blob.o \
util.o \
fsusage.o \
ms_fnmatch.o \
mutex.o \
idtree.o \
module.o
PUBLIC_DEPENDENCIES = \
LIBTALLOC LIBCRYPTO \
SOCKET_WRAPPER EXT_NSL \
CHARSET
[SUBSYSTEM::UNIX_PRIVS]
PRIVATE_PROTO_HEADER = unix_privs.h
OBJ_FILES = unix_privs.o
################################################
# Start SUBSYSTEM WRAP_XATTR
[SUBSYSTEM::WRAP_XATTR]
PUBLIC_PROTO_HEADER = wrap_xattr.h
OBJ_FILES = \
wrap_xattr.o
PUBLIC_DEPENDENCIES = XATTR
#
# End SUBSYSTEM WRAP_XATTR
################################################
################################################
# Start SUBSYSTEM UTIL_TDB
[SUBSYSTEM::UTIL_TDB]
PUBLIC_PROTO_HEADER = util_tdb.h
OBJ_FILES = \
util_tdb.o
PUBLIC_DEPENDENCIES = LIBTDB
# End SUBSYSTEM UTIL_TDB
################################################
+231
View File
@@ -0,0 +1,231 @@
/*
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"
/**
* @file
* @brief Manipulation of arbitrary data blobs
**/
/**
construct a data blob, must be freed with data_blob_free()
you can pass NULL for p and get a blank data blob
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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
**/
_PUBLIC_ void data_blob_clear(DATA_BLOB *d)
{
if (d->data) {
memset(d->data, 0, d->length);
}
}
/**
free a data blob and clear its contents
**/
_PUBLIC_ void data_blob_clear_free(DATA_BLOB *d)
{
data_blob_clear(d);
data_blob_free(d);
}
/**
check if two data blobs are equal
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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
**/
_PUBLIC_ DATA_BLOB data_blob_string_const(const char *str)
{
DATA_BLOB blob;
blob.data = discard_const(str);
blob.length = strlen(str);
return blob;
}
/**
* Create a new data blob from const data
*/
_PUBLIC_ 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
**/
_PUBLIC_ 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
**/
_PUBLIC_ NTSTATUS data_blob_append(TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
const void *p, size_t length)
{
NTSTATUS status;
size_t old_len = blob->length;
size_t new_len = old_len + length;
if (new_len < length || new_len < old_len) {
return NT_STATUS_NO_MEMORY;
}
if ((const uint8_t *)p + length < (const uint8_t *)p) {
return NT_STATUS_NO_MEMORY;
}
status = data_blob_realloc(mem_ctx, blob, new_len);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
memcpy(blob->data + old_len, p, length);
return NT_STATUS_OK;
}
+255
View File
@@ -0,0 +1,255 @@
/*
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"
/**
* @file
* @brief Debug logging
**/
/**
* this global variable determines what messages are printed
*/
_PUBLIC_ 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;
static BOOL reopen_logs_scheduled;
static BOOL check_reopen_logs(void)
{
if (state.fd == 0 || reopen_logs_scheduled) {
reopen_logs_scheduled = False;
reopen_logs();
}
if (state.fd <= 0) return False;
return True;
}
_PUBLIC_ void debug_schedule_reopen_logs(void)
{
reopen_logs_scheduled = True;
}
static void log_timestring(int level, const char *location, const char *func)
{
char *t = NULL;
char *s = NULL;
if (!check_reopen_logs()) return;
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);
}
static void log_location(const char* location, const char* func)
{
char *s = NULL;
if (!check_reopen_logs()) return;
if (strncmp(location, "lib/talloc/talloc.c", strlen("lib/talloc/talloc.c")) == 0) return;
asprintf(&s, "[%s:%s()] ", location, func);
if (!s) return;
write(state.fd, s, strlen(s));
free(s);
}
/**
the backend for debug messages. Note that the DEBUG() macro has already
ensured that the log level has been met before this is called
*/
_PUBLIC_ void do_debug_header(int level, const char *location, const char *func)
{
// log_timestring(level, location, func);
log_location(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
@note You should never have to call this function directly. Call the DEBUG()
macro instead.
*/
_PUBLIC_ void do_debug(const char *format, ...) _PRINTF_ATTRIBUTE(1,2)
{
va_list ap;
char *s = NULL;
if (!check_reopen_logs()) return;
va_start(ap, format);
vasprintf(&s, format, ap);
va_end(ap);
write(state.fd, s, strlen(s));
free(s);
}
_PUBLIC_ const char *logfile = NULL;
/**
reopen the log file (usually called because the log file name might have changed)
*/
_PUBLIC_ void reopen_logs(void)
{
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));
old_fd = -1;
} 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
*/
_PUBLIC_ 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
*/
_PUBLIC_ const char *do_debug_tab(int 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 suspicious usage - print comments and backtrace
*/
_PUBLIC_ void log_suspicious_usage(const char *from, const char *info)
{
if (!debug_handlers.ops.log_suspicious_usage) return;
debug_handlers.ops.log_suspicious_usage(from, info);
}
/**
print suspicious usage - print comments and backtrace
*/
_PUBLIC_ void print_suspicious_usage(const char* from, const char* info)
{
if (!debug_handlers.ops.print_suspicious_usage) return;
debug_handlers.ops.print_suspicious_usage(from, info);
}
_PUBLIC_ uint32_t get_task_id(void)
{
if (debug_handlers.ops.get_task_id) {
return debug_handlers.ops.get_task_id();
}
return getpid();
}
_PUBLIC_ void log_task_id(void)
{
if (!debug_handlers.ops.log_task_id) return;
if (!check_reopen_logs()) return;
debug_handlers.ops.log_task_id(state.fd);
}
/**
register a set of debug handlers.
*/
_PUBLIC_ void register_debug_handlers(const char *name, struct debug_ops *ops)
{
debug_handlers.name = name;
debug_handlers.ops = *ops;
}
+76
View File
@@ -0,0 +1,76 @@
/*
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.
*/
/**
* @file
* @brief Debugging macros
*/
/* 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);
};
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__); \
} \
do_debug body; \
} \
} while (0)
/**
* Write to the debug log.
*/
#define DEBUG(level, body) _DEBUG(level, body, True)
/**
* Add data to an existing debug log entry.
*/
#define DEBUGADD(level, body) _DEBUG(level, body, False)
/**
* Obtain indentation string for the debug log.
*
* Level specified by n.
*/
#define DEBUGTAB(n) do_debug_tab(n)
#define DEBUG_FN_ENTER DEBUG(9,("ENTER function %s\n", __FUNCTION__))
#define DEBUG_FN_ENTER_MSG(_msg) DEBUG(9,("ENTER function %s (%s)\n", __FUNCTION__, _msg))
#define DEBUG_FN_EXIT DEBUG(9,("EXIT function %s (PASS)\n", __FUNCTION__))
#define DEBUG_FN_EXIT_MSG(_msg) DEBUG(9,("EXIT function %s (PASS) (%s)\n", __FUNCTION__, _msg))
#define DEBUG_FN_FAIL(_msg) DEBUG(9,("exit function %s (FAIL) (%s)\n", __FUNCTION__, _msg))
/** Possible destinations for the debug log */
enum debug_logtype {DEBUG_STDOUT = 0, DEBUG_FILE = 1, DEBUG_STDERR = 2};
+114
View File
@@ -0,0 +1,114 @@
/*
Unix SMB/CIFS implementation.
some simple double linked list macros
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.
*/
/* To use these macros you must have a structure containing a next and
prev pointer */
#ifndef _DLINKLIST_H
#define _DLINKLIST_H
/* hook into the front of the list */
#define DLIST_ADD(list, p) \
do { \
if (!(list)) { \
(list) = (p); \
(p)->next = (p)->prev = NULL; \
} else { \
(list)->prev = (p); \
(p)->next = (list); \
(p)->prev = NULL; \
(list) = (p); \
}\
} while (0)
/* remove an element from a list - element doesn't have to be in list. */
#define DLIST_REMOVE(list, p) \
do { \
if ((p) == (list)) { \
(list) = (p)->next; \
if (list) (list)->prev = NULL; \
} else { \
if ((p)->prev) (p)->prev->next = (p)->next; \
if ((p)->next) (p)->next->prev = (p)->prev; \
} \
if ((p) != (list)) (p)->next = (p)->prev = NULL; \
} while (0)
/* promote an element to the top of the list */
#define DLIST_PROMOTE(list, p) \
do { \
DLIST_REMOVE(list, p); \
DLIST_ADD(list, p); \
} while (0)
/* hook into the end of the list - needs a tmp pointer */
#define DLIST_ADD_END(list, p, type) \
do { \
if (!(list)) { \
(list) = (p); \
(p)->next = (p)->prev = NULL; \
} else { \
type tmp; \
for (tmp = (list); tmp->next; tmp = tmp->next) ; \
tmp->next = (p); \
(p)->next = NULL; \
(p)->prev = tmp; \
} \
} while (0)
/* insert 'p' after the given element 'el' in a list. If el is NULL then
this is the same as a DLIST_ADD() */
#define DLIST_ADD_AFTER(list, p, el) \
do { \
if (!(list) || !(el)) { \
DLIST_ADD(list, p); \
} else { \
p->prev = el; \
p->next = el->next; \
el->next = p; \
if (p->next) p->next->prev = p; \
}\
} while (0)
/* demote an element to the end of the list, needs a tmp pointer */
#define DLIST_DEMOTE(list, p, tmp) \
do { \
DLIST_REMOVE(list, p); \
DLIST_ADD_END(list, p, tmp); \
} while (0)
/* concatenate two lists - putting all elements of the 2nd list at the
end of the first list */
#define DLIST_CONCATENATE(list1, list2, type) \
do { \
if (!(list1)) { \
(list1) = (list2); \
} else { \
type tmp; \
for (tmp = (list1); tmp->next; tmp = tmp->next) ; \
tmp->next = (list2); \
if (list2) { \
(list2)->prev = tmp; \
} \
} \
} while (0)
#endif /* _DLINKLIST_H */
+107
View File
@@ -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"
_PUBLIC_ 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;
}
_PUBLIC_ 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;
_PUBLIC_ 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 */
_PUBLIC_ void display_set_stderr(void)
{
outfile = stderr;
}
+226
View File
@@ -0,0 +1,226 @@
/*
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"
/**
* @file
* @brief Fault handling
*/
/* 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>
#elif HAVE_LIBEXC_H
#include <libexc.h>
#endif
/**
* Write backtrace to debug log
*/
_PUBLIC_ void call_backtrace(void)
{
#ifdef HAVE_BACKTRACE
#ifndef BACKTRACE_STACK_SIZE
#define BACKTRACE_STACK_SIZE 64
#endif
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 */
#ifndef BACKTRACE_STACK_SIZE
#define BACKTRACE_STACK_SIZE 64
#endif
/* 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
}
_PUBLIC_ const char *panic_action = NULL;
/**
Something really nasty happened - panic !
**/
_PUBLIC_ void smb_panic(const char *why)
{
int result;
if (panic_action && *panic_action) {
char pidstr[20];
char cmdstring[200];
safe_strcpy(cmdstring, panic_action, 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
**/
_PUBLIC_ 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.
*/
_PUBLIC_ 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;
}
+2
View File
@@ -0,0 +1,2 @@
AC_CHECK_HEADER(execinfo.h)
AC_CHECK_FUNCS(backtrace)
+155
View File
@@ -0,0 +1,155 @@
/*
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"
/**
* @file
* @brief Utility functions for getting the amount of free disk space
*/
/* 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);
}
/**
* Retrieve amount of free disk space.
* 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
*/
_PUBLIC_ 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;
}
+190
View File
@@ -0,0 +1,190 @@
#################################################
# these tests are taken from the GNU fileutils package
AC_CHECKING(how to get filesystem space usage)
AC_CHECK_HEADERS(sys/statfs.h sys/statvfs.h sys/vfs.h)
AC_CHECK_HEADERS(sys/mount.h, , , [AC_INCLUDES_DEFAULT
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif])
space=no
# Test for statvfs64.
if test $space = no; then
# SVR4
AC_CACHE_CHECK([statvfs64 function (SVR4)], fu_cv_sys_stat_statvfs64,
[AC_TRY_RUN([
#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/statvfs.h>
main ()
{
struct statvfs64 fsd;
exit (statvfs64 (".", &fsd));
}],
fu_cv_sys_stat_statvfs64=yes,
fu_cv_sys_stat_statvfs64=no,
fu_cv_sys_stat_statvfs64=cross)])
if test $fu_cv_sys_stat_statvfs64 = yes; then
space=yes
AC_DEFINE(STAT_STATVFS64,1,[Whether statvfs64() is available])
fi
fi
# Perform only the link test since it seems there are no variants of the
# statvfs function. This check is more than just AC_CHECK_FUNCS(statvfs)
# because that got a false positive on SCO OSR5. Adding the declaration
# of a `struct statvfs' causes this test to fail (as it should) on such
# systems. That system is reported to work fine with STAT_STATFS4 which
# is what it gets when this test fails.
if test $space = no; then
# SVR4
AC_CACHE_CHECK([statvfs function (SVR4)], fu_cv_sys_stat_statvfs,
[AC_TRY_LINK([#include <sys/types.h>
#include <sys/statvfs.h>],
[struct statvfs fsd; statvfs (0, &fsd);],
fu_cv_sys_stat_statvfs=yes,
fu_cv_sys_stat_statvfs=no)])
if test $fu_cv_sys_stat_statvfs = yes; then
space=yes
AC_DEFINE(STAT_STATVFS,1,[Whether statvfs() is available])
fi
fi
if test $space = no; then
# DEC Alpha running OSF/1
AC_MSG_CHECKING([for 3-argument statfs function (DEC OSF/1)])
AC_CACHE_VAL(fu_cv_sys_stat_statfs3_osf1,
[AC_TRY_RUN([
#include <sys/param.h>
#include <sys/types.h>
#include <sys/mount.h>
main ()
{
struct statfs fsd;
fsd.f_fsize = 0;
exit (statfs (".", &fsd, sizeof (struct statfs)));
}],
fu_cv_sys_stat_statfs3_osf1=yes,
fu_cv_sys_stat_statfs3_osf1=no,
fu_cv_sys_stat_statfs3_osf1=no)])
AC_MSG_RESULT($fu_cv_sys_stat_statfs3_osf1)
if test $fu_cv_sys_stat_statfs3_osf1 = yes; then
space=yes
AC_DEFINE(STAT_STATFS3_OSF1,1,[Whether statfs requires 3 arguments])
fi
fi
if test $space = no; then
# AIX
AC_MSG_CHECKING([for two-argument statfs with statfs.bsize dnl
member (AIX, 4.3BSD)])
AC_CACHE_VAL(fu_cv_sys_stat_statfs2_bsize,
[AC_TRY_RUN([
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
#ifdef HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
main ()
{
struct statfs fsd;
fsd.f_bsize = 0;
exit (statfs (".", &fsd));
}],
fu_cv_sys_stat_statfs2_bsize=yes,
fu_cv_sys_stat_statfs2_bsize=no,
fu_cv_sys_stat_statfs2_bsize=no)])
AC_MSG_RESULT($fu_cv_sys_stat_statfs2_bsize)
if test $fu_cv_sys_stat_statfs2_bsize = yes; then
space=yes
AC_DEFINE(STAT_STATFS2_BSIZE,1,[Whether statfs requires two arguments and struct statfs has bsize property])
fi
fi
if test $space = no; then
# SVR3
AC_MSG_CHECKING([for four-argument statfs (AIX-3.2.5, SVR3)])
AC_CACHE_VAL(fu_cv_sys_stat_statfs4,
[AC_TRY_RUN([#include <sys/types.h>
#include <sys/statfs.h>
main ()
{
struct statfs fsd;
exit (statfs (".", &fsd, sizeof fsd, 0));
}],
fu_cv_sys_stat_statfs4=yes,
fu_cv_sys_stat_statfs4=no,
fu_cv_sys_stat_statfs4=no)])
AC_MSG_RESULT($fu_cv_sys_stat_statfs4)
if test $fu_cv_sys_stat_statfs4 = yes; then
space=yes
AC_DEFINE(STAT_STATFS4,1,[Whether statfs requires 4 arguments])
fi
fi
if test $space = no; then
# 4.4BSD and NetBSD
AC_MSG_CHECKING([for two-argument statfs with statfs.fsize dnl
member (4.4BSD and NetBSD)])
AC_CACHE_VAL(fu_cv_sys_stat_statfs2_fsize,
[AC_TRY_RUN([#include <sys/types.h>
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
main ()
{
struct statfs fsd;
fsd.f_fsize = 0;
exit (statfs (".", &fsd));
}],
fu_cv_sys_stat_statfs2_fsize=yes,
fu_cv_sys_stat_statfs2_fsize=no,
fu_cv_sys_stat_statfs2_fsize=no)])
AC_MSG_RESULT($fu_cv_sys_stat_statfs2_fsize)
if test $fu_cv_sys_stat_statfs2_fsize = yes; then
space=yes
AC_DEFINE(STAT_STATFS2_FSIZE,1,[Whether statfs requires 2 arguments and struct statfs has fsize])
fi
fi
if test $space = no; then
# Ultrix
AC_MSG_CHECKING([for two-argument statfs with struct fs_data (Ultrix)])
AC_CACHE_VAL(fu_cv_sys_stat_fs_data,
[AC_TRY_RUN([#include <sys/types.h>
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
#ifdef HAVE_SYS_FS_TYPES_H
#include <sys/fs_types.h>
#endif
main ()
{
struct fs_data fsd;
/* Ultrix's statfs returns 1 for success,
0 for not mounted, -1 for failure. */
exit (statfs (".", &fsd) != 1);
}],
fu_cv_sys_stat_fs_data=yes,
fu_cv_sys_stat_fs_data=no,
fu_cv_sys_stat_fs_data=no)])
AC_MSG_RESULT($fu_cv_sys_stat_fs_data)
if test $fu_cv_sys_stat_fs_data = yes; then
space=yes
AC_DEFINE(STAT_STATFS2_FS_DATA,1,[Whether statfs requires 2 arguments and struct fs_data is available])
fi
fi
+329
View File
@@ -0,0 +1,329 @@
/*
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/filesys.h"
#include "lib/crypto/crypto.h"
#include "system/locale.h"
/**
* @file
* @brief Random number generation
*/
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.
**/
_PUBLIC_ void set_rand_reseed_callback(void (*fn)(int *))
{
reseed_callback = fn;
set_need_random_reseed();
}
/**
* Tell the random number generator it needs to reseed.
*/
_PUBLIC_ 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.
**/
_PUBLIC_ 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
**/
_PUBLIC_ uint32_t generate_random(void)
{
uint8_t v[4];
generate_random_buffer(v, 4);
return IVAL(v, 0);
}
/**
very basic password quality checker
**/
_PUBLIC_ 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.
**/
_PUBLIC_ 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;
}
/**
* Generate a random text string consisting of the specified length.
* The returned string will be allocated.
*
* Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,
*/
_PUBLIC_ 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;
}
+392
View File
@@ -0,0 +1,392 @@
/*
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
*/
/**
* @file
*/
#include "includes.h"
#define IDR_BITS 5
#define IDR_FULL 0xfffffffful
#if 0 /* unused */
#define TOP_LEVEL_FULL (IDR_FULL >> 30)
#endif
#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;
memset(pa, 0, sizeof(pa));
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 >= IDR_BITS && 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
*/
_PUBLIC_ 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()
*/
_PUBLIC_ 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
*/
_PUBLIC_ 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
*/
_PUBLIC_ 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
*/
_PUBLIC_ void *idr_find(struct idr_context *idp, int id)
{
return _idr_find(idp, id);
}
/**
remove an id from the idr tree
*/
_PUBLIC_ 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;
}
+11
View File
@@ -0,0 +1,11 @@
/**
\mainpage util
\section Introduction
This library 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.
*/
+112
View File
@@ -0,0 +1,112 @@
/*
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.
*/
/**
* @file
* @brief Module initialization function handling
*/
#include "includes.h"
#include "system/dir.h"
/**
* Obtain the init function from a shared library file
*/
_PUBLIC_ init_module_fn load_module(TALLOC_CTX *mem_ctx, const char *path)
{
void *handle;
void *init_fn;
handle = dlopen(path, RTLD_NOW);
if (handle == NULL) {
DEBUG(0, ("Unable to open %s: %s\n", path, dlerror()));
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);
return NULL;
}
return (init_module_fn)init_fn;
}
/**
* Obtain list of init functions from the modules in the specified
* directory
*/
_PUBLIC_ init_module_fn *load_modules(TALLOC_CTX *mem_ctx, const char *path)
{
DIR *dir;
struct dirent *entry;
char *filename;
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 (ISDOT(entry->d_name) || ISDOTDOT(entry->d_name))
continue;
filename = talloc_asprintf(mem_ctx, "%s/%s", path, entry->d_name);
ret[success] = load_module(mem_ctx, filename);
if (ret[success]) {
ret = talloc_realloc(mem_ctx, ret, init_module_fn, success+2);
success++;
ret[success] = NULL;
}
talloc_free(filename);
}
closedir(dir);
return ret;
}
/**
* Run the specified init functions.
*
* @return True if all functions ran successfully, False otherwise
*/
_PUBLIC_ BOOL run_init_functions(NTSTATUS (**fns) (void))
{
int i;
BOOL ret = True;
if (fns == NULL)
return True;
for (i = 0; fns[i]; i++) { ret &= (BOOL)NT_STATUS_IS_OK(fns[i]()); }
return ret;
}
+223
View File
@@ -0,0 +1,223 @@
/*
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
*/
/**
* @file
* @brief MS-style Filename matching
*/
#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 optimisation - 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);
}
+57
View File
@@ -0,0 +1,57 @@
/*
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"
/**
* @file
* @brief Mutex utility functions
*/
/* 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.
*/
_PUBLIC_ 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;
}
+76
View File
@@ -0,0 +1,76 @@
#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.
*/
/**
* @file
* @brief Mutex operations
*/
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_ */
+45
View File
@@ -0,0 +1,45 @@
/*
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 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_ */
#endif
+145
View File
@@ -0,0 +1,145 @@
/*
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"
/**
* @file
* @brief Signal handling
*/
/****************************************************************************
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);
}
+1
View File
@@ -0,0 +1 @@
AC_CHECK_FUNCS(sigprocmask sigblock sigaction)
+98
View File
@@ -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.
****************************************************************************/
_PUBLIC_ 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(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(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 */
}
_PUBLIC_ const char *sys_inet_ntoa(struct ipv4_addr in)
{
struct in_addr in2;
in2.s_addr = in.addr;
return inet_ntoa(in2);
}
_PUBLIC_ 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;
}
+623
View File
@@ -0,0 +1,623 @@
/*
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"
/**
* @file
* @brief time handling functions
*/
#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.
**/
_PUBLIC_ time_t get_time_t_max(void)
{
return TIME_T_MAX;
}
/**
a gettimeofday wrapper
**/
_PUBLIC_ 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"
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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
**/
_PUBLIC_ BOOL null_time(time_t t)
{
return t == 0 ||
t == (time_t)0xFFFFFFFF ||
t == (time_t)-1;
}
/**
check if it's a null NTTIME
**/
_PUBLIC_ 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 = (((unsigned int)(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 = ((((unsigned int)t->tm_min >> 3)&0x7) | (((unsigned int)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
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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)
**/
_PUBLIC_ 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)
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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
*/
_PUBLIC_ 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
*/
_PUBLIC_ void push_nttime(uint8_t *base, uint16_t offset, NTTIME t)
{
SBVAL(base, offset, t);
}
/**
pull a NTTIME from a packet
*/
_PUBLIC_ 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
*/
_PUBLIC_ NTTIME nttime_from_string(const char *s)
{
return strtoull(s, NULL, 0);
}
/**
return (tv1 - tv2) in microseconds
*/
_PUBLIC_ 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
*/
_PUBLIC_ 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
*/
_PUBLIC_ BOOL timeval_is_zero(const struct timeval *tv)
{
return tv->tv_sec == 0 && tv->tv_usec == 0;
}
/**
return a timeval for the current time
*/
_PUBLIC_ struct timeval timeval_current(void)
{
struct timeval tv;
GetTimeOfDay(&tv);
return tv;
}
/**
return a timeval struct with the given elements
*/
_PUBLIC_ 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
*/
_PUBLIC_ struct timeval timeval_add(const struct timeval *tv,
uint32_t secs, uint32_t usecs)
{
struct timeval tv2 = *tv;
const unsigned int 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
*/
_PUBLIC_ 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
*/
_PUBLIC_ 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
*/
_PUBLIC_ 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
*/
_PUBLIC_ 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
*/
_PUBLIC_ double timeval_elapsed(const struct timeval *tv)
{
struct timeval tv2 = timeval_current();
return timeval_elapsed2(tv, &tv2);
}
/**
return the lesser of two timevals
*/
_PUBLIC_ 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
*/
_PUBLIC_ 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)
*/
_PUBLIC_ 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
*/
_PUBLIC_ NTTIME timeval_to_nttime(const struct timeval *tv)
{
return 10*(tv->tv_usec +
((TIME_FIXUP_CONSTANT + (uint64_t)tv->tv_sec) * 1000000));
}
/**
convert a NTTIME to a timeval
*/
_PUBLIC_ void nttime_to_timeval(struct timeval *tv, NTTIME t)
{
if (tv == NULL) return;
t += 10/2;
t /= 10;
t -= TIME_FIXUP_CONSTANT*1000*1000;
tv->tv_sec = t / 1000000;
if (TIME_T_MIN > tv->tv_sec || tv->tv_sec > TIME_T_MAX) {
tv->tv_sec = 0;
tv->tv_usec = 0;
return;
}
tv->tv_usec = 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
*/
_PUBLIC_ 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);
}
+9
View File
@@ -0,0 +1,9 @@
AC_CACHE_CHECK([if gettimeofday takes tz argument],samba_cv_HAVE_GETTIMEOFDAY_TZ,[
AC_TRY_RUN([
#include <sys/time.h>
#include <unistd.h>
main() { struct timeval tv; exit(gettimeofday(&tv, NULL));}],
samba_cv_HAVE_GETTIMEOFDAY_TZ=yes,samba_cv_HAVE_GETTIMEOFDAY_TZ=no,samba_cv_HAVE_GETTIMEOFDAY_TZ=cross)])
if test x"$samba_cv_HAVE_GETTIMEOFDAY_TZ" = x"yes"; then
AC_DEFINE(HAVE_GETTIMEOFDAY_TZ,1,[Whether gettimeofday() is available])
fi
+78
View File
@@ -0,0 +1,78 @@
/*
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"
/**
* @file
* @brief Gaining/losing root privileges
*/
/*
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(struct saved_state *s)
{
if (geteuid() != s->uid &&
seteuid(s->uid) != 0) {
smb_panic("Failed to restore privileges");
}
return 0;
}
/**
* Obtain root privileges for the current process.
*
* The privileges can be dropped by talloc_free()-ing the
* token returned by this function
*/
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;
}
+596
View File
@@ -0,0 +1,596 @@
/*
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 "system/network.h"
#include "system/filesys.h"
#include "system/locale.h"
/**
* @file
* @brief Misc utility functions
*/
/**
Find a suitable temporary directory. The result should be copied immediately
as it may be overwritten by a subsequent call.
**/
_PUBLIC_ 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.
**/
_PUBLIC_ 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.
**/
_PUBLIC_ 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.
**/
_PUBLIC_ 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;
}
/**
* Try to create the specified directory if it didn't exist.
*
* @retval True if the directory already existed and has the right permissions
* or was successfully created.
*/
_PUBLIC_ 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
**/
_PUBLIC_ 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.
**/
_PUBLIC_ void msleep(unsigned int 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.
**/
_PUBLIC_ 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 */
}
/**
Get my own name, return in malloc'ed storage.
**/
_PUBLIC_ 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(hostname,'.');
if (p)
*p = 0;
return hostname;
}
/**
Return true if a string could be a pure IP address.
**/
_PUBLIC_ 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(str, '.') != NULL);
return pure_address;
}
/**
Interpret an internet address or name into an IP address in 4 byte form.
**/
_PUBLIC_ 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().
**/
_PUBLIC_ 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.
**/
_PUBLIC_ BOOL is_zero_ip(struct ipv4_addr ip)
{
return ip.addr == 0;
}
/**
Are two IPs on the same subnet?
**/
_PUBLIC_ 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?
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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]:'.'));
}
/**
* Write dump of binary data to the log file.
*
* The data is only written if the log level is at least level.
*/
_PUBLIC_ 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.
**/
_PUBLIC_ 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.
**/
_PUBLIC_ 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.
**/
_PUBLIC_ 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.
**/
_PUBLIC_ 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;
}
/**
* Write a password to the log file.
*
* @note Only actually does something if DEBUG_PASSWORD was defined during
* compile-time.
*/
_PUBLIC_ 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
*/
_PUBLIC_ BOOL all_zero(const uint8_t *ptr, size_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
*/
_PUBLIC_ 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);
}
+133
View File
@@ -0,0 +1,133 @@
/*
Unix SMB/CIFS implementation.
Utility functions for Samba
Copyright (C) Andrew Tridgell 1992-1999
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.
*/
#ifndef _SAMBA_UTIL_H_
#define _SAMBA_UTIL_H_
#include "charset/charset.h"
/**
* @file
* @brief Helpful macros
*/
struct substitute_context;
struct smbsrv_tcon;
extern const char *logfile;
extern const char *panic_action;
#include "util/xfile.h"
#include "util/debug.h"
#include "util/mutex.h"
#include "util/byteorder.h"
#include "lib/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"); abort(); }} while (0)
#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
/**
* Type-safe version of malloc. Allocated one copy of the
* specified data type.
*/
#define malloc_p(type) (type *)malloc(sizeof(type))
/**
* Allocate an array of elements of one data type. Does type-checking.
*/
#define malloc_array_p(type, count) (type *)realloc_array(NULL, sizeof(type), count)
/**
* Resize an array of elements of one data type. Does type-checking.
*/
#define realloc_p(p, type, count) (type *)realloc_array(p, sizeof(type), count)
#define data_blob(ptr, size) data_blob_named(ptr, size, "DATA_BLOB: "__location__)
#define data_blob_talloc(ctx, ptr, size) data_blob_talloc_named(ctx, ptr, size, "DATA_BLOB: "__location__)
#define data_blob_dup_talloc(ctx, blob) data_blob_talloc_named(ctx, (blob)->data, (blob)->length, "DATA_BLOB: "__location__)
#if defined(VALGRIND)
#define strlen(x) valgrind_strlen(x)
#endif
/**
this is a warning hack. The idea is to use this everywhere that we
get the "discarding const" warning from gcc. That doesn't actually
fix the problem of course, but it means that when we do get to
cleaning them up we can do it by searching the code for
discard_const.
It also means that other error types aren't as swamped by the noise
of hundreds of const warnings, so we are more likely to notice when
we get new errors.
Please only add more uses of this macro when you find it
_really_ hard to fix const warnings. Our aim is to eventually use
this function in only a very few places.
Also, please call this via the discard_const_p() macro interface, as that
makes the return type safe.
*/
#define discard_const(ptr) ((void *)((intptr_t)(ptr)))
/** Type-safe version of discard_const */
#define discard_const_p(type, ptr) ((type *)discard_const(ptr))
#endif /* _SAMBA_UTIL_H_ */
+1
View File
@@ -0,0 +1 @@
AC_CHECK_FUNCS(setsid)
+405
View File
@@ -0,0 +1,405 @@
/*
* 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"
/**
* @file
* @brief File-related utility functions
*/
/**
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
**/
_PUBLIC_ 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;
/* fall through */
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
*/
_PUBLIC_ 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 == 0) {
return NULL;
}
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.
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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
'p' will be freed on error, and otherwise will be made a child of the returned array
**/
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_steal(ret, p);
memset(ret, 0, sizeof(ret[0])*(i+2));
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;
}
/* remove any blank lines at the end */
while (i > 0 && ret[i-1][0] == 0) {
i--;
}
if (numlines) *numlines = i;
return ret;
}
/**
load a file into memory and return an array of pointers to lines in the file
must be freed with talloc_free().
**/
_PUBLIC_ char **file_lines_load(const char *fname, int *numlines, TALLOC_CTX *mem_ctx)
{
char *p;
size_t size;
p = file_load(fname, &size, mem_ctx);
if (!p) return NULL;
return file_lines_parse(p, size, numlines, mem_ctx);
}
/**
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.
**/
_PUBLIC_ char **fd_lines_load(int fd, int *numlines, TALLOC_CTX *mem_ctx)
{
char *p;
size_t size;
p = fd_load(fd, &size, mem_ctx);
if (!p) return NULL;
return file_lines_parse(p, size, numlines, mem_ctx);
}
/**
take a list of lines and modify them to produce a list where \ continues
a line
**/
_PUBLIC_ 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
*/
_PUBLIC_ 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;
}
_PUBLIC_ 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;
}
_PUBLIC_ 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;
}
/*
try to determine if the filesystem supports large files
*/
_PUBLIC_ bool large_file_support(const char *path)
{
int fd;
ssize_t ret;
char c;
fd = open(path, O_RDWR|O_CREAT, 0600);
unlink(path);
if (fd == -1) {
/* have to assume large files are OK */
return true;
}
ret = pread(fd, &c, 1, ((uint64_t)1)<<32);
close(fd);
return ret == 0;
}
+284
View File
@@ -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);
}
}
+89
View File
@@ -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);
}
+797
View File
@@ -0,0 +1,797 @@
/*
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 "libcli/raw/smb.h"
#include "pstring.h"
#include "lib/ldb/include/ldb.h"
#include "system/locale.h"
/**
* @file
* @brief String utilities.
**/
/**
Trim the specified elements off the front and back of a string.
**/
_PUBLIC_ 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
**/
_PUBLIC_ size_t count_chars(const char *s, char c)
{
size_t count = 0;
while (*s) {
if (*s == c) count++;
s ++;
}
return count;
}
/**
Safe string copy into a known length string. maxlength does not
include the terminating zero.
**/
_PUBLIC_ 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.
**/
_PUBLIC_ 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;
}
/**
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"
**/
_PUBLIC_ 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(hexchars, toupper((unsigned char)strhex[i]))))
break;
i++; /* next hex digit */
if (!(p2 = strchr(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;
}
/**
* Parse a hex string and return a data blob.
*/
_PUBLIC_ 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.
*/
_PUBLIC_ 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.
**/
_PUBLIC_ 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.
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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.
**/
_PUBLIC_ 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.
**/
_PUBLIC_ 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);
}
}
/**
Unescape a URL encoded string, in place.
**/
_PUBLIC_ void rfc1738_unescape(char *buf)
{
char *p=buf;
while ((p=strchr(p,'+')))
*p = ' ';
p = buf;
while (p && *p && (p=strchr(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++;
}
}
#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
**/
_PUBLIC_ 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;
}
/**
* Add a string to an array of strings.
*
* num should be a pointer to an integer that holds the current
* number of elements in strings. It will be updated by this function.
*/
_PUBLIC_ 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
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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.
**/
_PUBLIC_ 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.
**/
_PUBLIC_ 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;
}
/**
* Parse a string containing a boolean value.
*
* val will be set to the read value.
*
* @retval True if a boolean value was parsed, False otherwise.
*/
_PUBLIC_ 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.
**/
_PUBLIC_ 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;
}
/**
* Parse a uint64_t value from a string
*
* val will be set to the value read.
*
* @retval True if parsing was successful, False otherwise
*/
_PUBLIC_ 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;
}
/**
return the number of bytes occupied by a buffer in CH_UTF16 format
the result includes the null termination
**/
_PUBLIC_ 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
**/
_PUBLIC_ 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;
}
_PUBLIC_ 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;
}
/**
Do a case-insensitive, whitespace-ignoring string compare.
**/
_PUBLIC_ 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.
**/
_PUBLIC_ void string_replace(char *s, char oldc, char newc)
{
while (*s) {
if (*s == oldc) *s = newc;
s++;
}
}
/**
* Compare 2 strings.
*
* @note The comparison is case-insensitive.
**/
_PUBLIC_ BOOL strequal(const char *s1, const char *s2)
{
if (s1 == s2)
return(True);
if (!s1 || !s2)
return(False);
return strcasecmp(s1,s2) == 0;
}
+300
View File
@@ -0,0 +1,300 @@
/*
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"
/**
* @file
* @brief String list manipulation
*/
/**
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
*/
_PUBLIC_ 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
*/
_PUBLIC_ 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
*/
_PUBLIC_ 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 */
_PUBLIC_ 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
*/
_PUBLIC_ 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
*/
_PUBLIC_ 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.
*/
_PUBLIC_ 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
*/
_PUBLIC_ 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
*/
_PUBLIC_ 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
*/
_PUBLIC_ 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
*/
_PUBLIC_ 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;
}
+541
View File
@@ -0,0 +1,541 @@
/*
Unix SMB/CIFS implementation.
tdb utility functions
Copyright (C) Andrew Tridgell 1992-2006
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 "lib/tdb/include/tdb.h"
#include "pstring.h"
/* these are little tdb utility functions that are meant to make
dealing with a tdb database a little less cumbersome in Samba */
/***************************************************************
Make a TDB_DATA and keep the const warning in one place
****************************************************************/
static TDB_DATA make_tdb_data(const char *dptr, size_t dsize)
{
TDB_DATA ret;
ret.dptr = discard_const_p(unsigned char, dptr);
ret.dsize = dsize;
return ret;
}
/****************************************************************************
Lock a chain by string. Return -1 if lock failed.
****************************************************************************/
int tdb_lock_bystring(struct tdb_context *tdb, const char *keyval)
{
TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
return tdb_chainlock(tdb, key);
}
/****************************************************************************
Unlock a chain by string.
****************************************************************************/
void tdb_unlock_bystring(struct tdb_context *tdb, const char *keyval)
{
TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
tdb_chainunlock(tdb, key);
}
/****************************************************************************
Read lock a chain by string. Return -1 if lock failed.
****************************************************************************/
int tdb_read_lock_bystring(struct tdb_context *tdb, const char *keyval)
{
TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
return tdb_chainlock_read(tdb, key);
}
/****************************************************************************
Read unlock a chain by string.
****************************************************************************/
void tdb_read_unlock_bystring(struct tdb_context *tdb, const char *keyval)
{
TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
tdb_chainunlock_read(tdb, key);
}
/****************************************************************************
Fetch a int32_t value by a arbitrary blob key, return -1 if not found.
Output is int32_t in native byte order.
****************************************************************************/
int32_t tdb_fetch_int32_byblob(struct tdb_context *tdb, const char *keyval, size_t len)
{
TDB_DATA key = make_tdb_data(keyval, len);
TDB_DATA data;
int32_t ret;
data = tdb_fetch(tdb, key);
if (!data.dptr || data.dsize != sizeof(int32_t)) {
SAFE_FREE(data.dptr);
return -1;
}
ret = IVAL(data.dptr,0);
SAFE_FREE(data.dptr);
return ret;
}
/****************************************************************************
Fetch a int32_t value by string key, return -1 if not found.
Output is int32_t in native byte order.
****************************************************************************/
int32_t tdb_fetch_int32(struct tdb_context *tdb, const char *keystr)
{
return tdb_fetch_int32_byblob(tdb, keystr, strlen(keystr) + 1);
}
/****************************************************************************
Store a int32_t value by an arbitary blob key, return 0 on success, -1 on failure.
Input is int32_t in native byte order. Output in tdb is in little-endian.
****************************************************************************/
int tdb_store_int32_byblob(struct tdb_context *tdb, const char *keystr, size_t len, int32_t v)
{
TDB_DATA key = make_tdb_data(keystr, len);
TDB_DATA data;
int32_t v_store;
SIVAL(&v_store,0,v);
data.dptr = (void *)&v_store;
data.dsize = sizeof(int32_t);
return tdb_store(tdb, key, data, TDB_REPLACE);
}
/****************************************************************************
Store a int32_t value by string key, return 0 on success, -1 on failure.
Input is int32_t in native byte order. Output in tdb is in little-endian.
****************************************************************************/
int tdb_store_int32(struct tdb_context *tdb, const char *keystr, int32_t v)
{
return tdb_store_int32_byblob(tdb, keystr, strlen(keystr) + 1, v);
}
/****************************************************************************
Fetch a uint32_t value by a arbitrary blob key, return -1 if not found.
Output is uint32_t in native byte order.
****************************************************************************/
BOOL tdb_fetch_uint32_byblob(struct tdb_context *tdb, const char *keyval, size_t len, uint32_t *value)
{
TDB_DATA key = make_tdb_data(keyval, len);
TDB_DATA data;
data = tdb_fetch(tdb, key);
if (!data.dptr || data.dsize != sizeof(uint32_t)) {
SAFE_FREE(data.dptr);
return False;
}
*value = IVAL(data.dptr,0);
SAFE_FREE(data.dptr);
return True;
}
/****************************************************************************
Fetch a uint32_t value by string key, return -1 if not found.
Output is uint32_t in native byte order.
****************************************************************************/
BOOL tdb_fetch_uint32(struct tdb_context *tdb, const char *keystr, uint32_t *value)
{
return tdb_fetch_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
}
/****************************************************************************
Store a uint32_t value by an arbitary blob key, return 0 on success, -1 on failure.
Input is uint32_t in native byte order. Output in tdb is in little-endian.
****************************************************************************/
BOOL tdb_store_uint32_byblob(struct tdb_context *tdb, const char *keystr, size_t len, uint32_t value)
{
TDB_DATA key = make_tdb_data(keystr, len);
TDB_DATA data;
uint32_t v_store;
BOOL ret = True;
SIVAL(&v_store, 0, value);
data.dptr = (void *)&v_store;
data.dsize = sizeof(uint32_t);
if (tdb_store(tdb, key, data, TDB_REPLACE) == -1)
ret = False;
return ret;
}
/****************************************************************************
Store a uint32_t value by string key, return 0 on success, -1 on failure.
Input is uint32_t in native byte order. Output in tdb is in little-endian.
****************************************************************************/
BOOL tdb_store_uint32(struct tdb_context *tdb, const char *keystr, uint32_t value)
{
return tdb_store_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
}
/****************************************************************************
Store a buffer by a null terminated string key. Return 0 on success, -1
on failure.
****************************************************************************/
int tdb_store_bystring(struct tdb_context *tdb, const char *keystr, TDB_DATA data, int flags)
{
TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
return tdb_store(tdb, key, data, flags);
}
/****************************************************************************
Fetch a buffer using a null terminated string key. Don't forget to call
free() on the result dptr.
****************************************************************************/
TDB_DATA tdb_fetch_bystring(struct tdb_context *tdb, const char *keystr)
{
TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
return tdb_fetch(tdb, key);
}
/****************************************************************************
Delete an entry using a null terminated string key.
****************************************************************************/
int tdb_delete_bystring(struct tdb_context *tdb, const char *keystr)
{
TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
return tdb_delete(tdb, key);
}
/****************************************************************************
Atomic integer change. Returns old value. To create, set initial value in *oldval.
****************************************************************************/
int32_t tdb_change_int32_atomic(struct tdb_context *tdb, const char *keystr, int32_t *oldval, int32_t change_val)
{
int32_t val;
int32_t ret = -1;
if (tdb_lock_bystring(tdb, keystr) == -1)
return -1;
if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
/* The lookup failed */
if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
/* but not because it didn't exist */
goto err_out;
}
/* Start with 'old' value */
val = *oldval;
} else {
/* It worked, set return value (oldval) to tdb data */
*oldval = val;
}
/* Increment value for storage and return next time */
val += change_val;
if (tdb_store_int32(tdb, keystr, val) == -1)
goto err_out;
ret = 0;
err_out:
tdb_unlock_bystring(tdb, keystr);
return ret;
}
/****************************************************************************
Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval.
****************************************************************************/
BOOL tdb_change_uint32_atomic(struct tdb_context *tdb, const char *keystr, uint32_t *oldval, uint32_t change_val)
{
uint32_t val;
BOOL ret = False;
if (tdb_lock_bystring(tdb, keystr) == -1)
return False;
if (!tdb_fetch_uint32(tdb, keystr, &val)) {
/* It failed */
if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
/* and not because it didn't exist */
goto err_out;
}
/* Start with 'old' value */
val = *oldval;
} else {
/* it worked, set return value (oldval) to tdb data */
*oldval = val;
}
/* get a new value to store */
val += change_val;
if (!tdb_store_uint32(tdb, keystr, val))
goto err_out;
ret = True;
err_out:
tdb_unlock_bystring(tdb, keystr);
return ret;
}
/****************************************************************************
Allow tdb_delete to be used as a tdb_traversal_fn.
****************************************************************************/
int tdb_traverse_delete_fn(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf,
void *state)
{
return tdb_delete(the_tdb, key);
}
/****************************************************************************
Useful pair of routines for packing/unpacking data consisting of
integers and strings.
****************************************************************************/
size_t tdb_pack(TDB_CONTEXT *tdb, char *buf, int bufsize, const char *fmt, ...)
{
va_list ap;
uint8_t bt;
uint16_t w;
uint32_t d;
int i;
void *p;
int len;
char *s;
char c;
char *buf0 = buf;
const char *fmt0 = fmt;
int bufsize0 = bufsize;
tdb_log_func log_fn = tdb_log_fn(tdb);
va_start(ap, fmt);
while (*fmt) {
switch ((c = *fmt++)) {
case 'b': /* unsigned 8-bit integer */
len = 1;
bt = (uint8_t)va_arg(ap, int);
if (bufsize && bufsize >= len)
SSVAL(buf, 0, bt);
break;
case 'w': /* unsigned 16-bit integer */
len = 2;
w = (uint16_t)va_arg(ap, int);
if (bufsize && bufsize >= len)
SSVAL(buf, 0, w);
break;
case 'd': /* signed 32-bit integer (standard int in most systems) */
len = 4;
d = va_arg(ap, uint32_t);
if (bufsize && bufsize >= len)
SIVAL(buf, 0, d);
break;
case 'p': /* pointer */
len = 4;
p = va_arg(ap, void *);
d = p?1:0;
if (bufsize && bufsize >= len)
SIVAL(buf, 0, d);
break;
case 'P': /* null-terminated string */
s = va_arg(ap,char *);
w = strlen(s);
len = w + 1;
if (bufsize && bufsize >= len)
memcpy(buf, s, len);
break;
case 'f': /* null-terminated string */
s = va_arg(ap,char *);
w = strlen(s);
len = w + 1;
if (bufsize && bufsize >= len)
memcpy(buf, s, len);
break;
case 'B': /* fixed-length string */
i = va_arg(ap, int);
s = va_arg(ap, char *);
len = 4+i;
if (bufsize && bufsize >= len) {
SIVAL(buf, 0, i);
memcpy(buf+4, s, i);
}
break;
default:
log_fn(tdb, 0,"Unknown tdb_pack format %c in %s\n",
c, fmt);
len = 0;
break;
}
buf += len;
if (bufsize)
bufsize -= len;
if (bufsize < 0)
bufsize = 0;
}
va_end(ap);
log_fn(tdb, 18,"tdb_pack(%s, %d) -> %d\n",
fmt0, bufsize0, (int)PTR_DIFF(buf, buf0));
return PTR_DIFF(buf, buf0);
}
/****************************************************************************
Useful pair of routines for packing/unpacking data consisting of
integers and strings.
****************************************************************************/
int tdb_unpack(TDB_CONTEXT *tdb, char *buf, int bufsize, const char *fmt, ...)
{
va_list ap;
uint8_t *bt;
uint16_t *w;
uint32_t *d;
int len;
int *i;
void **p;
char *s, **b;
char c;
char *buf0 = buf;
const char *fmt0 = fmt;
int bufsize0 = bufsize;
tdb_log_func log_fn = tdb_log_fn(tdb);
va_start(ap, fmt);
while (*fmt) {
switch ((c=*fmt++)) {
case 'b':
len = 1;
bt = va_arg(ap, uint8_t *);
if (bufsize < len)
goto no_space;
*bt = SVAL(buf, 0);
break;
case 'w':
len = 2;
w = va_arg(ap, uint16_t *);
if (bufsize < len)
goto no_space;
*w = SVAL(buf, 0);
break;
case 'd':
len = 4;
d = va_arg(ap, uint32_t *);
if (bufsize < len)
goto no_space;
*d = IVAL(buf, 0);
break;
case 'p':
len = 4;
p = va_arg(ap, void **);
if (bufsize < len)
goto no_space;
*p = (void *)IVAL(buf, 0);
break;
case 'P':
s = va_arg(ap,char *);
len = strlen(buf) + 1;
if (bufsize < len || len > sizeof(pstring))
goto no_space;
memcpy(s, buf, len);
break;
case 'f':
s = va_arg(ap,char *);
len = strlen(buf) + 1;
if (bufsize < len || len > sizeof(fstring))
goto no_space;
memcpy(s, buf, len);
break;
case 'B':
i = va_arg(ap, int *);
b = va_arg(ap, char **);
len = 4;
if (bufsize < len)
goto no_space;
*i = IVAL(buf, 0);
if (! *i) {
*b = NULL;
break;
}
len += *i;
if (bufsize < len)
goto no_space;
*b = (char *)malloc(*i);
if (! *b)
goto no_space;
memcpy(*b, buf+4, *i);
break;
default:
log_fn(tdb, 0, "Unknown tdb_unpack format %c in %s\n",
c, fmt);
len = 0;
break;
}
buf += len;
bufsize -= len;
}
va_end(ap);
log_fn(tdb, 18, "tdb_unpack(%s, %d) -> %d\n",
fmt0, bufsize0, (int)PTR_DIFF(buf, buf0));
return PTR_DIFF(buf, buf0);
no_space:
return -1;
}
+121
View File
@@ -0,0 +1,121 @@
/*
Unix SMB/CIFS implementation.
POSIX NTVFS backend - xattr support using filesystem xattrs
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"
#include "lib/util/wrap_xattr.h"
#if defined(HAVE_XATTR_SUPPORT) && defined(XATTR_ADDITIONAL_OPTIONS)
static ssize_t _wrap_darwin_fgetxattr(int fd, const char *name, void *value, size_t size)
{
return fgetxattr(fd, name, value, size, 0, 0);
}
static ssize_t _wrap_darwin_getxattr(const char *path, const char *name, void *value, size_t size)
{
return getxattr(path, name, value, size, 0, 0);
}
static int _wrap_darwin_fsetxattr(int fd, const char *name, void *value, size_t size, int flags)
{
return fsetxattr(fd, name, value, size, 0, flags);
}
static int _wrap_darwin_setxattr(const char *path, const char *name, void *value, size_t size, int flags)
{
return setxattr(path, name, value, size, 0, flags);
}
static int _wrap_darwin_fremovexattr(int fd, const char *name)
{
return fremovexattr(fd, name, 0);
}
static int _wrap_darwin_removexattr(const char *path, const char *name)
{
return removexattr(path, name, 0);
}
#define fgetxattr _wrap_darwin_fgetxattr
#define getxattr _wrap_darwin_getxattr
#define fsetxattr _wrap_darwin_fsetxattr
#define setxattr _wrap_darwin_setxattr
#define fremovexattr _wrap_darwin_fremovexattr
#define removexattr _wrap_darwin_removexattr
#elif !defined(HAVE_XATTR_SUPPORT)
static ssize_t _none_fgetxattr(int fd, const char *name, void *value, size_t size)
{
errno = ENOSYS;
return -1;
}
static ssize_t _none_getxattr(const char *path, const char *name, void *value, size_t size)
{
errno = ENOSYS;
return -1;
}
static int _none_fsetxattr(int fd, const char *name, void *value, size_t size, int flags)
{
errno = ENOSYS;
return -1;
}
static int _none_setxattr(const char *path, const char *name, void *value, size_t size, int flags)
{
errno = ENOSYS;
return -1;
}
static int _none_fremovexattr(int fd, const char *name)
{
errno = ENOSYS;
return -1;
}
static int _none_removexattr(const char *path, const char *name)
{
errno = ENOSYS;
return -1;
}
#define fgetxattr _none_fgetxattr
#define getxattr _none_getxattr
#define fsetxattr _none_fsetxattr
#define setxattr _none_setxattr
#define fremovexattr _none_fremovexattr
#define removexattr _none_removexattr
#endif
_PUBLIC_ ssize_t wrap_fgetxattr(int fd, const char *name, void *value, size_t size)
{
return fgetxattr(fd, name, value, size);
}
_PUBLIC_ ssize_t wrap_getxattr(const char *path, const char *name, void *value, size_t size)
{
return getxattr(path, name, value, size);
}
_PUBLIC_ int wrap_fsetxattr(int fd, const char *name, void *value, size_t size, int flags)
{
return fsetxattr(fd, name, value, size, flags);
}
_PUBLIC_ int wrap_setxattr(const char *path, const char *name, void *value, size_t size, int flags)
{
return setxattr(path, name, value, size, flags);
}
_PUBLIC_ int wrap_fremovexattr(int fd, const char *name)
{
return fremovexattr(fd, name);
}
_PUBLIC_ int wrap_removexattr(const char *path, const char *name)
{
return removexattr(path, name);
}
+32
View File
@@ -0,0 +1,32 @@
dnl ############################################
dnl use flistxattr as the key function for having
dnl sufficient xattr support for posix xattr backend
AC_CHECK_HEADERS(sys/attributes.h attr/xattr.h sys/xattr.h)
AC_SEARCH_LIBS_EXT(flistxattr, [attr], XATTR_LIBS)
AC_CHECK_FUNC_EXT(flistxattr, $XATTR_LIBS)
SMB_EXT_LIB(XATTR,[${XATTR_LIBS}],[${XATTR_CFLAGS}],[${XATTR_CPPFLAGS}],[${XATTR_LDFLAGS}])
if test x"$ac_cv_func_ext_flistxattr" = x"yes"; then
AC_CACHE_CHECK([whether xattr interface takes additional options], smb_attr_cv_xattr_add_opt,
[old_LIBS=$LIBS
LIBS="$LIBS $XATTRLIBS"
AC_TRY_COMPILE([
#include <sys/types.h>
#if HAVE_ATTR_XATTR_H
#include <attr/xattr.h>
#elif HAVE_SYS_XATTR_H
#include <sys/xattr.h>
#endif
#ifndef NULL
#define NULL ((void *)0)
#endif
],[
getxattr(NULL, NULL, NULL, 0, 0, 0);
],smb_attr_cv_xattr_add_opt=yes,smb_attr_cv_xattr_add_opt=no)
LIBS=$old_LIBS])
if test x"$smb_attr_cv_xattr_add_opt" = x"yes"; then
AC_DEFINE(XATTR_ADDITIONAL_OPTIONS, 1, [xattr functions have additional options])
fi
AC_DEFINE(HAVE_XATTR_SUPPORT,1,[Whether we have xattr support])
SMB_ENABLE(XATTR,YES)
fi
+390
View File
@@ -0,0 +1,390 @@
/*
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.
*/
/**
* @file
* @brief scalable FILE replacement
*/
/*
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);
}
+49
View File
@@ -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_ */