1
0
mirror of https://github.com/samba-team/samba.git synced 2025-11-30 20:23:49 +03:00

first public release of samba4 code

This commit is contained in:
Andrew Tridgell
-
commit b0510b5428
779 changed files with 352638 additions and 0 deletions

3
source/lib/.cvsignore Normal file
View File

@@ -0,0 +1,3 @@
*.po
*.po32

169
source/lib/account_pol.c Normal file
View File

@@ -0,0 +1,169 @@
/*
* Unix SMB/CIFS implementation.
* account policy storage
* Copyright (C) Jean Fran<61>ois Micouleau 1998-2001.
* 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 TDB_CONTEXT *tdb; /* used for driver files */
#define DATABASE_VERSION 1
/****************************************************************************
Open the account policy tdb.
****************************************************************************/
BOOL init_account_policy(void)
{
static pid_t local_pid;
const char *vstring = "INFO/version";
uint32 version;
TALLOC_CTX *mem_ctx;
if (tdb && local_pid == getpid())
return True;
mem_ctx = talloc_init("init_account_policy");
if (!mem_ctx) {
DEBUG(0,("No memory to open account policy database\n"));
return False;
}
tdb = tdb_open_log(lock_path(mem_ctx, "account_policy.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
talloc_destroy(mem_ctx);
if (!tdb) {
DEBUG(0,("Failed to open account policy database\n"));
return False;
}
local_pid = getpid();
/* handle a Samba upgrade */
tdb_lock_bystring(tdb, vstring,0);
if (!tdb_fetch_uint32(tdb, vstring, &version) || version != DATABASE_VERSION) {
tdb_traverse(tdb, tdb_traverse_delete_fn, NULL);
tdb_store_uint32(tdb, vstring, DATABASE_VERSION);
account_policy_set(AP_MIN_PASSWORD_LEN, MINPASSWDLENGTH); /* 5 chars minimum */
account_policy_set(AP_PASSWORD_HISTORY, 0); /* don't keep any old password */
account_policy_set(AP_USER_MUST_LOGON_TO_CHG_PASS, 0); /* don't force user to logon */
account_policy_set(AP_MAX_PASSWORD_AGE, MAX_PASSWORD_AGE); /* 21 days */
account_policy_set(AP_MIN_PASSWORD_AGE, 0); /* 0 days */
account_policy_set(AP_LOCK_ACCOUNT_DURATION, 0); /* lockout for 0 minutes */
account_policy_set(AP_RESET_COUNT_TIME, 0); /* reset immediatly */
account_policy_set(AP_BAD_ATTEMPT_LOCKOUT, 0); /* don't lockout */
account_policy_set(AP_TIME_TO_LOGOUT, -1); /* don't force logout */
}
tdb_unlock_bystring(tdb, vstring);
return True;
}
static const struct {
int field;
const char *string;
} account_policy_names[] = {
{AP_MIN_PASSWORD_LEN, "min password length"},
{AP_PASSWORD_HISTORY, "password history"},
{AP_USER_MUST_LOGON_TO_CHG_PASS, "user must logon to change password"},
{AP_MAX_PASSWORD_AGE, "maximum password age"},
{AP_MIN_PASSWORD_AGE,"minimum password age"},
{AP_LOCK_ACCOUNT_DURATION, "lockout duration"},
{AP_RESET_COUNT_TIME, "reset count minutes"},
{AP_BAD_ATTEMPT_LOCKOUT, "bad lockout attempt"},
{AP_TIME_TO_LOGOUT, "disconnect time"},
{0, NULL}
};
/****************************************************************************
Get the account policy name as a string from its #define'ed number
****************************************************************************/
static const char *decode_account_policy_name(int field)
{
int i;
for (i=0; account_policy_names[i].string; i++) {
if (field == account_policy_names[i].field)
return account_policy_names[i].string;
}
return NULL;
}
/****************************************************************************
Get the account policy name as a string from its #define'ed number
****************************************************************************/
int account_policy_name_to_fieldnum(const char *name)
{
int i;
for (i=0; account_policy_names[i].string; i++) {
if (strcmp(name, account_policy_names[i].string) == 0)
return account_policy_names[i].field;
}
return 0;
}
/****************************************************************************
****************************************************************************/
BOOL account_policy_get(int field, uint32 *value)
{
fstring name;
init_account_policy();
*value = 0;
fstrcpy(name, decode_account_policy_name(field));
if (!*name) {
DEBUG(1, ("account_policy_get: Field %d is not a valid account policy type! Cannot get, returning 0.\n", field));
return False;
}
if (!tdb_fetch_uint32(tdb, name, value)) {
DEBUG(1, ("account_policy_get: tdb_fetch_uint32 failed for efild %d (%s), returning 0", field, name));
return False;
}
DEBUG(10,("account_policy_get: %s:%d\n", name, *value));
return True;
}
/****************************************************************************
****************************************************************************/
BOOL account_policy_set(int field, uint32 value)
{
fstring name;
init_account_policy();
fstrcpy(name, decode_account_policy_name(field));
if (!*name) {
DEBUG(1, ("Field %d is not a valid account policy type! Cannot set.\n", field));
return False;
}
if (!tdb_store_uint32(tdb, name, value)) {
DEBUG(1, ("tdb_store_uint32 failed for field %d (%s) on value %u", field, name, value));
return False;
}
DEBUG(10,("account_policy_set: %s:%d\n", name, value));
return True;
}

464
source/lib/adt_tree.c Normal file
View File

@@ -0,0 +1,464 @@
/*
* Unix SMB/CIFS implementation.
* Generic Abstract Data Types
* Copyright (C) Gerald Carter 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"
/**************************************************************************
Initialize the tree's root. The cmp_fn is a callback function used
for comparision of two children
*************************************************************************/
static BOOL trim_tree_keypath( char *path, char **base, char **new_path )
{
char *p;
*new_path = *base = NULL;
if ( !path )
return False;
*base = path;
p = strchr( path, '/' );
if ( p ) {
*p = '\0';
*new_path = p+1;
}
return True;
}
/**************************************************************************
Initialize the tree's root. The cmp_fn is a callback function used
for comparision of two children
*************************************************************************/
SORTED_TREE* sorted_tree_init( void *data_p,
int (cmp_fn)(void*, void*),
void (free_fn)(void*) )
{
SORTED_TREE *tree = NULL;
if ( !(tree = (SORTED_TREE*)malloc( sizeof(SORTED_TREE) )) )
return NULL;
ZERO_STRUCTP( tree );
tree->compare = cmp_fn;
tree->free = free_fn;
if ( !(tree->root = (TREE_NODE*)malloc( sizeof(TREE_NODE) )) ) {
SAFE_FREE( tree );
return NULL;
}
ZERO_STRUCTP( tree->root );
tree->root->data_p = data_p;
return tree;
}
/**************************************************************************
Delete a tree and free all allocated memory
*************************************************************************/
static void sorted_tree_destroy_children( TREE_NODE *root )
{
int i;
if ( !root )
return;
for ( i=0; i<root->num_children; i++ )
{
sorted_tree_destroy_children( root->children[i] );
}
SAFE_FREE( root->children );
SAFE_FREE( root->key );
return;
}
/**************************************************************************
Delete a tree and free all allocated memory
*************************************************************************/
void sorted_tree_destroy( SORTED_TREE *tree )
{
if ( tree->root )
sorted_tree_destroy_children( tree->root );
if ( tree->free )
tree->free( tree->root );
SAFE_FREE( tree );
}
/**************************************************************************
Find the next child given a key string
*************************************************************************/
static TREE_NODE* sorted_tree_birth_child( TREE_NODE *node, char* key )
{
TREE_NODE *infant = NULL;
TREE_NODE **siblings;
int i;
if ( !(infant = (TREE_NODE*)malloc( sizeof(TREE_NODE) )) )
return NULL;
ZERO_STRUCTP( infant );
infant->key = strdup( key );
infant->parent = node;
siblings = Realloc( node->children, sizeof(TREE_NODE*)*(node->num_children+1) );
if ( siblings )
node->children = siblings;
node->num_children++;
/* first child */
if ( node->num_children == 1 ) {
DEBUG(11,("sorted_tree_birth_child: First child of node [%s]! [%s]\n",
node->key ? node->key : "NULL", infant->key ));
node->children[0] = infant;
}
else
{
/*
* multiple siblings .... (at least 2 children)
*
* work from the end of the list forward
* The last child is not set at this point
* Insert the new infanct in ascending order
* from left to right
*/
for ( i = node->num_children-1; i>=1; i-- )
{
DEBUG(11,("sorted_tree_birth_child: Looking for crib; infant -> [%s], child -> [%s]\n",
infant->key, node->children[i-1]->key));
/* the strings should never match assuming that we
have called sorted_tree_find_child() first */
if ( StrCaseCmp( infant->key, node->children[i-1]->key ) > 0 ) {
DEBUG(11,("sorted_tree_birth_child: storing infant in i == [%d]\n",
i));
node->children[i] = infant;
break;
}
/* bump everything towards the end on slot */
node->children[i] = node->children[i-1];
}
DEBUG(11,("sorted_tree_birth_child: Exiting loop (i == [%d])\n", i ));
/* if we haven't found the correct slot yet, the child
will be first in the list */
if ( i == 0 )
node->children[0] = infant;
}
return infant;
}
/**************************************************************************
Find the next child given a key string
*************************************************************************/
static TREE_NODE* sorted_tree_find_child( TREE_NODE *node, char* key )
{
TREE_NODE *next = NULL;
int i, result;
if ( !node ) {
DEBUG(0,("sorted_tree_find_child: NULL node passed into function!\n"));
return NULL;
}
if ( !key ) {
DEBUG(0,("sorted_tree_find_child: NULL key string passed into function!\n"));
return NULL;
}
for ( i=0; i<node->num_children; i++ )
{
DEBUG(11,("sorted_tree_find_child: child key => [%s]\n",
node->children[i]->key));
result = StrCaseCmp( node->children[i]->key, key );
if ( result == 0 )
next = node->children[i];
/* if result > 0 then we've gone to far because
the list of children is sorted by key name
If result == 0, then we have a match */
if ( result > 0 )
break;
}
DEBUG(11,("sorted_tree_find_child: %s [%s]\n",
next ? "Found" : "Did not find", key ));
return next;
}
/**************************************************************************
Add a new node into the tree given a key path and a blob of data
*************************************************************************/
BOOL sorted_tree_add( SORTED_TREE *tree, const char *path, void *data_p )
{
char *str, *base, *path2;
TREE_NODE *current, *next;
BOOL ret = True;
DEBUG(8,("sorted_tree_add: Enter\n"));
if ( !path || *path != '/' ) {
DEBUG(0,("sorted_tree_add: Attempt to add a node with a bad path [%s]\n",
path ? path : "NULL" ));
return False;
}
if ( !tree ) {
DEBUG(0,("sorted_tree_add: Attempt to add a node to an uninitialized tree!\n"));
return False;
}
/* move past the first '/' */
path++;
path2 = strdup( path );
if ( !path2 ) {
DEBUG(0,("sorted_tree_add: strdup() failed on string [%s]!?!?!\n", path));
return False;
}
/*
* this works sort of like a 'mkdir -p' call, possibly
* creating an entire path to the new node at once
* The path should be of the form /<key1>/<key2>/...
*/
base = path2;
str = path2;
current = tree->root;
do {
/* break off the remaining part of the path */
str = strchr( str, '/' );
if ( str )
*str = '\0';
/* iterate to the next child--birth it if necessary */
next = sorted_tree_find_child( current, base );
if ( !next ) {
next = sorted_tree_birth_child( current, base );
if ( !next ) {
DEBUG(0,("sorted_tree_add: Failed to create new child!\n"));
ret = False;
goto done;
}
}
current = next;
/* setup the next part of the path */
base = str;
if ( base ) {
*base = '/';
base++;
str = base;
}
} while ( base != NULL );
current->data_p = data_p;
DEBUG(10,("sorted_tree_add: Successfully added node [%s] to tree\n",
path ));
DEBUG(8,("sorted_tree_add: Exit\n"));
done:
SAFE_FREE( path2 );
return ret;
}
/**************************************************************************
Recursive routine to print out all children of a TREE_NODE
*************************************************************************/
static void sorted_tree_print_children( TREE_NODE *node, int debug, const char *path )
{
int i;
int num_children;
pstring path2;
if ( !node )
return;
if ( node->key )
DEBUG(debug,("%s: [%s] (%s)\n", path ? path : "NULL", node->key,
node->data_p ? "data" : "NULL" ));
*path2 = '\0';
if ( path )
pstrcpy( path2, path );
pstrcat( path2, node->key ? node->key : "NULL" );
pstrcat( path2, "/" );
num_children = node->num_children;
for ( i=0; i<num_children; i++ )
sorted_tree_print_children( node->children[i], debug, path2 );
}
/**************************************************************************
Dump the kys for a tree to the log file
*************************************************************************/
void sorted_tree_print_keys( SORTED_TREE *tree, int debug )
{
int i;
int num_children = tree->root->num_children;
if ( tree->root->key )
DEBUG(debug,("ROOT/: [%s] (%s)\n", tree->root->key,
tree->root->data_p ? "data" : "NULL" ));
for ( i=0; i<num_children; i++ ) {
sorted_tree_print_children( tree->root->children[i], debug,
tree->root->key ? tree->root->key : "ROOT/" );
}
}
/**************************************************************************
return the data_p for for the node in tree matching the key string
The key string is the full path. We must break it apart and walk
the tree
*************************************************************************/
void* sorted_tree_find( SORTED_TREE *tree, char *key )
{
char *keystr, *base, *str, *p;
TREE_NODE *current;
void *result = NULL;
DEBUG(10,("sorted_tree_find: Enter [%s]\n", key ? key : "NULL" ));
/* sanity checks first */
if ( !key ) {
DEBUG(0,("sorted_tree_find: Attempt to search tree using NULL search string!\n"));
return NULL;
}
if ( !tree ) {
DEBUG(0,("sorted_tree_find: Attempt to search an uninitialized tree using string [%s]!\n",
key ? key : "NULL" ));
return NULL;
}
if ( !tree->root )
return NULL;
/* make a copy to play with */
if ( *key == '/' )
keystr = strdup( key+1 );
else
keystr = strdup( key );
if ( !keystr ) {
DEBUG(0,("sorted_tree_find: strdup() failed on string [%s]!?!?!\n", key));
return NULL;
}
/* start breaking the path apart */
p = keystr;
current = tree->root;
if ( tree->root->data_p )
result = tree->root->data_p;
do
{
/* break off the remaining part of the path */
trim_tree_keypath( p, &base, &str );
DEBUG(11,("sorted_tree_find: [loop] base => [%s], new_path => [%s]\n",
base, str));
/* iterate to the next child */
current = sorted_tree_find_child( current, base );
/*
* the idea is that the data_p for a parent should
* be inherited by all children, but allow it to be
* overridden farther down
*/
if ( current && current->data_p )
result = current->data_p;
/* reset the path pointer 'p' to the remaining part of the key string */
p = str;
} while ( str && current );
/* result should be the data_p from the lowest match node in the tree */
if ( result )
DEBUG(11,("sorted_tree_find: Found data_p!\n"));
SAFE_FREE( keystr );
DEBUG(10,("sorted_tree_find: Exit\n"));
return result;
}

163
source/lib/bitmap.c Normal file
View File

@@ -0,0 +1,163 @@
/*
Unix SMB/CIFS implementation.
simple bitmap functions
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"
/* these functions provide a simple way to allocate integers from a
pool without repetition */
/****************************************************************************
allocate a bitmap of the specified size
****************************************************************************/
struct bitmap *bitmap_allocate(int n)
{
struct bitmap *bm;
bm = (struct bitmap *)malloc(sizeof(*bm));
if (!bm) return NULL;
bm->n = n;
bm->b = (uint32 *)malloc(sizeof(bm->b[0])*(n+31)/32);
if (!bm->b) {
SAFE_FREE(bm);
return NULL;
}
memset(bm->b, 0, sizeof(bm->b[0])*(n+31)/32);
return bm;
}
/****************************************************************************
free a bitmap.
****************************************************************************/
void bitmap_free(struct bitmap *bm)
{
if (!bm)
return;
SAFE_FREE(bm->b);
SAFE_FREE(bm);
}
/****************************************************************************
talloc a bitmap
****************************************************************************/
struct bitmap *bitmap_talloc(TALLOC_CTX *mem_ctx, int n)
{
struct bitmap *bm;
if (!mem_ctx) return NULL;
bm = (struct bitmap *)talloc(mem_ctx, sizeof(*bm));
if (!bm) return NULL;
bm->n = n;
bm->b = (uint32 *)talloc(mem_ctx, sizeof(bm->b[0])*(n+31)/32);
if (!bm->b) {
return NULL;
}
memset(bm->b, 0, sizeof(bm->b[0])*(n+31)/32);
return bm;
}
/****************************************************************************
set a bit in a bitmap
****************************************************************************/
BOOL bitmap_set(struct bitmap *bm, unsigned i)
{
if (i >= bm->n) {
DEBUG(0,("Setting invalid bitmap entry %d (of %d)\n",
i, bm->n));
return False;
}
bm->b[i/32] |= (1<<(i%32));
return True;
}
/****************************************************************************
clear a bit in a bitmap
****************************************************************************/
BOOL bitmap_clear(struct bitmap *bm, unsigned i)
{
if (i >= bm->n) {
DEBUG(0,("clearing invalid bitmap entry %d (of %d)\n",
i, bm->n));
return False;
}
bm->b[i/32] &= ~(1<<(i%32));
return True;
}
/****************************************************************************
query a bit in a bitmap
****************************************************************************/
BOOL bitmap_query(struct bitmap *bm, unsigned i)
{
if (i >= bm->n) return False;
if (bm->b[i/32] & (1<<(i%32))) {
return True;
}
return False;
}
/****************************************************************************
find a zero bit in a bitmap starting at the specified offset, with
wraparound
****************************************************************************/
int bitmap_find(struct bitmap *bm, unsigned ofs)
{
unsigned int i, j;
if (ofs > bm->n) ofs = 0;
i = ofs;
while (i < bm->n) {
if (~(bm->b[i/32])) {
j = i;
do {
if (!bitmap_query(bm, j)) return j;
j++;
} while (j & 31 && j < bm->n);
}
i += 32;
i &= ~31;
}
i = 0;
while (i < ofs) {
if (~(bm->b[i/32])) {
j = i;
do {
if (!bitmap_query(bm, j)) return j;
j++;
} while (j & 31 && j < bm->n);
}
i += 32;
i &= ~31;
}
return -1;
}

925
source/lib/charcnv.c Normal file
View File

@@ -0,0 +1,925 @@
/*
Unix SMB/CIFS implementation.
Character set conversion Extensions
Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
Copyright (C) Andrew Tridgell 2001
Copyright (C) Simo Sorce 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
/**
* @file
*
* @brief Character-set conversion routines built on our iconv.
*
* @note Samba's internal character set (at least in the 3.0 series)
* is always the same as the one for the Unix filesystem. It is
* <b>not</b> necessarily UTF-8 and may be different on machines that
* need i18n filenames to be compatible with Unix software. It does
* have to be a superset of ASCII. All multibyte sequences must start
* with a byte with the high bit set.
*
* @sa lib/iconv.c
*/
static smb_iconv_t conv_handles[NUM_CHARSETS][NUM_CHARSETS];
/**
* Return the name of a charset to give to iconv().
**/
static const char *charset_name(charset_t ch)
{
const char *ret = NULL;
if (ch == CH_UCS2) ret = "UCS-2LE";
else if (ch == CH_UNIX) ret = lp_unix_charset();
else if (ch == CH_DOS) ret = lp_dos_charset();
else if (ch == CH_DISPLAY) ret = lp_display_charset();
else if (ch == CH_UTF8) ret = "UTF8";
if (!ret || !*ret) ret = "ASCII";
return ret;
}
static void lazy_initialize_conv(void)
{
static int initialized = False;
if (!initialized) {
initialized = True;
load_case_tables();
init_iconv();
init_valid_table();
}
}
/**
Initialize iconv conversion descriptors.
**/
void init_iconv(void)
{
int c1, c2;
BOOL did_reload = False;
/* so that charset_name() works we need to get the UNIX<->UCS2 going
first */
if (!conv_handles[CH_UNIX][CH_UCS2])
conv_handles[CH_UNIX][CH_UCS2] = smb_iconv_open("UCS-2LE", "ASCII");
if (!conv_handles[CH_UCS2][CH_UNIX])
conv_handles[CH_UCS2][CH_UNIX] = smb_iconv_open("ASCII", "UCS-2LE");
for (c1=0;c1<NUM_CHARSETS;c1++) {
for (c2=0;c2<NUM_CHARSETS;c2++) {
const char *n1 = charset_name((charset_t)c1);
const char *n2 = charset_name((charset_t)c2);
if (conv_handles[c1][c2] &&
strcmp(n1, conv_handles[c1][c2]->from_name) == 0 &&
strcmp(n2, conv_handles[c1][c2]->to_name) == 0)
continue;
did_reload = True;
if (conv_handles[c1][c2])
smb_iconv_close(conv_handles[c1][c2]);
conv_handles[c1][c2] = smb_iconv_open(n2,n1);
if (conv_handles[c1][c2] == (smb_iconv_t)-1) {
DEBUG(0,("Conversion from %s to %s not supported\n",
charset_name((charset_t)c1), charset_name((charset_t)c2)));
conv_handles[c1][c2] = NULL;
}
}
}
if (did_reload) {
init_valid_table();
}
}
/**
* Convert string from one encoding to another, making error checking etc
*
* @param src pointer to source string (multibyte or singlebyte)
* @param srclen length of the source string in bytes
* @param dest pointer to destination string (multibyte or singlebyte)
* @param destlen maximal length allowed for string
* @returns the number of bytes occupied in the destination
**/
ssize_t convert_string(charset_t from, charset_t to,
void const *src, size_t srclen,
void *dest, size_t destlen)
{
size_t i_len, o_len;
size_t retval;
const char* inbuf = (const char*)src;
char* outbuf = (char*)dest;
smb_iconv_t descriptor;
if (srclen == (size_t)-1)
srclen = strlen(src)+1;
lazy_initialize_conv();
descriptor = conv_handles[from][to];
if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
/* conversion not supported, use as is */
size_t len = MIN(srclen,destlen);
memcpy(dest,src,len);
return len;
}
i_len=srclen;
o_len=destlen;
retval = smb_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len);
if(retval==(size_t)-1) {
const char *reason="unknown error";
switch(errno) {
case EINVAL:
reason="Incomplete multibyte sequence";
break;
case E2BIG:
reason="No more room";
DEBUG(0, ("convert_string: Required %d, available %d\n",
srclen, destlen));
/* we are not sure we need srclen bytes,
may be more, may be less.
We only know we need more than destlen
bytes ---simo */
break;
case EILSEQ:
reason="Illegal multibyte sequence";
break;
}
/* smb_panic(reason); */
}
return destlen-o_len;
}
/**
* Convert between character sets, allocating a new buffer for the result.
*
* @param srclen length of source buffer.
* @param dest always set at least to NULL
* @note -1 is not accepted for srclen.
*
* @returns Size in bytes of the converted string; or -1 in case of error.
**/
ssize_t convert_string_allocate(charset_t from, charset_t to,
void const *src, size_t srclen, void **dest)
{
size_t i_len, o_len, destlen;
size_t retval;
const char *inbuf = (const char *)src;
char *outbuf, *ob;
smb_iconv_t descriptor;
*dest = NULL;
if (src == NULL || srclen == (size_t)-1 || srclen == 0)
return (size_t)-1;
lazy_initialize_conv();
descriptor = conv_handles[from][to];
if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
/* conversion not supported, return -1*/
DEBUG(3, ("convert_string_allocate: conversion not supported!\n"));
return -1;
}
destlen = MAX(srclen, 512);
outbuf = NULL;
convert:
destlen = destlen * 2;
ob = (char *)realloc(outbuf, destlen);
if (!ob) {
DEBUG(0, ("convert_string_allocate: realloc failed!\n"));
SAFE_FREE(outbuf);
return (size_t)-1;
}
else
outbuf = ob;
i_len = srclen;
o_len = destlen;
retval = smb_iconv(descriptor,
&inbuf, &i_len,
&outbuf, &o_len);
if(retval == (size_t)-1) {
const char *reason="unknown error";
switch(errno) {
case EINVAL:
reason="Incomplete multibyte sequence";
break;
case E2BIG:
goto convert;
case EILSEQ:
reason="Illegal multibyte sequence";
break;
}
DEBUG(0,("Conversion error: %s(%s)\n",reason,inbuf));
/* smb_panic(reason); */
return (size_t)-1;
}
destlen = destlen - o_len;
*dest = (char *)Realloc(ob,destlen);
if (!*dest) {
DEBUG(0, ("convert_string_allocate: out of memory!\n"));
SAFE_FREE(ob);
return (size_t)-1;
}
return destlen;
}
/**
* Convert between character sets, allocating a new buffer using talloc for the result.
*
* @param srclen length of source buffer.
* @param dest always set at least to NULL
* @note -1 is not accepted for srclen.
*
* @returns Size in bytes of the converted string; or -1 in case of error.
**/
ssize_t convert_string_talloc(TALLOC_CTX *ctx, charset_t from, charset_t to,
void const *src, size_t srclen, const void **dest)
{
void *alloced_string;
size_t dest_len;
void *dst;
*dest = NULL;
dest_len=convert_string_allocate(from, to, src, srclen, &alloced_string);
if (dest_len == (size_t)-1)
return (size_t)-1;
dst = talloc(ctx, dest_len + 2);
/* we want to be absolutely sure that the result is terminated */
memcpy(dst, alloced_string, dest_len);
SSVAL(dst, dest_len, 0);
SAFE_FREE(alloced_string);
if (dst == NULL)
return -1;
*dest = dst;
return dest_len;
}
size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
{
size_t size;
smb_ucs2_t *buffer;
size = convert_string_allocate(CH_UNIX, CH_UCS2, src, srclen,
(void **) &buffer);
if (size == -1) {
smb_panic("failed to create UCS2 buffer");
}
if (!strupper_w(buffer) && (dest == src)) {
free(buffer);
return srclen;
}
size = convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
free(buffer);
return size;
}
size_t unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
{
size_t size;
smb_ucs2_t *buffer;
size = convert_string_allocate(CH_UNIX, CH_UCS2, src, srclen,
(void **) &buffer);
if (size == -1) {
smb_panic("failed to create UCS2 buffer");
}
if (!strlower_w(buffer) && (dest == src)) {
free(buffer);
return srclen;
}
size = convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
free(buffer);
return size;
}
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;
}
/**
* Copy a string from a char* unix src to a dos codepage string destination.
*
* @return the number of bytes occupied by the string in the destination.
*
* @param flags can include
* <dl>
* <dt>STR_TERMINATE</dt> <dd>means include the null termination</dd>
* <dt>STR_UPPER</dt> <dd>means uppercase in the destination</dd>
* </dl>
*
* @param dest_len the maximum length in bytes allowed in the
* destination. If @p dest_len is -1 then no maximum is used.
**/
ssize_t push_ascii(void *dest, const char *src, size_t dest_len, int flags)
{
size_t src_len = strlen(src);
pstring tmpbuf;
/* treat a pstring as "unlimited" length */
if (dest_len == (size_t)-1)
dest_len = sizeof(pstring);
if (flags & STR_UPPER) {
pstrcpy(tmpbuf, src);
strupper(tmpbuf);
src = tmpbuf;
}
if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII))
src_len++;
return convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len);
}
ssize_t push_ascii_fstring(void *dest, const char *src)
{
return push_ascii(dest, src, sizeof(fstring), STR_TERMINATE);
}
ssize_t push_ascii_pstring(void *dest, const char *src)
{
return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
}
ssize_t push_pstring(void *dest, const char *src)
{
return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
}
/**
* Copy a string from a dos codepage source to a unix char* destination.
*
* The resulting string in "dest" is always null terminated.
*
* @param flags can have:
* <dl>
* <dt>STR_TERMINATE</dt>
* <dd>STR_TERMINATE means the string in @p src
* is null terminated, and src_len is ignored.</dd>
* </dl>
*
* @param src_len is the length of the source area in bytes.
* @returns the number of bytes occupied by the string in @p src.
**/
ssize_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
{
size_t ret;
if (dest_len == (size_t)-1)
dest_len = sizeof(pstring);
if (flags & STR_TERMINATE) {
if (src_len == (size_t)-1) {
src_len = strlen(src) + 1;
} else {
size_t len = strnlen(src, src_len);
if (len < src_len)
len++;
src_len = len;
}
}
ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len);
if (dest_len)
dest[MIN(ret, dest_len-1)] = 0;
return src_len;
}
ssize_t pull_ascii_pstring(char *dest, const void *src)
{
return pull_ascii(dest, src, sizeof(pstring), -1, STR_TERMINATE);
}
ssize_t pull_ascii_fstring(char *dest, const void *src)
{
return pull_ascii(dest, src, sizeof(fstring), -1, STR_TERMINATE);
}
/**
* Copy a string from a char* src to a unicode destination.
*
* @returns the number of bytes occupied by the string in the destination.
*
* @param flags can have:
*
* <dl>
* <dt>STR_TERMINATE <dd>means include the null termination.
* <dt>STR_UPPER <dd>means uppercase in the destination.
* <dt>STR_NOALIGN <dd>means don't do alignment.
* </dl>
*
* @param dest_len is the maximum length allowed in the
* destination. If dest_len is -1 then no maxiumum is used.
**/
ssize_t push_ucs2(const void *base_ptr, void *dest, const char *src, size_t dest_len, int flags)
{
size_t len=0;
size_t src_len = strlen(src);
pstring tmpbuf;
/* treat a pstring as "unlimited" length */
if (dest_len == (size_t)-1)
dest_len = sizeof(pstring);
if (flags & STR_UPPER) {
pstrcpy(tmpbuf, src);
strupper(tmpbuf);
src = tmpbuf;
}
if (flags & STR_TERMINATE)
src_len++;
if (ucs2_align(base_ptr, dest, flags)) {
*(char *)dest = 0;
dest = (void *)((char *)dest + 1);
if (dest_len) dest_len--;
len++;
}
/* ucs2 is always a multiple of 2 bytes */
dest_len &= ~1;
len += convert_string(CH_UNIX, CH_UCS2, src, src_len, dest, dest_len);
return len;
}
/**
* Copy a string from a unix char* src to a UCS2 destination,
* allocating a buffer using talloc().
*
* @param dest always set at least to NULL
*
* @returns The number of bytes occupied by the string in the destination
* or -1 in case of error.
**/
ssize_t push_ucs2_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src)
{
size_t src_len = strlen(src)+1;
*dest = NULL;
return convert_string_talloc(ctx, CH_UNIX, CH_UCS2, src, src_len, (const void **)dest);
}
/**
* Copy a string from a unix char* src to a UCS2 destination, allocating a buffer
*
* @param dest always set at least to NULL
*
* @returns The number of bytes occupied by the string in the destination
* or -1 in case of error.
**/
ssize_t push_ucs2_allocate(smb_ucs2_t **dest, const char *src)
{
size_t src_len = strlen(src)+1;
*dest = NULL;
return convert_string_allocate(CH_UNIX, CH_UCS2, src, src_len, (void **)dest);
}
/**
Copy a string from a char* src to a UTF-8 destination.
Return the number of bytes occupied by the string in the destination
Flags can have:
STR_TERMINATE means include the null termination
STR_UPPER means uppercase in the destination
dest_len is the maximum length allowed in the destination. If dest_len
is -1 then no maxiumum is used.
**/
ssize_t push_utf8(void *dest, const char *src, size_t dest_len, int flags)
{
size_t src_len = strlen(src);
pstring tmpbuf;
/* treat a pstring as "unlimited" length */
if (dest_len == (size_t)-1)
dest_len = sizeof(pstring);
if (flags & STR_UPPER) {
pstrcpy(tmpbuf, src);
strupper(tmpbuf);
src = tmpbuf;
}
if (flags & STR_TERMINATE)
src_len++;
return convert_string(CH_UNIX, CH_UTF8, src, src_len, dest, dest_len);
}
ssize_t push_utf8_fstring(void *dest, const char *src)
{
return push_utf8(dest, src, sizeof(fstring), STR_TERMINATE);
}
ssize_t push_utf8_pstring(void *dest, const char *src)
{
return push_utf8(dest, src, sizeof(pstring), STR_TERMINATE);
}
/**
* Copy a string from a unix char* src to a UTF-8 destination, allocating a buffer using talloc
*
* @param dest always set at least to NULL
*
* @returns The number of bytes occupied by the string in the destination
**/
ssize_t push_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src)
{
size_t src_len = strlen(src)+1;
*dest = NULL;
return convert_string_talloc(ctx, CH_UNIX, CH_UTF8, src, src_len, (const void **)dest);
}
/**
* Copy a string from a unix char* src to a UTF-8 destination, allocating a buffer
*
* @param dest always set at least to NULL
*
* @returns The number of bytes occupied by the string in the destination
**/
ssize_t push_utf8_allocate(char **dest, const char *src)
{
size_t src_len = strlen(src)+1;
*dest = NULL;
return convert_string_allocate(CH_UNIX, CH_UTF8, src, src_len, (void **)dest);
}
/**
Copy a string from a ucs2 source to a unix char* destination.
Flags can have:
STR_TERMINATE means the string in src is null terminated.
STR_NOALIGN means don't try to align.
if STR_TERMINATE is set then src_len is ignored if it is -1.
src_len is the length of the source area in bytes
Return the number of bytes occupied by the string in src.
The resulting string in "dest" is always null terminated.
**/
size_t pull_ucs2(const void *base_ptr, char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
{
size_t ret;
if (dest_len == (size_t)-1)
dest_len = sizeof(pstring);
if (ucs2_align(base_ptr, src, flags)) {
src = (const void *)((const char *)src + 1);
if (src_len > 0)
src_len--;
}
if (flags & STR_TERMINATE) {
if (src_len == (size_t)-1) {
src_len = strlen_w(src)*2 + 2;
} else {
size_t len = strnlen_w(src, src_len/2);
if (len < src_len/2)
len++;
src_len = len*2;
}
}
/* ucs2 is always a multiple of 2 bytes */
if (src_len != (size_t)-1)
src_len &= ~1;
ret = convert_string(CH_UCS2, CH_UNIX, src, src_len, dest, dest_len);
if (dest_len)
dest[MIN(ret, dest_len-1)] = 0;
return src_len;
}
ssize_t pull_ucs2_pstring(char *dest, const void *src)
{
return pull_ucs2(NULL, dest, src, sizeof(pstring), -1, STR_TERMINATE);
}
ssize_t pull_ucs2_fstring(char *dest, const void *src)
{
return pull_ucs2(NULL, dest, src, sizeof(fstring), -1, STR_TERMINATE);
}
/**
* Copy a string from a UCS2 src to a unix char * destination, allocating a buffer using talloc
*
* @param dest always set at least to NULL
*
* @returns The number of bytes occupied by the string in the destination
**/
ssize_t pull_ucs2_talloc(TALLOC_CTX *ctx, char **dest, const smb_ucs2_t *src)
{
size_t src_len = (strlen_w(src)+1) * sizeof(smb_ucs2_t);
*dest = NULL;
return convert_string_talloc(ctx, CH_UCS2, CH_UNIX, src, src_len, (const void **)dest);
}
/**
* Copy a string from a UCS2 src to a unix char * destination, allocating a buffer
*
* @param dest always set at least to NULL
*
* @returns The number of bytes occupied by the string in the destination
**/
ssize_t pull_ucs2_allocate(void **dest, const smb_ucs2_t *src)
{
size_t src_len = (strlen_w(src)+1) * sizeof(smb_ucs2_t);
*dest = NULL;
return convert_string_allocate(CH_UCS2, CH_UNIX, src, src_len, dest);
}
/**
Copy a string from a utf-8 source to a unix char* destination.
Flags can have:
STR_TERMINATE means the string in src is null terminated.
if STR_TERMINATE is set then src_len is ignored.
src_len is the length of the source area in bytes
Return the number of bytes occupied by the string in src.
The resulting string in "dest" is always null terminated.
**/
ssize_t pull_utf8(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
{
size_t ret;
if (dest_len == (size_t)-1)
dest_len = sizeof(pstring);
if (flags & STR_TERMINATE) {
if (src_len == (size_t)-1) {
src_len = strlen(src) + 1;
} else {
size_t len = strnlen(src, src_len);
if (len < src_len)
len++;
src_len = len;
}
}
ret = convert_string(CH_UTF8, CH_UNIX, src, src_len, dest, dest_len);
if (dest_len)
dest[MIN(ret, dest_len-1)] = 0;
return src_len;
}
ssize_t pull_utf8_pstring(char *dest, const void *src)
{
return pull_utf8(dest, src, sizeof(pstring), -1, STR_TERMINATE);
}
ssize_t pull_utf8_fstring(char *dest, const void *src)
{
return pull_utf8(dest, src, sizeof(fstring), -1, STR_TERMINATE);
}
/**
* Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer using talloc
*
* @param dest always set at least to NULL
*
* @returns The number of bytes occupied by the string in the destination
**/
ssize_t pull_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src)
{
size_t src_len = strlen(src)+1;
*dest = NULL;
return convert_string_talloc(ctx, CH_UTF8, CH_UNIX, src, src_len, (const void **)dest);
}
/**
* Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer
*
* @param dest always set at least to NULL
*
* @returns The number of bytes occupied by the string in the destination
**/
ssize_t pull_utf8_allocate(void **dest, const char *src)
{
size_t src_len = strlen(src)+1;
*dest = NULL;
return convert_string_allocate(CH_UTF8, CH_UNIX, src, src_len, dest);
}
/**
Copy a string from a char* src to a unicode or ascii
dos codepage destination choosing unicode or ascii based on the
flags in the SMB buffer starting at base_ptr.
Return the number of bytes occupied by the string in the destination.
flags can have:
STR_TERMINATE means include the null termination.
STR_UPPER means uppercase in the destination.
STR_ASCII use ascii even with unicode packet.
STR_NOALIGN means don't do alignment.
dest_len is the maximum length allowed in the destination. If dest_len
is -1 then no maxiumum is used.
**/
ssize_t push_string(const void *base_ptr, void *dest, const char *src, size_t dest_len, int flags)
{
if (!(flags & STR_ASCII) && \
((flags & STR_UNICODE || \
(SVAL(base_ptr, NBT_HDR_SIZE+HDR_FLG2) & FLAGS2_UNICODE_STRINGS)))) {
return push_ucs2(base_ptr, dest, src, dest_len, flags);
}
return push_ascii(dest, src, dest_len, flags);
}
/**
Copy a string from a unicode or ascii source (depending on
the packet flags) to a char* destination.
Flags can have:
STR_TERMINATE means the string in src is null terminated.
STR_UNICODE means to force as unicode.
STR_ASCII use ascii even with unicode packet.
STR_NOALIGN means don't do alignment.
if STR_TERMINATE is set then src_len is ignored is it is -1
src_len is the length of the source area in bytes.
Return the number of bytes occupied by the string in src.
The resulting string in "dest" is always null terminated.
**/
ssize_t pull_string(const void *base_ptr, char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
{
if (!(flags & STR_ASCII) && \
((flags & STR_UNICODE || \
(SVAL(base_ptr, NBT_HDR_SIZE+HDR_FLG2) & FLAGS2_UNICODE_STRINGS)))) {
return pull_ucs2(base_ptr, dest, src, dest_len, src_len, flags);
}
return pull_ascii(dest, src, dest_len, src_len, flags);
}
ssize_t align_string(const void *base_ptr, const char *p, int flags)
{
if (!(flags & STR_ASCII) && \
((flags & STR_UNICODE || \
(SVAL(base_ptr, NBT_HDR_SIZE+HDR_FLG2) & FLAGS2_UNICODE_STRINGS)))) {
return ucs2_align(base_ptr, p, flags);
}
return 0;
}
/**
Copy a string from a unicode or ascii source (depending on
the packet flags) to a TALLOC'ed destination.
Flags can have:
STR_TERMINATE means the string in src is null terminated.
STR_UNICODE means to force as unicode.
STR_ASCII use ascii even with unicode packet.
STR_NOALIGN means don't do alignment.
if STR_TERMINATE is set then src_len is ignored is it is -1
src_len is the length of the source area in bytes.
Return the number of bytes occupied by the string in src.
The resulting string in "dest" is always null terminated.
**/
ssize_t pull_string_talloc(TALLOC_CTX *ctx, char **dest, const void *src, size_t src_len, int flags)
{
if (!(flags & STR_ASCII) && \
(flags & STR_UNICODE)) {
return pull_ucs2_talloc(ctx, dest, src);
}
*dest = NULL;
if (flags & STR_TERMINATE) {
*dest = talloc_strdup(ctx, src);
return strlen(*dest);
}
*dest = talloc_strndup(ctx, src, src_len);
return src_len;
}
/**
Convert from ucs2 to unix charset and return the
allocated and converted string or NULL if an error occurred.
You must provide a zero terminated string.
The returning string will be zero terminated.
**/
char *acnv_u2ux(const smb_ucs2_t *src)
{
size_t slen;
size_t dlen;
void *dest;
slen = (strlen_w(src) + 1) * sizeof(smb_ucs2_t);
dlen = convert_string_allocate(CH_UCS2, CH_UNIX, src, slen, &dest);
if (dlen == (size_t)-1)
return NULL;
else
return dest;
}
/**
Convert from unix to ucs2 charset and return the
allocated and converted string or NULL if an error occurred.
You must provide a zero terminated string.
The returning string will be zero terminated.
**/
smb_ucs2_t *acnv_uxu2(const char *src)
{
size_t slen;
size_t dlen;
void *dest;
slen = strlen(src) + 1;
dlen = convert_string_allocate(CH_UNIX, CH_UCS2, src, slen, &dest);
if (dlen == (size_t)-1)
return NULL;
else
return dest;
}
/**
Convert from ucs2 to dos charset and return the
allocated and converted string or NULL if an error occurred.
You must provide a zero terminated string.
The returning string will be zero terminated.
**/
char *acnv_u2dos(const smb_ucs2_t *src)
{
size_t slen;
size_t dlen;
void *dest;
slen = (strlen_w(src) + 1) * sizeof(smb_ucs2_t);
dlen = convert_string_allocate(CH_UCS2, CH_DOS, src, slen, &dest);
if (dlen == (size_t)-1)
return NULL;
else
return dest;
}
/**
Convert from dos to ucs2 charset and return the
allocated and converted string or NULL if an error occurred.
You must provide a zero terminated string.
The returning string will be zero terminated.
**/
smb_ucs2_t *acnv_dosu2(const char *src)
{
size_t slen;
size_t dlen;
void *dest;
slen = strlen(src) + 1;
dlen = convert_string_allocate(CH_DOS, CH_UCS2, src, slen, &dest);
if (dlen == (size_t)-1)
return NULL;
else
return dest;
}

View File

@@ -0,0 +1,327 @@
/*
Unix SMB/CIFS implementation.
Common popt routines
Copyright (C) Tim Potter 2001,2002
Copyright (C) Jelmer Vernooij 2002,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"
/* Handle command line options:
* -d,--debuglevel
* -s,--configfile
* -O,--socket-options
* -V,--version
* -l,--log-base
* -n,--netbios-name
* -W,--workgroup
* -i,--scope
*/
extern pstring user_socket_options;
extern BOOL AllowDebugChange;
struct user_auth_info cmdline_auth_info;
static void popt_common_callback(poptContext con,
enum poptCallbackReason reason,
const struct poptOption *opt,
const char *arg, const void *data)
{
pstring logfile;
const char *pname;
/* Find out basename of current program */
pname = strrchr_m(poptGetInvocationName(con),'/');
if (!pname)
pname = poptGetInvocationName(con);
else
pname++;
if (reason == POPT_CALLBACK_REASON_PRE) {
pstr_sprintf(logfile, "%s/log.%s", dyn_LOGFILEBASE, pname);
lp_set_cmdline("log file", logfile);
return;
}
switch(opt->val) {
case 'd':
lp_set_cmdline("log level", arg);
break;
case 'V':
printf( "Version %s\n", SAMBA_VERSION );
exit(0);
break;
case 's':
if (arg) {
pstrcpy(dyn_CONFIGFILE, arg);
}
break;
case 'l':
if (arg) {
pstr_sprintf(logfile, "%s/log.%s", arg, pname);
lp_set_cmdline("log file", logfile);
}
break;
case 'W':
lp_set_cmdline("workgroup", arg);
break;
case 'n':
lp_set_cmdline("netbios name", arg);
break;
case 'i':
lp_set_cmdline("netbios scope", arg);
break;
}
}
struct poptOption popt_common_connection[] = {
{ NULL, 0, POPT_ARG_CALLBACK, popt_common_callback },
{ "socket-options", 'O', POPT_ARG_STRING, NULL, 'O', "socket options to use",
"SOCKETOPTIONS" },
{ "netbiosname", 'n', POPT_ARG_STRING, NULL, 'n', "Primary netbios name", "NETBIOSNAME" },
{ "workgroup", 'W', POPT_ARG_STRING, NULL, 'W', "Set the workgroup name", "WORKGROUP" },
{ "scope", 'i', POPT_ARG_STRING, NULL, 'i', "Use this Netbios scope", "SCOPE" },
POPT_TABLEEND
};
struct poptOption popt_common_samba[] = {
{ NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE, popt_common_callback },
{ "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Set debug level", "DEBUGLEVEL" },
{ "configfile", 's', POPT_ARG_STRING, NULL, 's', "Use alternative configuration file", "CONFIGFILE" },
{ "log-basename", 'l', POPT_ARG_STRING, NULL, 'l', "Basename for log/debug files", "LOGFILEBASE" },
{ "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" },
POPT_TABLEEND
};
struct poptOption popt_common_version[] = {
{ NULL, 0, POPT_ARG_CALLBACK, popt_common_callback },
{ "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" },
POPT_TABLEEND
};
/****************************************************************************
* get a password from a a file or file descriptor
* exit on failure
* ****************************************************************************/
static void get_password_file(struct user_auth_info *a)
{
int fd = -1;
char *p;
BOOL close_it = False;
pstring spec;
char pass[128];
if ((p = getenv("PASSWD_FD")) != NULL) {
pstrcpy(spec, "descriptor ");
pstrcat(spec, p);
sscanf(p, "%d", &fd);
close_it = False;
} else if ((p = getenv("PASSWD_FILE")) != NULL) {
fd = sys_open(p, O_RDONLY, 0);
pstrcpy(spec, p);
if (fd < 0) {
fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
spec, strerror(errno));
exit(1);
}
close_it = True;
}
for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
p && p - pass < sizeof(pass);) {
switch (read(fd, p, 1)) {
case 1:
if (*p != '\n' && *p != '\0') {
*++p = '\0'; /* advance p, and null-terminate pass */
break;
}
case 0:
if (p - pass) {
*p = '\0'; /* null-terminate it, just in case... */
p = NULL; /* then force the loop condition to become false */
break;
} else {
fprintf(stderr, "Error reading password from file %s: %s\n",
spec, "empty password\n");
exit(1);
}
default:
fprintf(stderr, "Error reading password from file %s: %s\n",
spec, strerror(errno));
exit(1);
}
}
pstrcpy(a->password, pass);
if (close_it)
close(fd);
}
static void get_credentials_file(const char *file, struct user_auth_info *info)
{
XFILE *auth;
fstring buf;
uint16 len = 0;
char *ptr, *val, *param;
if ((auth=x_fopen(file, O_RDONLY, 0)) == NULL)
{
/* fail if we can't open the credentials file */
d_printf("ERROR: Unable to open credentials file!\n");
exit(-1);
}
while (!x_feof(auth))
{
/* get a line from the file */
if (!x_fgets(buf, sizeof(buf), auth))
continue;
len = strlen(buf);
if ((len) && (buf[len-1]=='\n'))
{
buf[len-1] = '\0';
len--;
}
if (len == 0)
continue;
/* break up the line into parameter & value.
* will need to eat a little whitespace possibly */
param = buf;
if (!(ptr = strchr_m (buf, '=')))
continue;
val = ptr+1;
*ptr = '\0';
/* eat leading white space */
while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
val++;
if (strwicmp("password", param) == 0)
{
pstrcpy(info->password, val);
info->got_pass = True;
}
else if (strwicmp("username", param) == 0)
pstrcpy(info->username, val);
//else if (strwicmp("domain", param) == 0)
// set_global_myworkgroup(val);
memset(buf, 0, sizeof(buf));
}
x_fclose(auth);
}
/* Handle command line options:
* -U,--user
* -A,--authentication-file
* -k,--use-kerberos
* -N,--no-pass
*/
static void popt_common_credentials_callback(poptContext con,
enum poptCallbackReason reason,
const struct poptOption *opt,
const char *arg, const void *data)
{
char *p;
if (reason == POPT_CALLBACK_REASON_PRE) {
cmdline_auth_info.use_kerberos = False;
cmdline_auth_info.got_pass = False;
pstrcpy(cmdline_auth_info.username, "GUEST");
if (getenv("LOGNAME"))pstrcpy(cmdline_auth_info.username,getenv("LOGNAME"));
if (getenv("USER")) {
pstrcpy(cmdline_auth_info.username,getenv("USER"));
if ((p = strchr_m(cmdline_auth_info.username,'%'))) {
*p = 0;
pstrcpy(cmdline_auth_info.password,p+1);
cmdline_auth_info.got_pass = True;
memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(cmdline_auth_info.password));
}
}
if (getenv("PASSWD")) {
pstrcpy(cmdline_auth_info.password,getenv("PASSWD"));
cmdline_auth_info.got_pass = True;
}
if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
get_password_file(&cmdline_auth_info);
cmdline_auth_info.got_pass = True;
}
return;
}
switch(opt->val) {
case 'U':
{
char *lp;
pstrcpy(cmdline_auth_info.username,arg);
if ((lp=strchr_m(cmdline_auth_info.username,'%'))) {
*lp = 0;
pstrcpy(cmdline_auth_info.password,lp+1);
cmdline_auth_info.got_pass = True;
memset(strchr_m(arg,'%')+1,'X',strlen(cmdline_auth_info.password));
}
}
break;
case 'A':
get_credentials_file(arg, &cmdline_auth_info);
break;
case 'k':
#ifndef HAVE_KRB5
d_printf("No kerberos support compiled in\n");
exit(1);
#else
cmdline_auth_info.use_kerberos = True;
cmdline_auth_info.got_pass = True;
#endif
break;
}
}
struct poptOption popt_common_credentials[] = {
{ NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE, popt_common_credentials_callback },
{ "user", 'U', POPT_ARG_STRING, NULL, 'U', "Set the network username", "USERNAME" },
{ "no-pass", 'N', POPT_ARG_NONE, &cmdline_auth_info.got_pass, True, "Don't ask for a password" },
{ "kerberos", 'k', POPT_ARG_NONE, &cmdline_auth_info.use_kerberos, True, "Use kerberos (active directory) authentication" },
{ "authentication-file", 'A', POPT_ARG_STRING, NULL, 'A', "Get the credentials from a file", "FILE" },
POPT_TABLEEND
};

View File

@@ -0,0 +1,159 @@
/*
Unix SMB/CIFS implementation.
Samba readline wrapper implementation
Copyright (C) Simo Sorce 2001
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.
*/
#include "includes.h"
#ifdef HAVE_LIBREADLINE
# ifdef HAVE_READLINE_READLINE_H
# include <readline/readline.h>
# ifdef HAVE_READLINE_HISTORY_H
# include <readline/history.h>
# endif
# else
# ifdef HAVE_READLINE_H
# include <readline.h>
# ifdef HAVE_HISTORY_H
# include <history.h>
# endif
# else
# undef HAVE_LIBREADLINE
# endif
# endif
#endif
#ifdef HAVE_NEW_LIBREADLINE
# define RL_COMPLETION_CAST (rl_completion_func_t *)
#else
/* This type is missing from libreadline<4.0 (approximately) */
# define RL_COMPLETION_CAST
#endif /* HAVE_NEW_LIBREADLINE */
/****************************************************************************
Display the prompt and wait for input. Call callback() regularly
****************************************************************************/
static char *smb_readline_replacement(const char *prompt, void (*callback)(void),
char **(completion_fn)(const char *text, int start, int end))
{
fd_set fds;
static pstring line;
struct timeval timeout;
int fd = x_fileno(x_stdin);
char *ret;
do_debug("%s", prompt);
while (1) {
timeout.tv_sec = 5;
timeout.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(fd,&fds);
if (sys_select_intr(fd+1,&fds,NULL,NULL,&timeout) == 1) {
ret = x_fgets(line, sizeof(line), x_stdin);
return ret;
}
if (callback)
callback();
}
}
/****************************************************************************
Display the prompt and wait for input. Call callback() regularly.
****************************************************************************/
char *smb_readline(const char *prompt, void (*callback)(void),
char **(completion_fn)(const char *text, int start, int end))
{
#if HAVE_LIBREADLINE
if (isatty(x_fileno(x_stdin))) {
char *ret;
/* Aargh! Readline does bizzare things with the terminal width
that mucks up expect(1). Set CLI_NO_READLINE in the environment
to force readline not to be used. */
if (getenv("CLI_NO_READLINE"))
return smb_readline_replacement(prompt, callback, completion_fn);
if (completion_fn) {
/* The callback prototype has changed slightly between
different versions of Readline, so the same function
works in all of them to date, but we get compiler
warnings in some. */
rl_attempted_completion_function = RL_COMPLETION_CAST completion_fn;
}
if (callback)
rl_event_hook = (Function *)callback;
ret = readline(prompt);
if (ret && *ret)
add_history(ret);
return ret;
} else
#endif
return smb_readline_replacement(prompt, callback, completion_fn);
}
/****************************************************************************
* return line buffer text
****************************************************************************/
const char *smb_readline_get_line_buffer(void)
{
#if defined(HAVE_LIBREADLINE)
return rl_line_buffer;
#else
return NULL;
#endif
}
/****************************************************************************
* set completion append character
***************************************************************************/
void smb_readline_ca_char(char c)
{
#if defined(HAVE_LIBREADLINE)
rl_completion_append_character = c;
#endif
}
/****************************************************************************
history
****************************************************************************/
int cmd_history(void)
{
#if defined(HAVE_LIBREADLINE)
HIST_ENTRY **hlist;
int i;
hlist = history_list();
for (i = 0; hlist && hlist[i]; i++) {
DEBUG(0, ("%d: %s\n", i, hlist[i]->line));
}
#else
DEBUG(0,("no history without readline support\n"));
#endif
return 0;
}

71
source/lib/crc32.c Normal file
View File

@@ -0,0 +1,71 @@
/*
Unix SMB/CIFS implementation.
crc32 implementation
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.
*/
#include "includes.h"
/* table generated using algorithm from Mark Adler */
static const uint32 crc_table[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
/*
see PNG specification or ISO-3309 for details
*/
uint32 crc32_buffer(const uint8 *buf, int n)
{
int i;
uint32 ret;
for (ret=~0, i=0;i<n; i++) {
ret = crc_table[0xff & (buf[i] ^ ret)] ^ (ret >> 8);
}
return ~ret;
}

71
source/lib/crypto/crc32.c Normal file
View File

@@ -0,0 +1,71 @@
/*
Unix SMB/CIFS implementation.
crc32 implementation
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.
*/
#include "includes.h"
/* table generated using algorithm from Mark Adler */
static const uint32 crc_table[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
/*
see PNG specification or ISO-3309 for details
*/
uint32 crc32_buffer(const uint8 *buf, int n)
{
int i;
uint32 ret;
for (ret=~0, i=0;i<n; i++) {
ret = crc_table[0xff & (buf[i] ^ ret)] ^ (ret >> 8);
}
return ~ret;
}

134
source/lib/crypto/hmacmd5.c Normal file
View File

@@ -0,0 +1,134 @@
/*
Unix SMB/CIFS implementation.
HMAC MD5 code for use in NTLMv2
Copyright (C) Luke Kenneth Casson Leighton 1996-2000
Copyright (C) Andrew Tridgell 1992-2000
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* taken direct from rfc2104 implementation and modified for suitable use
* for ntlmv2.
*/
#include "includes.h"
/***********************************************************************
the rfc 2104 version of hmac_md5 initialisation.
***********************************************************************/
void hmac_md5_init_rfc2104(uchar* key, int key_len, HMACMD5Context *ctx)
{
int i;
/* if key is longer than 64 bytes reset it to key=MD5(key) */
if (key_len > 64)
{
uchar tk[16];
struct MD5Context tctx;
MD5Init(&tctx);
MD5Update(&tctx, key, key_len);
MD5Final(tk, &tctx);
key = tk;
key_len = 16;
}
/* start out by storing key in pads */
ZERO_STRUCT(ctx->k_ipad);
ZERO_STRUCT(ctx->k_opad);
memcpy( ctx->k_ipad, key, key_len);
memcpy( ctx->k_opad, key, key_len);
/* XOR key with ipad and opad values */
for (i=0; i<64; i++)
{
ctx->k_ipad[i] ^= 0x36;
ctx->k_opad[i] ^= 0x5c;
}
MD5Init(&ctx->ctx);
MD5Update(&ctx->ctx, ctx->k_ipad, 64);
}
/***********************************************************************
the microsoft version of hmac_md5 initialisation.
***********************************************************************/
void hmac_md5_init_limK_to_64(const uchar* key, int key_len,
HMACMD5Context *ctx)
{
int i;
/* if key is longer than 64 bytes truncate it */
if (key_len > 64)
{
key_len = 64;
}
/* start out by storing key in pads */
ZERO_STRUCT(ctx->k_ipad);
ZERO_STRUCT(ctx->k_opad);
memcpy( ctx->k_ipad, key, key_len);
memcpy( ctx->k_opad, key, key_len);
/* XOR key with ipad and opad values */
for (i=0; i<64; i++) {
ctx->k_ipad[i] ^= 0x36;
ctx->k_opad[i] ^= 0x5c;
}
MD5Init(&ctx->ctx);
MD5Update(&ctx->ctx, ctx->k_ipad, 64);
}
/***********************************************************************
update hmac_md5 "inner" buffer
***********************************************************************/
void hmac_md5_update(const uchar* text, int text_len, HMACMD5Context *ctx)
{
MD5Update(&ctx->ctx, text, text_len); /* then text of datagram */
}
/***********************************************************************
finish off hmac_md5 "inner" buffer and generate outer one.
***********************************************************************/
void hmac_md5_final(uchar *digest, HMACMD5Context *ctx)
{
struct MD5Context ctx_o;
MD5Final(digest, &ctx->ctx);
MD5Init(&ctx_o);
MD5Update(&ctx_o, ctx->k_opad, 64);
MD5Update(&ctx_o, digest, 16);
MD5Final(digest, &ctx_o);
}
/***********************************************************
single function to calculate an HMAC MD5 digest from data.
use the microsoft hmacmd5 init method because the key is 16 bytes.
************************************************************/
void hmac_md5( uchar key[16], uchar* data, int data_len, uchar* digest)
{
HMACMD5Context ctx;
hmac_md5_init_limK_to_64(key, 16, &ctx);
if (data_len != 0)
{
hmac_md5_update(data, data_len, &ctx);
}
hmac_md5_final(digest, &ctx);
}

175
source/lib/crypto/md4.c Normal file
View File

@@ -0,0 +1,175 @@
/*
Unix SMB/CIFS implementation.
a implementation of MD4 designed for use in the SMB authentication protocol
Copyright (C) Andrew Tridgell 1997-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"
/* NOTE: This code makes no attempt to be fast!
It assumes that a int is at least 32 bits long
*/
struct mdfour_state {
uint32 A, B, C, D;
};
static uint32 F(uint32 X, uint32 Y, uint32 Z)
{
return (X&Y) | ((~X)&Z);
}
static uint32 G(uint32 X, uint32 Y, uint32 Z)
{
return (X&Y) | (X&Z) | (Y&Z);
}
static uint32 H(uint32 X, uint32 Y, uint32 Z)
{
return X^Y^Z;
}
static uint32 lshift(uint32 x, int s)
{
x &= 0xFFFFFFFF;
return ((x<<s)&0xFFFFFFFF) | (x>>(32-s));
}
#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + (uint32)0x5A827999,s)
#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + (uint32)0x6ED9EBA1,s)
/* this applies md4 to 64 byte chunks */
static void mdfour64(struct mdfour_state *s, uint32 *M)
{
int j;
uint32 AA, BB, CC, DD;
uint32 X[16];
for (j=0;j<16;j++)
X[j] = M[j];
AA = s->A; BB = s->B; CC = s->C; DD = s->D;
ROUND1(s->A,s->B,s->C,s->D, 0, 3); ROUND1(s->D,s->A,s->B,s->C, 1, 7);
ROUND1(s->C,s->D,s->A,s->B, 2, 11); ROUND1(s->B,s->C,s->D,s->A, 3, 19);
ROUND1(s->A,s->B,s->C,s->D, 4, 3); ROUND1(s->D,s->A,s->B,s->C, 5, 7);
ROUND1(s->C,s->D,s->A,s->B, 6, 11); ROUND1(s->B,s->C,s->D,s->A, 7, 19);
ROUND1(s->A,s->B,s->C,s->D, 8, 3); ROUND1(s->D,s->A,s->B,s->C, 9, 7);
ROUND1(s->C,s->D,s->A,s->B, 10, 11); ROUND1(s->B,s->C,s->D,s->A, 11, 19);
ROUND1(s->A,s->B,s->C,s->D, 12, 3); ROUND1(s->D,s->A,s->B,s->C, 13, 7);
ROUND1(s->C,s->D,s->A,s->B, 14, 11); ROUND1(s->B,s->C,s->D,s->A, 15, 19);
ROUND2(s->A,s->B,s->C,s->D, 0, 3); ROUND2(s->D,s->A,s->B,s->C, 4, 5);
ROUND2(s->C,s->D,s->A,s->B, 8, 9); ROUND2(s->B,s->C,s->D,s->A, 12, 13);
ROUND2(s->A,s->B,s->C,s->D, 1, 3); ROUND2(s->D,s->A,s->B,s->C, 5, 5);
ROUND2(s->C,s->D,s->A,s->B, 9, 9); ROUND2(s->B,s->C,s->D,s->A, 13, 13);
ROUND2(s->A,s->B,s->C,s->D, 2, 3); ROUND2(s->D,s->A,s->B,s->C, 6, 5);
ROUND2(s->C,s->D,s->A,s->B, 10, 9); ROUND2(s->B,s->C,s->D,s->A, 14, 13);
ROUND2(s->A,s->B,s->C,s->D, 3, 3); ROUND2(s->D,s->A,s->B,s->C, 7, 5);
ROUND2(s->C,s->D,s->A,s->B, 11, 9); ROUND2(s->B,s->C,s->D,s->A, 15, 13);
ROUND3(s->A,s->B,s->C,s->D, 0, 3); ROUND3(s->D,s->A,s->B,s->C, 8, 9);
ROUND3(s->C,s->D,s->A,s->B, 4, 11); ROUND3(s->B,s->C,s->D,s->A, 12, 15);
ROUND3(s->A,s->B,s->C,s->D, 2, 3); ROUND3(s->D,s->A,s->B,s->C, 10, 9);
ROUND3(s->C,s->D,s->A,s->B, 6, 11); ROUND3(s->B,s->C,s->D,s->A, 14, 15);
ROUND3(s->A,s->B,s->C,s->D, 1, 3); ROUND3(s->D,s->A,s->B,s->C, 9, 9);
ROUND3(s->C,s->D,s->A,s->B, 5, 11); ROUND3(s->B,s->C,s->D,s->A, 13, 15);
ROUND3(s->A,s->B,s->C,s->D, 3, 3); ROUND3(s->D,s->A,s->B,s->C, 11, 9);
ROUND3(s->C,s->D,s->A,s->B, 7, 11); ROUND3(s->B,s->C,s->D,s->A, 15, 15);
s->A += AA;
s->B += BB;
s->C += CC;
s->D += DD;
s->A &= 0xFFFFFFFF;
s->B &= 0xFFFFFFFF;
s->C &= 0xFFFFFFFF;
s->D &= 0xFFFFFFFF;
for (j=0;j<16;j++)
X[j] = 0;
}
static void copy64(uint32 *M, const unsigned char *in)
{
int i;
for (i=0;i<16;i++)
M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
(in[i*4+1]<<8) | (in[i*4+0]<<0);
}
static void copy4(unsigned char *out, uint32 x)
{
out[0] = x&0xFF;
out[1] = (x>>8)&0xFF;
out[2] = (x>>16)&0xFF;
out[3] = (x>>24)&0xFF;
}
/* produce a md4 message digest from data of length n bytes */
void mdfour(unsigned char *out, const unsigned char *in, int n)
{
unsigned char buf[128];
uint32 M[16];
uint32 b = n * 8;
int i;
struct mdfour_state state;
state.A = 0x67452301;
state.B = 0xefcdab89;
state.C = 0x98badcfe;
state.D = 0x10325476;
while (n > 64) {
copy64(M, in);
mdfour64(&state, M);
in += 64;
n -= 64;
}
for (i=0;i<128;i++)
buf[i] = 0;
memcpy(buf, in, n);
buf[n] = 0x80;
if (n <= 55) {
copy4(buf+56, b);
copy64(M, buf);
mdfour64(&state, M);
} else {
copy4(buf+120, b);
copy64(M, buf);
mdfour64(&state, M);
copy64(M, buf+64);
mdfour64(&state, M);
}
for (i=0;i<128;i++)
buf[i] = 0;
copy64(M, buf);
copy4(out, state.A);
copy4(out+4, state.B);
copy4(out+8, state.C);
copy4(out+12, state.D);
}

247
source/lib/crypto/md5.c Normal file
View File

@@ -0,0 +1,247 @@
/*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
/* This code slightly modified to fit into Samba by
abartlet@samba.org Jun 2001 */
#include "includes.h"
#include "md5.h"
static void MD5Transform(uint32 buf[4], uint32 const in[16]);
/*
* Note: this code is harmless on little-endian machines.
*/
static void byteReverse(unsigned char *buf, unsigned longs)
{
uint32 t;
do {
t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
*(uint32 *) buf = t;
buf += 4;
} while (--longs);
}
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
void MD5Init(struct MD5Context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
{
register uint32 t;
/* Update bitcount */
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if (t) {
unsigned char *p = (unsigned char *) ctx->in + t;
t = 64 - t;
if (len < t) {
memmove(p, buf, len);
return;
}
memmove(p, buf, t);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *) ctx->in);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64) {
memmove(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *) ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memmove(ctx->in, buf, len);
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
{
unsigned int count;
unsigned char *p;
/* Compute number of bytes mod 64 */
count = (ctx->bits[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *) ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
} else {
/* Pad block to 56 bytes */
memset(p, 0, count - 8);
}
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
((uint32 *) ctx->in)[14] = ctx->bits[0];
((uint32 *) ctx->in)[15] = ctx->bits[1];
MD5Transform(ctx->buf, (uint32 *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
memmove(digest, ctx->buf, 16);
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
}
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void MD5Transform(uint32 buf[4], uint32 const in[16])
{
register uint32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}

141
source/lib/data_blob.c Normal file
View File

@@ -0,0 +1,141 @@
/*
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"
/*******************************************************************
free() a data blob
*******************************************************************/
static void free_data_blob(DATA_BLOB *d)
{
if ((d) && (d->free)) {
SAFE_FREE(d->data);
}
}
/*******************************************************************
construct a data blob, must be freed with data_blob_free()
you can pass NULL for p and get a blank data blob
*******************************************************************/
DATA_BLOB data_blob(const void *p, size_t length)
{
DATA_BLOB ret;
if (!length) {
ZERO_STRUCT(ret);
return ret;
}
if (p) {
ret.data = smb_xmemdup(p, length);
} else {
ret.data = smb_xmalloc(length);
}
ret.length = length;
ret.free = free_data_blob;
return ret;
}
/*******************************************************************
construct a data blob, using supplied TALLOC_CTX
*******************************************************************/
DATA_BLOB data_blob_talloc(TALLOC_CTX *mem_ctx, const void *p, size_t length)
{
DATA_BLOB ret;
if (length == 0) {
ZERO_STRUCT(ret);
return ret;
}
if (p == NULL) {
ret.data = talloc(mem_ctx, length);
if (ret.data == NULL) {
smb_panic("data_blob_talloc: talloc_memdup failed.\n");
}
ret.length = length;
memset(ret.data, 0, ret.length);
return ret;
}
ret.data = talloc_memdup(mem_ctx, p, length);
if (ret.data == NULL) {
smb_panic("data_blob_talloc: talloc_memdup failed.\n");
}
ret.length = length;
ret.free = NULL;
return ret;
}
/*******************************************************************
free a data blob
*******************************************************************/
void data_blob_free(DATA_BLOB *d)
{
if (d) {
if (d->free) {
(d->free)(d);
}
d->length = 0;
}
}
/*******************************************************************
clear a DATA_BLOB's contents
*******************************************************************/
void data_blob_clear(DATA_BLOB *d)
{
if (d->data) {
memset(d->data, 0, d->length);
}
}
/*******************************************************************
free a data blob and clear its contents
*******************************************************************/
void data_blob_clear_free(DATA_BLOB *d)
{
data_blob_clear(d);
data_blob_free(d);
}
/*******************************************************************
check if two data blobs are equal
*******************************************************************/
BOOL data_blob_equal(DATA_BLOB *d1, 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;
}

157
source/lib/debug.c Normal file
View File

@@ -0,0 +1,157 @@
/*
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"
/* this global variable determines what messages are printed */
int DEBUGLEVEL;
/* the registered mutex handlers */
static struct {
const char *name;
struct debug_ops ops;
} debug_handlers;
/* state variables for the debug system */
static struct {
int fd;
enum debug_logtype logtype;
const char *prog_name;
} state;
/*
the backend for debug messages. Note that the DEBUG() macro has already
ensured that the log level has been met before this is called
*/
void do_debug(const char *format, ...)
{
va_list ap;
char *s = NULL;
if (state.fd == 0) {
reopen_logs();
}
if (state.fd <= 0) return;
va_start(ap, format);
vasprintf(&s, format, ap);
va_end(ap);
write(state.fd, s, strlen(s));
free(s);
}
/*
reopen the log file (usually called because the log file name might have changed)
*/
void reopen_logs(void)
{
char *logfile = lp_logfile();
char *fname = NULL;
int old_fd = state.fd;
state.fd = 0;
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, logfile);
}
if (fname) {
state.fd = open(fname, O_CREAT|O_APPEND|O_WRONLY, 0644);
free(fname);
}
break;
}
if (old_fd > 2) {
close(old_fd);
}
}
/*
control the name of the logfile and whether logging will be to stdout, stderr
or a file
*/
void setup_logging(const char *prog_name, enum debug_logtype new_logtype)
{
state.logtype = new_logtype;
state.prog_name = prog_name;
reopen_logs();
}
/*
return a string constant containing n tabs
no more than 10 tabs are returned
*/
const char *do_debug_tab(uint_t n)
{
const char *tabs[] = {"", "\t", "\t\t", "\t\t\t", "\t\t\t\t", "\t\t\t\t\t",
"\t\t\t\t\t\t", "\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t",
"\t\t\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t\t\t"};
return tabs[MIN(n, 10)];
}
/*
log/print suspicious usage - print comments and backtrace
*/
void log_suspicious_usage(const char *from, const char *info)
{
if (debug_handlers.ops.log_suspicious_usage) {
return debug_handlers.ops.log_suspicious_usage(from, info);
}
}
void print_suspicious_usage(const char* from, const char* info)
{
if (debug_handlers.ops.print_suspicious_usage) {
return debug_handlers.ops.print_suspicious_usage(from, info);
}
}
uint32 get_task_id(void)
{
if (debug_handlers.ops.get_task_id) {
return debug_handlers.ops.get_task_id();
}
return getpid();
}
/*
register a set of debug handlers.
*/
void register_debug_handlers(const char *name, struct debug_ops *ops)
{
debug_handlers.name = name;
debug_handlers.ops = *ops;
}

72
source/lib/dmallocmsg.c Normal file
View File

@@ -0,0 +1,72 @@
/*
samba -- Unix SMB/CIFS implementation.
Copyright (C) 2002 by Martin Pool
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 dmallocmsg.c
*
* Glue code to cause dmalloc info to come out when we receive a prod
* over samba messaging.
**/
#ifdef ENABLE_DMALLOC
static unsigned long our_dm_mark = 0;
#endif /* ENABLE_DMALLOC */
/**
* Respond to a POOL_USAGE message by sending back string form of memory
* usage stats.
**/
static void msg_req_dmalloc_mark(int UNUSED(msg_type), pid_t UNUSED(src_pid),
void *UNUSED(buf), size_t UNUSED(len))
{
#ifdef ENABLE_DMALLOC
our_dm_mark = dmalloc_mark();
DEBUG(2,("Got MSG_REQ_DMALLOC_MARK: mark set\n"));
#else
DEBUG(2,("Got MSG_REQ_DMALLOC_MARK but dmalloc not in this process\n"));
#endif
}
static void msg_req_dmalloc_log_changed(int UNUSED(msg_type),
pid_t UNUSED(src_pid),
void *UNUSED(buf), size_t UNUSED(len))
{
#ifdef ENABLE_DMALLOC
dmalloc_log_changed(our_dm_mark, True, True, True);
DEBUG(2,("Got MSG_REQ_DMALLOC_LOG_CHANGED: done\n"));
#else
DEBUG(2,("Got MSG_REQ_DMALLOC_LOG_CHANGED but dmalloc not in this process\n"));
#endif
}
/**
* Register handler for MSG_REQ_POOL_USAGE
**/
void register_dmalloc_msgs(void)
{
message_register(MSG_REQ_DMALLOC_MARK, msg_req_dmalloc_mark);
message_register(MSG_REQ_DMALLOC_LOG_CHANGED, msg_req_dmalloc_log_changed);
DEBUG(2, ("Registered MSG_REQ_DMALLOC_MARK and LOG_CHANGED\n"));
}

113
source/lib/dprintf.c Normal file
View File

@@ -0,0 +1,113 @@
/*
Unix SMB/CIFS implementation.
display print functions
Copyright (C) Andrew Tridgell 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
this module provides functions for printing internal strings in the "display charset"
This charset may be quite different from the chosen unix charset
Eventually these functions will need to take care of column count constraints
The d_ prefix on print functions in Samba refers to the display character set
conversion
*/
#include "includes.h"
int d_vfprintf(FILE *f, const char *format, va_list ap)
{
char *p, *p2;
int ret, maxlen, clen;
const char *msgstr;
va_list ap2;
/* do any message translations */
msgstr = lang_msg(format);
if (!msgstr) return -1;
VA_COPY(ap2, ap);
ret = vasprintf(&p, msgstr, ap2);
lang_msg_free(msgstr);
if (ret <= 0) return ret;
/* now we have the string in unix format, convert it to the display
charset, but beware of it growing */
maxlen = ret*2;
again:
p2 = malloc(maxlen);
if (!p2) {
SAFE_FREE(p);
return -1;
}
clen = convert_string(CH_UNIX, CH_DISPLAY, p, ret, p2, maxlen);
if (clen >= maxlen) {
/* it didn't fit - try a larger buffer */
maxlen *= 2;
SAFE_FREE(p2);
goto again;
}
/* good, its converted OK */
SAFE_FREE(p);
ret = fwrite(p2, 1, clen, f);
SAFE_FREE(p2);
return ret;
}
int d_fprintf(FILE *f, const char *format, ...)
{
int ret;
va_list ap;
va_start(ap, format);
ret = d_vfprintf(f, format, ap);
va_end(ap);
return ret;
}
static FILE *outfile;
int d_printf(const char *format, ...)
{
int ret;
va_list ap;
if (!outfile) outfile = stdout;
va_start(ap, format);
ret = d_vfprintf(outfile, format, ap);
va_end(ap);
return ret;
}
/* interactive programs need a way of tell d_*() to write to stderr instead
of stdout */
void display_set_stderr(void)
{
outfile = stderr;
}

372
source/lib/events.c Normal file
View File

@@ -0,0 +1,372 @@
/*
Unix SMB/CIFS implementation.
main select loop and event handling
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.
*/
/*
PLEASE READ THIS BEFORE MODIFYING!
This module is a general abstraction for the main select loop and
event handling. Do not ever put any localised hacks in here, instead
register one of the possible event types and implement that event
somewhere else.
There are 4 types of event handling that are handled in this module:
1) a file descriptor becoming readable or writeable. This is mostly
used for network sockets, but can be used for any type of file
descriptor. You may only register one handler for each file
descriptor/io combination or you will get unpredictable results
(this means that you can have a handler for read events, and a
separate handler for write events, but not two handlers that are
both handling read events)
2) a timed event. You can register an event that happens at a
specific time. You can register as many of these as you
like. When they are called the handler can choose to set the time
for the next event. If next_event is not set then the event is removed.
3) an event that happens every time through the select loop. These
sorts of events should be very fast, as they will occur a
lot. Mostly used for things like destroying a talloc context or
checking a signal flag.
4) an event triggered by a signal. These can be one shot or
repeated. You can have more than one handler registered for a
single signal if you want to.
To setup a set of events you first need to create a event_context
structure using the function event_context_init(); This returns a
'struct event_context' that you use in all subsequent calls.
After that you can add/remove events that you are interested in
using event_add_*() and event_remove_*().
Finally, you call event_loop_wait() to block waiting for one of the
events to occor. In normal operation event_loop_wait() will loop
forever, unless you call event_loop_exit() from inside one of your
handler functions.
*/
#include "includes.h"
/*
create a event_context structure. This must be the first events
call, and all subsequent calls pass this event_context as the first
element. Event handlers also receive this as their first argument.
*/
struct event_context *event_context_init(void)
{
struct event_context *ev;
ev = malloc(sizeof(*ev));
if (!ev) return NULL;
/* start off with no events */
ZERO_STRUCTP(ev);
return ev;
}
/*
add a fd based event
return False on failure (memory allocation error)
*/
BOOL event_add_fd(struct event_context *ev, struct fd_event *e)
{
e = memdup(e, sizeof(*e));
if (!e) return False;
DLIST_ADD(ev->fd_events, e);
e->ref_count = 1;
if (e->fd > ev->maxfd) {
ev->maxfd = e->fd;
}
return True;
}
/*
recalculate the maxfd
*/
static void calc_maxfd(struct event_context *ev)
{
struct fd_event *e;
ev->maxfd = 0;
for (e=ev->fd_events; e; e=e->next) {
if (e->ref_count &&
e->fd > ev->maxfd) {
ev->maxfd = e->fd;
}
}
}
/*
remove a fd based event
the event to remove is matched by looking at the handler
function and the file descriptor
return False on failure (event not found)
*/
BOOL event_remove_fd(struct event_context *ev, struct fd_event *e1)
{
struct fd_event *e;
for (e=ev->fd_events; e; e=e->next) {
if (e->ref_count &&
e->fd == e1->fd &&
e->handler == e1->handler) {
e->ref_count--;
/* possibly calculate the new maxfd */
calc_maxfd(ev);
return True;
}
}
return False;
}
/*
remove all fd based events that match a specified fd
*/
void event_remove_fd_all(struct event_context *ev, int fd)
{
struct fd_event *e;
for (e=ev->fd_events; e; e=e->next) {
if (e->ref_count && e->fd == fd) {
e->ref_count--;
}
}
calc_maxfd(ev);
}
/*
remove all fd based events that match a specified handler
*/
void event_remove_fd_all_handler(struct event_context *ev, void *handler)
{
struct fd_event *e;
for (e=ev->fd_events; e; e=e->next) {
if (e->ref_count &&
handler == (void *)e->handler) {
e->ref_count--;
}
}
calc_maxfd(ev);
}
/*
add a timed event
return False on failure (memory allocation error)
*/
BOOL event_add_timed(struct event_context *ev, struct timed_event *e)
{
e = memdup(e, sizeof(*e));
if (!e) return False;
e->ref_count = 1;
DLIST_ADD(ev->timed_events, e);
return True;
}
/*
remove a timed event
the event to remove is matched only on the handler function
return False on failure (event not found)
*/
BOOL event_remove_timed(struct event_context *ev, struct timed_event *e1)
{
struct timed_event *e;
for (e=ev->timed_events; e; e=e->next) {
if (e->ref_count &&
e->handler == e1->handler) {
e->ref_count--;
return True;
}
}
return False;
}
/*
add a loop event
return False on failure (memory allocation error)
*/
BOOL event_add_loop(struct event_context *ev, struct loop_event *e)
{
e = memdup(e, sizeof(*e));
if (!e) return False;
e->ref_count = 1;
DLIST_ADD(ev->loop_events, e);
return True;
}
/*
remove a loop event
the event to remove is matched only on the handler function
return False on failure (memory allocation error)
*/
BOOL event_remove_loop(struct event_context *ev, struct loop_event *e1)
{
struct loop_event *e;
for (e=ev->loop_events; e; e=e->next) {
if (e->ref_count &&
e->handler == e1->handler) {
e->ref_count--;
return True;
}
}
return False;
}
/*
tell the event loop to exit with the specified code
*/
void event_loop_exit(struct event_context *ev, int code)
{
ev->exit.exit_now = True;
ev->exit.code = code;
}
/*
go into an event loop using the events defined in ev this function
will return with the specified code if one of the handlers calls
event_loop_exit()
also return (with code 0) if all fd events are removed
*/
int event_loop_wait(struct event_context *ev)
{
time_t t;
ZERO_STRUCT(ev->exit);
t = time(NULL);
while (ev->fd_events && !ev->exit.exit_now) {
fd_set r_fds, w_fds;
struct fd_event *fe;
struct loop_event *le;
struct timed_event *te;
int selrtn;
struct timeval tval;
/* the loop events are called on each loop. Be careful to allow the
event to remove itself */
for (le=ev->loop_events;le;) {
struct loop_event *next = le->next;
if (le->ref_count == 0) {
DLIST_REMOVE(ev->loop_events, le);
free(le);
} else {
le->ref_count++;
le->handler(ev, le, t);
le->ref_count--;
}
le = next;
}
ZERO_STRUCT(tval);
FD_ZERO(&r_fds);
FD_ZERO(&w_fds);
/* setup any fd events */
for (fe=ev->fd_events; fe; ) {
struct fd_event *next = fe->next;
if (fe->ref_count == 0) {
DLIST_REMOVE(ev->fd_events, fe);
free(fe);
} else {
if (fe->flags & EVENT_FD_READ) {
FD_SET(fe->fd, &r_fds);
}
if (fe->flags & EVENT_FD_WRITE) {
FD_SET(fe->fd, &w_fds);
}
}
fe = next;
}
/* start with a reasonable max timeout */
tval.tv_sec = 600;
/* work out the right timeout for all timed events */
for (te=ev->timed_events;te;te=te->next) {
int timeout = te->next_event - t;
if (timeout < 0) {
timeout = 0;
}
if (te->ref_count &&
timeout < tval.tv_sec) {
tval.tv_sec = timeout;
}
}
selrtn = sys_select(ev->maxfd+1, &r_fds, &w_fds, NULL, &tval);
t = time(NULL);
if (selrtn == -1 && errno == EBADF) {
/* the socket is dead! this should never
happen as the socket should have first been
made readable and that should have removed
the event, so this must be a bug. This is a
fatal error. */
DEBUG(0,("EBADF on event_loop_wait - exiting\n"));
return -1;
}
if (selrtn > 0) {
/* at least one file descriptor is ready - check
which ones and call the handler, being careful to allow
the handler to remove itself when called */
for (fe=ev->fd_events; fe; fe=fe->next) {
uint16 flags = 0;
if (FD_ISSET(fe->fd, &r_fds)) flags |= EVENT_FD_READ;
if (FD_ISSET(fe->fd, &w_fds)) flags |= EVENT_FD_WRITE;
if (fe->ref_count && flags) {
fe->ref_count++;
fe->handler(ev, fe, t, flags);
fe->ref_count--;
}
}
}
/* call any timed events that are now due */
for (te=ev->timed_events;te;) {
struct timed_event *next = te->next;
if (te->ref_count == 0) {
DLIST_REMOVE(ev->timed_events, te);
free(te);
} else if (te->next_event <= t) {
te->ref_count++;
te->handler(ev, te, t);
te->ref_count--;
if (te->next_event <= t) {
/* the handler didn't set a time for the
next event - remove the event */
event_remove_timed(ev, te);
}
}
te = next;
}
}
return ev->exit.code;
}

107
source/lib/fault.c Normal file
View File

@@ -0,0 +1,107 @@
/*
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"
static void (*cont_fn)(void *);
/* the registered fault handler */
static struct {
const char *name;
void (*fault_handler)(int sig);
} fault_handlers;
/*******************************************************************
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));
DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n"));
DEBUG(0,("===============================================================\n"));
smb_panic("internal error");
if (cont_fn) {
cont_fn(NULL);
#ifdef SIGSEGV
CatchSignal(SIGSEGV,SIGNAL_CAST SIG_DFL);
#endif
#ifdef SIGBUS
CatchSignal(SIGBUS,SIGNAL_CAST SIG_DFL);
#endif
return; /* this should cause a core dump */
}
exit(1);
}
/****************************************************************************
catch serious errors
****************************************************************************/
static void sig_fault(int sig)
{
if (fault_handlers.fault_handler) {
/* we have a fault handler, call it. It may not return. */
fault_handlers.fault_handler(sig);
}
/* If it returns or doean't exist, use regular reporter */
fault_report(sig);
}
/*******************************************************************
setup our fault handlers
********************************************************************/
void fault_setup(void (*fn)(void *))
{
cont_fn = fn;
#ifdef SIGSEGV
CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault);
#endif
#ifdef SIGBUS
CatchSignal(SIGBUS,SIGNAL_CAST sig_fault);
#endif
}
/*
register a fault handler.
Should only be called once in the execution of smbd.
*/
BOOL register_fault_handler(const char *name, void (*fault_handler)(int sig))
{
if (fault_handlers.name != NULL) {
/* it's already registered! */
DEBUG(2,("fault handler '%s' already registered - failed '%s'\n",
fault_handlers.name, name));
return False;
}
fault_handlers.name = name;
fault_handlers.fault_handler = fault_handler;
DEBUG(2,("fault handler '%s' registered\n", name));
return True;
}

148
source/lib/fsusage.c Normal file
View File

@@ -0,0 +1,148 @@
/*
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"
/* Return the number of TOSIZE-byte blocks used by
BLOCKS FROMSIZE-byte blocks, rounding away from zero.
*/
static SMB_BIG_UINT adjust_blocks(SMB_BIG_UINT blocks, SMB_BIG_UINT fromsize, SMB_BIG_UINT tosize)
{
if (fromsize == tosize) /* e.g., from 512 to 512 */
return blocks;
else if (fromsize > tosize) /* e.g., from 2048 to 512 */
return blocks * (fromsize / tosize);
else /* e.g., from 256 to 512 */
return (blocks + 1) / (tosize / fromsize);
}
/* this does all of the system specific guff to get the free disk space.
It is derived from code in the GNU fileutils package, but has been
considerably mangled for use here
results are returned in *dfree and *dsize, in 512 byte units
*/
int sys_fsusage(const char *path, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
#ifdef STAT_STATFS3_OSF1
#define CONVERT_BLOCKS(B) adjust_blocks ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_fsize, (SMB_BIG_UINT)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 ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)1024, (SMB_BIG_UINT)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 ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_bsize, (SMB_BIG_UINT)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 ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_fsize, (SMB_BIG_UINT)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 ((SMB_BIG_UINT)(B), (SMB_BIG_UINT)fsd.f_bsize, (SMB_BIG_UINT)512)
# ifdef _CRAY
# define f_bavail f_bfree
# endif
# else
# define CONVERT_BLOCKS(B) ((SMB_BIG_UINT)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 ((SMB_BIG_UINT)(B), fsd.f_frsize ? (SMB_BIG_UINT)fsd.f_frsize : (SMB_BIG_UINT)fsd.f_bsize, (SMB_BIG_UINT)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;
}

372
source/lib/gencache.c Normal file
View File

@@ -0,0 +1,372 @@
/*
Unix SMB/CIFS implementation.
Generic, persistent and shared between processes cache mechanism for use
by various parts of the Samba code
Copyright (C) Rafal Szczesniak 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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_TDB
#define TIMEOUT_LEN 12
#define CACHE_DATA_FMT "%12u/%s"
static TDB_CONTEXT *cache;
/**
* @file gencache.c
* @brief Generic, persistent and shared between processes cache mechanism
* for use by various parts of the Samba code
*
**/
/**
* Cache initialisation function. Opens cache tdb file or creates
* it if does not exist.
*
* @return true on successful initialisation of the cache or
* false on failure
**/
BOOL gencache_init(void)
{
char* cache_fname = NULL;
/* skip file open if it's already opened */
if (cache) return True;
asprintf(&cache_fname, "%s/%s", lp_lockdir(), "gencache.tdb");
if (cache_fname)
DEBUG(5, ("Opening cache file at %s\n", cache_fname));
else {
DEBUG(0, ("Filename allocation failed.\n"));
return False;
}
cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT,
O_RDWR|O_CREAT, 0644);
SAFE_FREE(cache_fname);
if (!cache) {
DEBUG(5, ("Attempt to open gencache.tdb has failed.\n"));
return False;
}
return True;
}
/**
* Cache shutdown function. Closes opened cache tdb file.
*
* @return true on successful closing the cache or
* false on failure during cache shutdown
**/
BOOL gencache_shutdown(void)
{
/* tdb_close routine returns -1 on error */
if (!cache) return False;
DEBUG(5, ("Closing cache file\n"));
return tdb_close(cache) != -1;
}
/**
* Set an entry in the cache file. If there's no such
* one, then add it.
*
* @param keystr string that represents a key of this entry
* @param value text representation value being cached
* @param timeout time when the value is expired
*
* @retval true when entry is successfuly stored
* @retval false on failure
**/
BOOL gencache_set(const char *keystr, const char *value, time_t timeout)
{
int ret;
TDB_DATA keybuf, databuf;
char* valstr = NULL;
/* fail completely if get null pointers passed */
SMB_ASSERT(keystr && value);
if (!gencache_init()) return False;
asprintf(&valstr, CACHE_DATA_FMT, (int)timeout, value);
if (!valstr)
return False;
keybuf.dptr = strdup(keystr);
keybuf.dsize = strlen(keystr)+1;
databuf.dptr = strdup(valstr);
databuf.dsize = strlen(valstr)+1;
DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout \
= %s (%d seconds %s)\n", keybuf.dptr, value, ctime(&timeout),
(int)(timeout - time(NULL)), timeout > time(NULL) ? "ahead" : "in the past"));
ret = tdb_store(cache, keybuf, databuf, 0);
SAFE_FREE(valstr);
SAFE_FREE(keybuf.dptr);
SAFE_FREE(databuf.dptr);
return ret == 0;
}
/**
* Set existing entry to the cache file.
*
* @param keystr string that represents a key of this entry
* @param valstr text representation value being cached
* @param timeout time when the value is expired
*
* @retval true when entry is successfuly set
* @retval false on failure
**/
BOOL gencache_set_only(const char *keystr, const char *valstr, time_t timeout)
{
int ret = -1;
TDB_DATA keybuf, databuf;
char *old_valstr, *datastr;
time_t old_timeout;
/* fail completely if get null pointers passed */
SMB_ASSERT(keystr && valstr);
if (!gencache_init()) return False;
/*
* Check whether entry exists in the cache
* Don't verify gencache_get exit code, since the entry may be expired
*/
gencache_get(keystr, &old_valstr, &old_timeout);
if (!(old_valstr && old_timeout)) return False;
DEBUG(10, ("Setting cache entry with key = %s; old value = %s and old timeout \
= %s\n", keystr, old_valstr, ctime(&old_timeout)));
asprintf(&datastr, CACHE_DATA_FMT, (int)timeout, valstr);
keybuf.dptr = strdup(keystr);
keybuf.dsize = strlen(keystr)+1;
databuf.dptr = strdup(datastr);
databuf.dsize = strlen(datastr)+1;
DEBUGADD(10, ("New value = %s, new timeout = %s (%d seconds %s)", valstr,
ctime(&timeout), (int)(timeout - time(NULL)),
timeout > time(NULL) ? "ahead" : "in the past"));
ret = tdb_store(cache, keybuf, databuf, TDB_REPLACE);
SAFE_FREE(datastr);
SAFE_FREE(old_valstr);
SAFE_FREE(keybuf.dptr);
SAFE_FREE(databuf.dptr);
return ret == 0;
}
/**
* Delete one entry from the cache file.
*
* @param keystr string that represents a key of this entry
*
* @retval true upon successful deletion
* @retval false in case of failure
**/
BOOL gencache_del(const char *keystr)
{
int ret;
TDB_DATA keybuf;
/* fail completely if get null pointers passed */
SMB_ASSERT(keystr);
if (!gencache_init()) return False;
keybuf.dptr = strdup(keystr);
keybuf.dsize = strlen(keystr)+1;
DEBUG(10, ("Deleting cache entry (key = %s)\n", keystr));
ret = tdb_delete(cache, keybuf);
SAFE_FREE(keybuf.dptr);
return ret == 0;
}
/**
* Get existing entry from the cache file.
*
* @param keystr string that represents a key of this entry
* @param valstr buffer that is allocated and filled with the entry value
* buffer's disposing must be done outside
* @param timeout pointer to a time_t that is filled with entry's
* timeout
*
* @retval true when entry is successfuly fetched
* @retval False for failure
**/
BOOL gencache_get(const char *keystr, char **valstr, time_t *timeout)
{
TDB_DATA keybuf, databuf;
/* fail completely if get null pointers passed */
SMB_ASSERT(keystr);
if (!gencache_init())
return False;
keybuf.dptr = strdup(keystr);
keybuf.dsize = strlen(keystr)+1;
databuf = tdb_fetch(cache, keybuf);
SAFE_FREE(keybuf.dptr);
if (databuf.dptr && databuf.dsize > TIMEOUT_LEN) {
char* entry_buf = strndup(databuf.dptr, databuf.dsize);
char *v;
time_t t;
v = (char*)malloc(sizeof(char) *
(databuf.dsize - TIMEOUT_LEN));
SAFE_FREE(databuf.dptr);
sscanf(entry_buf, CACHE_DATA_FMT, (int*)&t, v);
SAFE_FREE(entry_buf);
DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, "
"timeout = %s\n", t > time(NULL) ? "valid" :
"expired", keystr, v, ctime(&t)));
if (valstr)
*valstr = v;
else
SAFE_FREE(v);
if (timeout)
*timeout = t;
return t > time(NULL);
} else {
SAFE_FREE(databuf.dptr);
if (valstr)
*valstr = NULL;
if (timeout)
timeout = NULL;
DEBUG(10, ("Cache entry with key = %s couldn't be found\n",
keystr));
return False;
}
}
/**
* Iterate through all entries which key matches to specified pattern
*
* @param fn pointer to the function that will be supplied with each single
* matching cache entry (key, value and timeout) as an arguments
* @param data void pointer to an arbitrary data that is passed directly to the fn
* function on each call
* @param keystr_pattern pattern the existing entries' keys are matched to
*
**/
void gencache_iterate(void (*fn)(const char* key, const char *value, time_t timeout, void* dptr),
void* data, const char* keystr_pattern)
{
TDB_LIST_NODE *node, *first_node;
TDB_DATA databuf;
char *keystr = NULL, *valstr = NULL, *entry = NULL;
time_t timeout = 0;
/* fail completely if get null pointers passed */
SMB_ASSERT(fn && keystr_pattern);
if (!gencache_init()) return;
DEBUG(5, ("Searching cache keys with pattern %s\n", keystr_pattern));
node = tdb_search_keys(cache, keystr_pattern);
first_node = node;
while (node) {
/* ensure null termination of the key string */
keystr = strndup(node->node_key.dptr, node->node_key.dsize);
/*
* We don't use gencache_get function, because we need to iterate through
* all of the entries. Validity verification is up to fn routine.
*/
databuf = tdb_fetch(cache, node->node_key);
if (!databuf.dptr || databuf.dsize <= TIMEOUT_LEN) {
SAFE_FREE(databuf.dptr);
SAFE_FREE(keystr);
node = node->next;
continue;
}
entry = strndup(databuf.dptr, databuf.dsize);
SAFE_FREE(databuf.dptr);
valstr = (char*)malloc(sizeof(char) * (databuf.dsize - TIMEOUT_LEN));
sscanf(entry, CACHE_DATA_FMT, (int*)(&timeout), valstr);
DEBUG(10, ("Calling function with arguments (key = %s, value = %s, timeout = %s)\n",
keystr, valstr, ctime(&timeout)));
fn(keystr, valstr, timeout, data);
SAFE_FREE(valstr);
SAFE_FREE(entry);
SAFE_FREE(keystr);
node = node->next;
}
tdb_search_list_free(first_node);
}
/********************************************************************
lock a key
********************************************************************/
int gencache_lock_entry( const char *key )
{
return tdb_lock_bystring(cache, key, 0);
}
/********************************************************************
unlock a key
********************************************************************/
void gencache_unlock_entry( const char *key )
{
tdb_unlock_bystring(cache, key);
return;
}

786
source/lib/genparser.c Normal file
View File

@@ -0,0 +1,786 @@
/*
Copyright (C) Andrew Tridgell <genstruct@tridgell.net> 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.
*/
/*
automatic marshalling/unmarshalling system for C structures
*/
#include "includes.h"
/* see if a range of memory is all zero. Used to prevent dumping of zero elements */
static int all_zero(const char *ptr, unsigned size)
{
int i;
if (!ptr) return 1;
for (i=0;i<size;i++) {
if (ptr[i]) return 0;
}
return 1;
}
/* encode a buffer of bytes into a escaped string */
static char *encode_bytes(TALLOC_CTX *mem_ctx, const char *ptr, unsigned len)
{
const char *hexdig = "0123456789abcdef";
char *ret, *p;
unsigned i;
ret = talloc(mem_ctx, len*3 + 1); /* worst case size */
if (!ret) return NULL;
for (p=ret,i=0;i<len;i++) {
if (isalnum(ptr[i]) || isspace(ptr[i]) ||
(ispunct(ptr[i]) && !strchr("\\{}", ptr[i]))) {
*p++ = ptr[i];
} else {
unsigned char c = *(const unsigned char *)(ptr+i);
if (c == 0 && all_zero(ptr+i, len-i)) break;
p[0] = '\\';
p[1] = hexdig[c>>4];
p[2] = hexdig[c&0xF];
p += 3;
}
}
*p = 0;
return ret;
}
/* decode an escaped string from encode_bytes() into a buffer */
static char *decode_bytes(TALLOC_CTX *mem_ctx, const char *s, unsigned *len)
{
char *ret, *p;
unsigned i;
int slen = strlen(s) + 1;
ret = talloc(mem_ctx, slen); /* worst case length */
if (!ret)
return NULL;
memset(ret, 0, slen);
if (*s == '{') s++;
for (p=ret,i=0;s[i];i++) {
if (s[i] == '}') {
break;
} else if (s[i] == '\\') {
unsigned v;
if (sscanf(&s[i+1], "%02x", &v) != 1 || v > 255) {
return NULL;
}
*(unsigned char *)p = v;
p++;
i += 2;
} else {
*p++ = s[i];
}
}
*p = 0;
(*len) = (unsigned)(p - ret);
return ret;
}
/* the add*() functions deal with adding things to a struct
parse_string */
/* allocate more space if needed */
static int addgen_alloc(TALLOC_CTX *mem_ctx, struct parse_string *p, int n)
{
if (p->length + n <= p->allocated) return 0;
p->allocated = p->length + n + 200;
p->s = talloc_realloc(mem_ctx, p->s, p->allocated);
if (!p->s) {
errno = ENOMEM;
return -1;
}
return 0;
}
/* add a character to the buffer */
static int addchar(TALLOC_CTX *mem_ctx, struct parse_string *p, char c)
{
if (addgen_alloc(mem_ctx, p, 2) != 0) {
return -1;
}
p->s[p->length++] = c;
p->s[p->length] = 0;
return 0;
}
/* add a string to the buffer */
int addstr(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *s)
{
int len = strlen(s);
if (addgen_alloc(mem_ctx, p, len+1) != 0) {
return -1;
}
memcpy(p->s + p->length, s, len+1);
p->length += len;
return 0;
}
/* add a string to the buffer with a tab prefix */
static int addtabbed(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *s, unsigned indent)
{
int len = strlen(s);
if (addgen_alloc(mem_ctx, p, indent+len+1) != 0) {
return -1;
}
while (indent--) {
p->s[p->length++] = '\t';
}
memcpy(p->s + p->length, s, len+1);
p->length += len;
return 0;
}
/* note! this can only be used for results up to 60 chars wide! */
int addshort(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *fmt, ...)
{
char buf[60];
int n;
va_list ap;
va_start(ap, fmt);
n = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (addgen_alloc(mem_ctx, p, n + 1) != 0) {
return -1;
}
if (n != 0) {
memcpy(p->s + p->length, buf, n);
}
p->length += n;
p->s[p->length] = 0;
return 0;
}
/*
this is here to make it easier for people to write dump functions
for their own types
*/
int gen_addgen(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *fmt, ...)
{
char *buf = NULL;
int n;
va_list ap;
va_start(ap, fmt);
n = vasprintf(&buf, fmt, ap);
va_end(ap);
if (addgen_alloc(mem_ctx, p, n + 1) != 0) {
if (buf) free(buf);
return -1;
}
if (n != 0) {
memcpy(p->s + p->length, buf, n);
}
p->length += n;
p->s[p->length] = 0;
if (buf) free(buf);
return 0;
}
/* dump a enumerated type */
int gen_dump_enum(TALLOC_CTX *mem_ctx,
const struct enum_struct *einfo,
struct parse_string *p,
const char *ptr,
unsigned indent)
{
unsigned v = *(const unsigned *)ptr;
int i;
for (i=0;einfo[i].name;i++) {
if (v == einfo[i].value) {
addstr(mem_ctx, p, einfo[i].name);
return 0;
}
}
/* hmm, maybe we should just fail? */
return gen_dump_unsigned(mem_ctx, p, ptr, indent);
}
/* dump a single non-array element, hanlding struct and enum */
static int gen_dump_one(TALLOC_CTX *mem_ctx,
struct parse_string *p,
const struct parse_struct *pinfo,
const char *ptr,
unsigned indent)
{
if (pinfo->dump_fn == gen_dump_char && pinfo->ptr_count == 1) {
char *s = encode_bytes(mem_ctx, ptr, strlen(ptr));
if (addchar(mem_ctx, p,'{') ||
addstr(mem_ctx, p, s) ||
addstr(mem_ctx, p, "}")) {
return -1;
}
return 0;
}
return pinfo->dump_fn(mem_ctx, p, ptr, indent);
}
/* handle dumping of an array of arbitrary type */
static int gen_dump_array(TALLOC_CTX *mem_ctx,
struct parse_string *p,
const struct parse_struct *pinfo,
const char *ptr,
int array_len,
int indent)
{
int i, count=0;
/* special handling of fixed length strings */
if (array_len != 0 &&
pinfo->ptr_count == 0 &&
pinfo->dump_fn == gen_dump_char) {
char *s = encode_bytes(mem_ctx, ptr, array_len);
if (!s) return -1;
if (addtabbed(mem_ctx, p, pinfo->name, indent) ||
addstr(mem_ctx, p, " = {") ||
addstr(mem_ctx, p, s) ||
addstr(mem_ctx, p, "}\n")) {
return -1;
}
free(s);
return 0;
}
for (i=0;i<array_len;i++) {
const char *p2 = ptr;
unsigned size = pinfo->size;
/* generic pointer dereference */
if (pinfo->ptr_count) {
p2 = *(const char **)ptr;
size = sizeof(void *);
}
if ((count || pinfo->ptr_count) &&
!(pinfo->flags & FLAG_ALWAYS) &&
all_zero(ptr, size)) {
ptr += size;
continue;
}
if (count == 0) {
if (addtabbed(mem_ctx, p, pinfo->name, indent) ||
addshort(mem_ctx, p, " = %u:", i)) {
return -1;
}
} else {
if (addshort(mem_ctx, p, ", %u:", i) != 0) {
return -1;
}
}
if (gen_dump_one(mem_ctx, p, pinfo, p2, indent) != 0) {
return -1;
}
ptr += size;
count++;
}
if (count) {
return addstr(mem_ctx, p, "\n");
}
return 0;
}
/* find a variable by name in a loaded structure and return its value
as an integer. Used to support dynamic arrays */
static int find_var(const struct parse_struct *pinfo,
const char *data,
const char *var)
{
int i;
const char *ptr;
/* this allows for constant lengths */
if (isdigit(*var)) {
return atoi(var);
}
for (i=0;pinfo[i].name;i++) {
if (strcmp(pinfo[i].name, var) == 0) break;
}
if (!pinfo[i].name) return -1;
ptr = data + pinfo[i].offset;
switch (pinfo[i].size) {
case sizeof(int):
return *(const int *)ptr;
case sizeof(char):
return *(const char *)ptr;
}
return -1;
}
int gen_dump_struct(TALLOC_CTX *mem_ctx,
const struct parse_struct *pinfo,
struct parse_string *p,
const char *ptr,
unsigned indent)
{
char *s = gen_dump(mem_ctx, pinfo, ptr, indent+1);
if (!s) return -1;
if (addstr(mem_ctx, p, "{\n") ||
addstr(mem_ctx, p, s) ||
addtabbed(mem_ctx, p, "}", indent)) {
return -1;
}
return 0;
}
static int gen_dump_string(TALLOC_CTX *mem_ctx,
struct parse_string *p,
const struct parse_struct *pinfo,
const char *data,
unsigned indent)
{
const char *ptr = *(const char **)data;
char *s = encode_bytes(mem_ctx, ptr, strlen(ptr));
if (addtabbed(mem_ctx, p, pinfo->name, indent) ||
addstr(mem_ctx, p, " = ") ||
addchar(mem_ctx, p, '{') ||
addstr(mem_ctx, p, s) ||
addstr(mem_ctx, p, "}\n")) {
return -1;
}
return 0;
}
/*
find the length of a nullterm array
*/
static int len_nullterm(const char *ptr, int size, int array_len)
{
int len;
if (size == 1) {
len = strnlen(ptr, array_len);
} else {
for (len=0; len < array_len; len++) {
if (all_zero(ptr+len*size, size)) break;
}
}
if (len == 0) len = 1;
return len;
}
/* the generic dump routine. Scans the parse information for this structure
and processes it recursively */
char *gen_dump(TALLOC_CTX *mem_ctx,
const struct parse_struct *pinfo,
const char *data,
unsigned indent)
{
struct parse_string p;
int i;
p.length = 0;
p.allocated = 0;
p.s = NULL;
if (addstr(mem_ctx, &p, "") != 0) {
return NULL;
}
for (i=0;pinfo[i].name;i++) {
const char *ptr = data + pinfo[i].offset;
unsigned size = pinfo[i].size;
if (pinfo[i].ptr_count) {
size = sizeof(void *);
}
/* special handling for array types */
if (pinfo[i].array_len) {
unsigned len = pinfo[i].array_len;
if (pinfo[i].flags & FLAG_NULLTERM) {
len = len_nullterm(ptr, size, len);
}
if (gen_dump_array(mem_ctx, &p, &pinfo[i], ptr,
len, indent)) {
goto failed;
}
continue;
}
/* and dynamically sized arrays */
if (pinfo[i].dynamic_len) {
int len = find_var(pinfo, data, pinfo[i].dynamic_len);
struct parse_struct p2 = pinfo[i];
if (len < 0) {
goto failed;
}
if (len > 0) {
if (pinfo[i].flags & FLAG_NULLTERM) {
len = len_nullterm(*(const char **)ptr,
pinfo[i].size, len);
}
p2.ptr_count--;
p2.dynamic_len = NULL;
if (gen_dump_array(mem_ctx, &p, &p2,
*(const char **)ptr,
len, indent) != 0) {
goto failed;
}
}
continue;
}
/* don't dump zero elements */
if (!(pinfo[i].flags & FLAG_ALWAYS) && all_zero(ptr, size)) continue;
/* assume char* is a null terminated string */
if (pinfo[i].size == 1 && pinfo[i].ptr_count == 1 &&
pinfo[i].dump_fn == gen_dump_char) {
if (gen_dump_string(mem_ctx, &p, &pinfo[i], ptr, indent) != 0) {
goto failed;
}
continue;
}
/* generic pointer dereference */
if (pinfo[i].ptr_count) {
ptr = *(const char **)ptr;
}
if (addtabbed(mem_ctx, &p, pinfo[i].name, indent) ||
addstr(mem_ctx, &p, " = ") ||
gen_dump_one(mem_ctx, &p, &pinfo[i], ptr, indent) ||
addstr(mem_ctx, &p, "\n")) {
goto failed;
}
}
return p.s;
failed:
return NULL;
}
/* search for a character in a string, skipping over sections within
matching braces */
static char *match_braces(char *s, char c)
{
int depth = 0;
while (*s) {
switch (*s) {
case '}':
depth--;
break;
case '{':
depth++;
break;
}
if (depth == 0 && *s == c) {
return s;
}
s++;
}
return s;
}
/* parse routine for enumerated types */
int gen_parse_enum(TALLOC_CTX *mem_ctx,
const struct enum_struct *einfo,
char *ptr,
const char *str)
{
unsigned v;
int i;
if (isdigit(*str)) {
if (sscanf(str, "%u", &v) != 1) {
errno = EINVAL;
return -1;
}
*(unsigned *)ptr = v;
return 0;
}
for (i=0;einfo[i].name;i++) {
if (strcmp(einfo[i].name, str) == 0) {
*(unsigned *)ptr = einfo[i].value;
return 0;
}
}
/* unknown enum value?? */
return -1;
}
/* parse all base types */
static int gen_parse_base(TALLOC_CTX *mem_ctx,
const struct parse_struct *pinfo,
char *ptr,
const char *str)
{
if (pinfo->parse_fn == gen_parse_char && pinfo->ptr_count==1) {
unsigned len;
char *s = decode_bytes(mem_ctx, str, &len);
if (!s) return -1;
*(char **)ptr = s;
return 0;
}
if (pinfo->ptr_count) {
unsigned size = pinfo->ptr_count>1?sizeof(void *):pinfo->size;
struct parse_struct p2 = *pinfo;
*(void **)ptr = talloc(mem_ctx, size);
if (! *(void **)ptr) {
return -1;
}
memset(*(void **)ptr, 0, size);
ptr = *(char **)ptr;
p2.ptr_count--;
return gen_parse_base(mem_ctx, &p2, ptr, str);
}
return pinfo->parse_fn(mem_ctx, ptr, str);
}
/* parse a generic array */
static int gen_parse_array(TALLOC_CTX *mem_ctx,
const struct parse_struct *pinfo,
char *ptr,
const char *str,
int array_len)
{
char *p, *p2;
unsigned size = pinfo->size;
/* special handling of fixed length strings */
if (array_len != 0 &&
pinfo->ptr_count == 0 &&
pinfo->dump_fn == gen_dump_char) {
unsigned len = 0;
char *s = decode_bytes(mem_ctx, str, &len);
if (!s || (len > array_len)) return -1;
memset(ptr, 0, array_len);
memcpy(ptr, s, len);
return 0;
}
if (pinfo->ptr_count) {
size = sizeof(void *);
}
while (*str) {
unsigned idx;
int done;
idx = atoi(str);
p = strchr(str,':');
if (!p) break;
p++;
p2 = match_braces(p, ',');
done = (*p2 != ',');
*p2 = 0;
if (*p == '{') {
p++;
p[strlen(p)-1] = 0;
}
if (gen_parse_base(mem_ctx, pinfo, ptr + idx*size, p) != 0) {
return -1;
}
if (done) break;
str = p2+1;
}
return 0;
}
/* parse one element, hanlding dynamic and static arrays */
static int gen_parse_one(TALLOC_CTX *mem_ctx,
const struct parse_struct *pinfo,
const char *name,
char *data,
const char *str)
{
int i;
for (i=0;pinfo[i].name;i++) {
if (strcmp(pinfo[i].name, name) == 0) {
break;
}
}
if (pinfo[i].name == NULL) {
return 0;
}
if (pinfo[i].array_len) {
return gen_parse_array(mem_ctx, &pinfo[i],
data+pinfo[i].offset,
str, pinfo[i].array_len);
}
if (pinfo[i].dynamic_len) {
int len = find_var(pinfo, data, pinfo[i].dynamic_len);
if (len < 0) {
errno = EINVAL;
return -1;
}
if (len > 0) {
struct parse_struct p2 = pinfo[i];
char *ptr;
unsigned size = pinfo[i].ptr_count>1?sizeof(void*):pinfo[i].size;
ptr = talloc(mem_ctx, len*size);
if (!ptr) {
errno = ENOMEM;
return -1;
}
memset(ptr, 0, len*size);
*((char **)(data + pinfo[i].offset)) = ptr;
p2.ptr_count--;
p2.dynamic_len = NULL;
return gen_parse_array(mem_ctx, &p2, ptr, str, len);
}
return 0;
}
return gen_parse_base(mem_ctx, &pinfo[i], data + pinfo[i].offset, str);
}
int gen_parse_struct(TALLOC_CTX * mem_ctx, const struct parse_struct *pinfo, char *ptr, const char *str)
{
return gen_parse(mem_ctx, pinfo, ptr, str);
}
/* the main parse routine */
int gen_parse(TALLOC_CTX *mem_ctx, const struct parse_struct *pinfo, char *data, const char *s)
{
char *str, *s0;
s0 = strdup(s);
str = s0;
while (*str) {
char *p;
char *name;
char *value;
/* skip leading whitespace */
while (isspace(*str)) str++;
p = strchr(str, '=');
if (!p) break;
value = p+1;
while (p > str && isspace(*(p-1))) {
p--;
}
*p = 0;
name = str;
while (isspace(*value)) value++;
if (*value == '{') {
str = match_braces(value, '}');
value++;
} else {
str = match_braces(value, '\n');
}
*str++ = 0;
if (gen_parse_one(mem_ctx, pinfo, name, data, value) != 0) {
free(s0);
return -1;
}
}
free(s0);
return 0;
}
/* for convenience supply some standard dumpers and parsers here */
int gen_parse_char(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
*(unsigned char *)ptr = atoi(str);
return 0;
}
int gen_parse_int(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
*(int *)ptr = atoi(str);
return 0;
}
int gen_parse_unsigned(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
*(unsigned *)ptr = strtoul(str, NULL, 10);
return 0;
}
int gen_parse_time_t(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
*(time_t *)ptr = strtoul(str, NULL, 10);
return 0;
}
int gen_parse_double(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
*(double *)ptr = atof(str);
return 0;
}
int gen_parse_float(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
*(float *)ptr = atof(str);
return 0;
}
int gen_dump_char(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
return addshort(mem_ctx, p, "%u", *(unsigned char *)(ptr));
}
int gen_dump_int(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
return addshort(mem_ctx, p, "%d", *(int *)(ptr));
}
int gen_dump_unsigned(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
return addshort(mem_ctx, p, "%u", *(unsigned *)(ptr));
}
int gen_dump_time_t(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
return addshort(mem_ctx, p, "%u", *(time_t *)(ptr));
}
int gen_dump_double(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
return addshort(mem_ctx, p, "%lg", *(double *)(ptr));
}
int gen_dump_float(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
return addshort(mem_ctx, p, "%g", *(float *)(ptr));
}

View File

@@ -0,0 +1,200 @@
/*
Copyright (C) Andrew Tridgell <genstruct@tridgell.net> 2002
Copyright (C) Simo Sorce <idra@samba.org> 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 "genparser_samba.h"
/* PARSE functions */
int gen_parse_uint8(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
*(uint8 *)ptr = atoi(str);
return 0;
}
int gen_parse_uint16(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
*(uint16 *)ptr = atoi(str);
return 0;
}
int gen_parse_uint32(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
*(uint32 *)ptr = strtoul(str, NULL, 10);
return 0;
}
int gen_parse_NTTIME(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
if(sscanf(str, "%u,%u", &(((NTTIME *)(ptr))->high), &(((NTTIME *)(ptr))->low)) != 2) {
errno = EINVAL;
return -1;
}
return 0;
}
int gen_parse_DOM_SID(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
if(!string_to_sid((DOM_SID *)ptr, str)) return -1;
return 0;
}
int gen_parse_SEC_ACCESS(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
((SEC_ACCESS *)ptr)->mask = strtoul(str, NULL, 10);
return 0;
}
int gen_parse_GUID(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
int info[GUID_SIZE];
int i;
char *sc;
char *p;
char *m;
m = strdup(str);
if (!m) return -1;
sc = m;
memset(info, 0, sizeof(info));
for (i = 0; i < GUID_SIZE; i++) {
p = strchr(sc, ',');
if (p != NULL) p = '\0';
info[i] = atoi(sc);
if (p != NULL) sc = p + 1;
}
free(m);
for (i = 0; i < GUID_SIZE; i++) {
((GUID *)ptr)->info[i] = info[i];
}
return 0;
}
int gen_parse_SEC_ACE(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
return gen_parse_struct(mem_ctx, pinfo_security_ace_info, ptr, str);
}
int gen_parse_SEC_ACL(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
return gen_parse_struct(mem_ctx, pinfo_security_acl_info, ptr, str);
}
int gen_parse_SEC_DESC(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
return gen_parse_struct(mem_ctx, pinfo_security_descriptor_info, ptr, str);
}
int gen_parse_LUID_ATTR(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
return gen_parse_struct(mem_ctx, pinfo_luid_attr_info, ptr, str);
}
int gen_parse_LUID(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
if(sscanf(str, "%u,%u", &(((LUID *)(ptr))->high), &(((LUID *)(ptr))->low)) != 2) {
errno = EINVAL;
return -1;
}
return 0;
}
/* DUMP functions */
int gen_dump_uint8(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
return addshort(mem_ctx, p, "%u", *(uint8 *)(ptr));
}
int gen_dump_uint16(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
return addshort(mem_ctx, p, "%u", *(uint16 *)(ptr));
}
int gen_dump_uint32(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
return addshort(mem_ctx, p, "%u", *(uint32 *)(ptr));
}
int gen_dump_NTTIME(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
uint32 low, high;
high = ((NTTIME *)(ptr))->high;
low = ((NTTIME *)(ptr))->low;
return addshort(mem_ctx, p, "%u,%u", high, low);
}
int gen_dump_DOM_SID(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
fstring sidstr;
sid_to_string(sidstr, (DOM_SID *)ptr);
return addstr(mem_ctx, p, sidstr);
}
int gen_dump_SEC_ACCESS(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
return addshort(mem_ctx, p, "%u", ((SEC_ACCESS *)ptr)->mask);
}
int gen_dump_GUID(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
int i, r;
for (i = 0; i < (GUID_SIZE - 1); i++) {
if (!(r = addshort(mem_ctx, p, "%d,", ((GUID *)ptr)->info[i]))) return r;
}
return addshort(mem_ctx, p, "%d", ((GUID *)ptr)->info[i]);
}
int gen_dump_SEC_ACE(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
return gen_dump_struct(mem_ctx, pinfo_security_ace_info, p, ptr, indent);
}
int gen_dump_SEC_ACL(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
return gen_dump_struct(mem_ctx, pinfo_security_acl_info, p, ptr, indent);
}
int gen_dump_SEC_DESC(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
return gen_dump_struct(mem_ctx, pinfo_security_descriptor_info, p, ptr, indent);
}
int gen_dump_LUID_ATTR(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
return gen_dump_struct(mem_ctx, pinfo_luid_attr_info, p, ptr, indent);
}
int gen_dump_LUID(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
{
uint32 low, high;
high = ((LUID *)(ptr))->high;
low = ((LUID *)(ptr))->low;
return addshort(mem_ctx, p, "%u,%u", high, low);
}

267
source/lib/genrand.c Normal file
View File

@@ -0,0 +1,267 @@
/*
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"
static unsigned char hash[258];
static uint32 counter;
static unsigned char *reseed_data;
static size_t reseed_data_size;
/****************************************************************
Copy any user given reseed data.
*****************************************************************/
void set_rand_reseed_data(unsigned char *data, size_t len)
{
SAFE_FREE(reseed_data);
reseed_data_size = 0;
reseed_data = (unsigned char *)memdup(data, len);
if (reseed_data)
reseed_data_size = len;
}
/****************************************************************
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 not initialised.
*****************************************************************/
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;
fd = sys_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 v1, v2; struct timeval tval; pid_t mypid;
struct passwd *pw;
if (use_fd) {
if (fd != -1)
return fd;
fd = sys_open( "/dev/urandom", O_RDONLY,0);
if(fd >= 0)
return fd;
}
/* Add in some secret file contents */
do_filehash("/etc/shadow", &seed_inbuf[0]);
do_filehash(lp_smb_passwd_file(), &seed_inbuf[16]);
/*
* Add in the root encrypted password.
* On any system where security is taken
* seriously this will be secret.
*/
pw = getpwnam_alloc("root");
if (pw && pw->pw_passwd) {
size_t i;
unsigned char md4_tmp[16];
mdfour(md4_tmp, (unsigned char *)pw->pw_passwd, strlen(pw->pw_passwd));
for (i=0;i<16;i++)
seed_inbuf[8+i] ^= md4_tmp[i];
passwd_free(&pw);
}
/*
* 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.
*/
if (reseed_data) {
size_t i;
for (i = 0; i < sizeof(seed_inbuf); i++)
seed_inbuf[i] ^= reseed_data[i % reseed_data_size];
}
seed_random_stream(seed_inbuf, sizeof(seed_inbuf));
return -1;
}
/*******************************************************************
Interface to the (hopefully) good crypto random number generator.
********************************************************************/
void generate_random_buffer( unsigned char *out, int len, BOOL do_reseed_now)
{
static BOOL done_reseed = False;
static int urand_fd = -1;
unsigned char md4_buf[64];
unsigned char tmp_buf[16];
unsigned char *p;
if(!done_reseed || do_reseed_now) {
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;
}
}
/*******************************************************************
Use the random number generator to generate a random string.
********************************************************************/
static char c_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
char *generate_random_str(size_t len)
{
static unsigned char retstr[256];
size_t i;
memset(retstr, '\0', sizeof(retstr));
if (len > sizeof(retstr)-1)
len = sizeof(retstr) -1;
generate_random_buffer( retstr, len, False);
for (i = 0; i < len; i++)
retstr[i] = c_list[ retstr[i] % (sizeof(c_list)-1) ];
retstr[i] = '\0';
return (char *)retstr;
}

156
source/lib/getsmbpass.c Normal file
View File

@@ -0,0 +1,156 @@
/* Copyright (C) 1992-1998 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
/* Modified to use with samba by Jeremy Allison, 8th July 1995. */
#include "includes.h"
#ifdef REPLACE_GETPASS
#ifdef SYSV_TERMIO
/* SYSTEM V TERMIO HANDLING */
static struct termio t;
#define ECHO_IS_ON(t) ((t).c_lflag & ECHO)
#define TURN_ECHO_OFF(t) ((t).c_lflag &= ~ECHO)
#define TURN_ECHO_ON(t) ((t).c_lflag |= ECHO)
#ifndef TCSAFLUSH
#define TCSAFLUSH 1
#endif
#ifndef TCSANOW
#define TCSANOW 0
#endif
static int tcgetattr(int fd, struct termio *t)
{
return ioctl(fd, TCGETA, t);
}
static int tcsetattr(int fd, int flags, struct termio *t)
{
if(flags & TCSAFLUSH)
ioctl(fd, TCFLSH, TCIOFLUSH);
return ioctl(fd, TCSETS, t);
}
#elif !defined(TCSAFLUSH)
/* BSD TERMIO HANDLING */
static struct sgttyb t;
#define ECHO_IS_ON(t) ((t).sg_flags & ECHO)
#define TURN_ECHO_OFF(t) ((t).sg_flags &= ~ECHO)
#define TURN_ECHO_ON(t) ((t).sg_flags |= ECHO)
#define TCSAFLUSH 1
#define TCSANOW 0
static int tcgetattr(int fd, struct sgttyb *t)
{
return ioctl(fd, TIOCGETP, (char *)t);
}
static int tcsetattr(int fd, int flags, struct sgttyb *t)
{
return ioctl(fd, TIOCSETP, (char *)t);
}
#else /* POSIX TERMIO HANDLING */
#define ECHO_IS_ON(t) ((t).c_lflag & ECHO)
#define TURN_ECHO_OFF(t) ((t).c_lflag &= ~ECHO)
#define TURN_ECHO_ON(t) ((t).c_lflag |= ECHO)
static struct termios t;
#endif /* SYSV_TERMIO */
char *getsmbpass(const char *prompt)
{
FILE *in, *out;
int echo_off;
static char buf[256];
static size_t bufsize = sizeof(buf);
size_t nread;
/* Catch problematic signals */
CatchSignal(SIGINT, SIGNAL_CAST SIG_IGN);
/* Try to write to and read from the terminal if we can.
If we can't open the terminal, use stderr and stdin. */
in = fopen ("/dev/tty", "w+");
if (in == NULL)
{
in = stdin;
out = stderr;
}
else
out = in;
setvbuf(in, NULL, _IONBF, 0);
/* Turn echoing off if it is on now. */
if (tcgetattr (fileno (in), &t) == 0)
{
if (ECHO_IS_ON(t))
{
TURN_ECHO_OFF(t);
echo_off = tcsetattr (fileno (in), TCSAFLUSH, &t) == 0;
TURN_ECHO_ON(t);
}
else
echo_off = 0;
}
else
echo_off = 0;
/* Write the prompt. */
fputs (prompt, out);
fflush (out);
/* Read the password. */
buf[0] = 0;
fgets(buf, bufsize, in);
nread = strlen(buf);
if (buf[nread - 1] == '\n')
buf[nread - 1] = '\0';
/* Restore echoing. */
if (echo_off)
(void) tcsetattr (fileno (in), TCSANOW, &t);
if (in != stdin)
/* We opened the terminal; now close it. */
fclose (in);
/* Catch problematic signals */
CatchSignal(SIGINT, SIGNAL_CAST SIG_DFL);
printf("\n");
return buf;
}
#else
void getsmbpasswd_dummy(void);
void getsmbpasswd_dummy(void) {;}
#endif

134
source/lib/hmacmd5.c Normal file
View File

@@ -0,0 +1,134 @@
/*
Unix SMB/CIFS implementation.
HMAC MD5 code for use in NTLMv2
Copyright (C) Luke Kenneth Casson Leighton 1996-2000
Copyright (C) Andrew Tridgell 1992-2000
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* taken direct from rfc2104 implementation and modified for suitable use
* for ntlmv2.
*/
#include "includes.h"
/***********************************************************************
the rfc 2104 version of hmac_md5 initialisation.
***********************************************************************/
void hmac_md5_init_rfc2104(uchar* key, int key_len, HMACMD5Context *ctx)
{
int i;
/* if key is longer than 64 bytes reset it to key=MD5(key) */
if (key_len > 64)
{
uchar tk[16];
struct MD5Context tctx;
MD5Init(&tctx);
MD5Update(&tctx, key, key_len);
MD5Final(tk, &tctx);
key = tk;
key_len = 16;
}
/* start out by storing key in pads */
ZERO_STRUCT(ctx->k_ipad);
ZERO_STRUCT(ctx->k_opad);
memcpy( ctx->k_ipad, key, key_len);
memcpy( ctx->k_opad, key, key_len);
/* XOR key with ipad and opad values */
for (i=0; i<64; i++)
{
ctx->k_ipad[i] ^= 0x36;
ctx->k_opad[i] ^= 0x5c;
}
MD5Init(&ctx->ctx);
MD5Update(&ctx->ctx, ctx->k_ipad, 64);
}
/***********************************************************************
the microsoft version of hmac_md5 initialisation.
***********************************************************************/
void hmac_md5_init_limK_to_64(const uchar* key, int key_len,
HMACMD5Context *ctx)
{
int i;
/* if key is longer than 64 bytes truncate it */
if (key_len > 64)
{
key_len = 64;
}
/* start out by storing key in pads */
ZERO_STRUCT(ctx->k_ipad);
ZERO_STRUCT(ctx->k_opad);
memcpy( ctx->k_ipad, key, key_len);
memcpy( ctx->k_opad, key, key_len);
/* XOR key with ipad and opad values */
for (i=0; i<64; i++) {
ctx->k_ipad[i] ^= 0x36;
ctx->k_opad[i] ^= 0x5c;
}
MD5Init(&ctx->ctx);
MD5Update(&ctx->ctx, ctx->k_ipad, 64);
}
/***********************************************************************
update hmac_md5 "inner" buffer
***********************************************************************/
void hmac_md5_update(const uchar* text, int text_len, HMACMD5Context *ctx)
{
MD5Update(&ctx->ctx, text, text_len); /* then text of datagram */
}
/***********************************************************************
finish off hmac_md5 "inner" buffer and generate outer one.
***********************************************************************/
void hmac_md5_final(uchar *digest, HMACMD5Context *ctx)
{
struct MD5Context ctx_o;
MD5Final(digest, &ctx->ctx);
MD5Init(&ctx_o);
MD5Update(&ctx_o, ctx->k_opad, 64);
MD5Update(&ctx_o, digest, 16);
MD5Final(digest, &ctx_o);
}
/***********************************************************
single function to calculate an HMAC MD5 digest from data.
use the microsoft hmacmd5 init method because the key is 16 bytes.
************************************************************/
void hmac_md5( uchar key[16], uchar* data, int data_len, uchar* digest)
{
HMACMD5Context ctx;
hmac_md5_init_limK_to_64(key, 16, &ctx);
if (data_len != 0)
{
hmac_md5_update(data, data_len, &ctx);
}
hmac_md5_final(digest, &ctx);
}

526
source/lib/iconv.c Normal file
View File

@@ -0,0 +1,526 @@
/*
Unix SMB/CIFS implementation.
minimal iconv implementation
Copyright (C) Andrew Tridgell 2001
Copyright (C) Jelmer Vernooij 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"
/**
* @file
*
* @brief Samba wrapper/stub for iconv character set conversion.
*
* iconv is the XPG2 interface for converting between character
* encodings. This file provides a Samba wrapper around it, and also
* a simple reimplementation that is used if the system does not
* implement iconv.
*
* Samba only works with encodings that are supersets of ASCII: ascii
* characters like whitespace can be tested for directly, multibyte
* sequences start with a byte with the high bit set, and strings are
* terminated by a nul byte.
*
* Note that the only function provided by iconv is conversion between
* characters. It doesn't directly support operations like
* uppercasing or comparison. We have to convert to UCS-2 and compare
* there.
*
* @sa Samba Developers Guide
**/
static size_t ascii_pull(void *,const char **, size_t *, char **, size_t *);
static size_t ascii_push(void *,const char **, size_t *, char **, size_t *);
static size_t utf8_pull(void *,const char **, size_t *, char **, size_t *);
static size_t utf8_push(void *,const char **, size_t *, char **, size_t *);
static size_t ucs2hex_pull(void *,const char **, size_t *, char **, size_t *);
static size_t ucs2hex_push(void *,const char **, size_t *, char **, size_t *);
static size_t iconv_copy(void *,const char **, size_t *, char **, size_t *);
static struct charset_functions builtin_functions[] = {
{"UCS-2LE", iconv_copy, iconv_copy},
{"UTF8", utf8_pull, utf8_push},
{"ASCII", ascii_pull, ascii_push},
{"UCS2-HEX", ucs2hex_pull, ucs2hex_push},
{NULL, NULL, NULL}
};
static struct charset_functions *charsets = NULL;
BOOL smb_register_charset(struct charset_functions *funcs)
{
struct charset_functions *c = charsets;
DEBUG(5, ("Attempting to register new charset %s\n", funcs->name));
/* Check whether we already have this charset... */
while(c) {
if(!strcasecmp(c->name, funcs->name)){
DEBUG(2, ("Duplicate charset %s, not registering\n", funcs->name));
return False;
}
c = c->next;
}
funcs->next = funcs->prev = NULL;
DEBUG(5, ("Registered charset %s\n", funcs->name));
DLIST_ADD(charsets, funcs);
return True;
}
static void lazy_initialize_iconv(void)
{
static BOOL initialized = False;
int i;
if (!initialized) {
initialized = True;
for(i = 0; builtin_functions[i].name; i++)
smb_register_charset(&builtin_functions[i]);
}
}
#ifdef HAVE_NATIVE_ICONV
/* if there was an error then reset the internal state,
this ensures that we don't have a shift state remaining for
character sets like SJIS */
static size_t sys_iconv(void *cd,
const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
size_t ret = iconv((iconv_t)cd,
inbuf, inbytesleft,
outbuf, outbytesleft);
if (ret == (size_t)-1) iconv(cd, NULL, NULL, NULL, NULL);
return ret;
}
#endif
/**
* This is a simple portable iconv() implementaion.
*
* It only knows about a very small number of character sets - just
* enough that Samba works on systems that don't have iconv.
**/
size_t smb_iconv(smb_iconv_t cd,
const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
char cvtbuf[2048];
char *bufp = cvtbuf;
size_t bufsize;
/* in many cases we can go direct */
if (cd->direct) {
return cd->direct(cd->cd_direct,
inbuf, inbytesleft, outbuf, outbytesleft);
}
/* otherwise we have to do it chunks at a time */
while (*inbytesleft > 0) {
bufp = cvtbuf;
bufsize = sizeof(cvtbuf);
if (cd->pull(cd->cd_pull,
inbuf, inbytesleft, &bufp, &bufsize) == -1
&& errno != E2BIG) return -1;
bufp = cvtbuf;
bufsize = sizeof(cvtbuf) - bufsize;
if (cd->push(cd->cd_push,
&bufp, &bufsize,
outbuf, outbytesleft) == -1) return -1;
}
return 0;
}
/*
simple iconv_open() wrapper
*/
smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
{
smb_iconv_t ret;
struct charset_functions *from, *to;
lazy_initialize_iconv();
from = charsets;
to = charsets;
ret = (smb_iconv_t)malloc(sizeof(*ret));
if (!ret) {
errno = ENOMEM;
return (smb_iconv_t)-1;
}
memset(ret, 0, sizeof(*ret));
ret->from_name = strdup(fromcode);
ret->to_name = strdup(tocode);
/* check for the simplest null conversion */
if (strcmp(fromcode, tocode) == 0) {
ret->direct = iconv_copy;
return ret;
}
while (from) {
if (strcasecmp(from->name, fromcode) == 0) break;
from = from->next;
}
while (to) {
if (strcasecmp(to->name, tocode) == 0) break;
to = to->next;
}
#ifdef HAVE_NATIVE_ICONV
if (!from) {
ret->pull = sys_iconv;
ret->cd_pull = iconv_open("UCS-2LE", fromcode);
if (ret->cd_pull == (iconv_t)-1) goto failed;
}
if (!to) {
ret->push = sys_iconv;
ret->cd_push = iconv_open(tocode, "UCS-2LE");
if (ret->cd_push == (iconv_t)-1) goto failed;
}
#else
if (!from || !to) {
goto failed;
}
#endif
/* check for conversion to/from ucs2 */
if (strcasecmp(fromcode, "UCS-2LE") == 0 && to) {
ret->direct = to->push;
return ret;
}
if (strcasecmp(tocode, "UCS-2LE") == 0 && from) {
ret->direct = from->pull;
return ret;
}
#ifdef HAVE_NATIVE_ICONV
if (strcasecmp(fromcode, "UCS-2LE") == 0) {
ret->direct = sys_iconv;
ret->cd_direct = ret->cd_push;
ret->cd_push = NULL;
return ret;
}
if (strcasecmp(tocode, "UCS-2LE") == 0) {
ret->direct = sys_iconv;
ret->cd_direct = ret->cd_pull;
ret->cd_pull = NULL;
return ret;
}
#endif
/* the general case has to go via a buffer */
if (!ret->pull) ret->pull = from->pull;
if (!ret->push) ret->push = to->push;
return ret;
failed:
SAFE_FREE(ret);
errno = EINVAL;
return (smb_iconv_t)-1;
}
/*
simple iconv_close() wrapper
*/
int smb_iconv_close (smb_iconv_t cd)
{
#ifdef HAVE_NATIVE_ICONV
if (cd->cd_direct) iconv_close((iconv_t)cd->cd_direct);
if (cd->cd_pull) iconv_close((iconv_t)cd->cd_pull);
if (cd->cd_push) iconv_close((iconv_t)cd->cd_push);
#endif
SAFE_FREE(cd->from_name);
SAFE_FREE(cd->to_name);
memset(cd, 0, sizeof(*cd));
SAFE_FREE(cd);
return 0;
}
/**********************************************************************
the following functions implement the builtin character sets in Samba
and also the "test" character sets that are designed to test
multi-byte character set support for english users
***********************************************************************/
static size_t ascii_pull(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
while (*inbytesleft >= 1 && *outbytesleft >= 2) {
(*outbuf)[0] = (*inbuf)[0];
(*outbuf)[1] = 0;
(*inbytesleft) -= 1;
(*outbytesleft) -= 2;
(*inbuf) += 1;
(*outbuf) += 2;
}
if (*inbytesleft > 0) {
errno = E2BIG;
return -1;
}
return 0;
}
static size_t ascii_push(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
int ir_count=0;
while (*inbytesleft >= 2 && *outbytesleft >= 1) {
(*outbuf)[0] = (*inbuf)[0] & 0x7F;
if ((*inbuf)[1]) ir_count++;
(*inbytesleft) -= 2;
(*outbytesleft) -= 1;
(*inbuf) += 2;
(*outbuf) += 1;
}
if (*inbytesleft == 1) {
errno = EINVAL;
return -1;
}
if (*inbytesleft > 1) {
errno = E2BIG;
return -1;
}
return ir_count;
}
static size_t ucs2hex_pull(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
while (*inbytesleft >= 1 && *outbytesleft >= 2) {
unsigned v;
if ((*inbuf)[0] != '@') {
/* seven bit ascii case */
(*outbuf)[0] = (*inbuf)[0];
(*outbuf)[1] = 0;
(*inbytesleft) -= 1;
(*outbytesleft) -= 2;
(*inbuf) += 1;
(*outbuf) += 2;
continue;
}
/* it's a hex character */
if (*inbytesleft < 5) {
errno = EINVAL;
return -1;
}
if (sscanf(&(*inbuf)[1], "%04x", &v) != 1) {
errno = EILSEQ;
return -1;
}
(*outbuf)[0] = v&0xff;
(*outbuf)[1] = v>>8;
(*inbytesleft) -= 5;
(*outbytesleft) -= 2;
(*inbuf) += 5;
(*outbuf) += 2;
}
if (*inbytesleft > 0) {
errno = E2BIG;
return -1;
}
return 0;
}
static size_t ucs2hex_push(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
while (*inbytesleft >= 2 && *outbytesleft >= 1) {
char buf[6];
if ((*inbuf)[1] == 0 &&
((*inbuf)[0] & 0x80) == 0 &&
(*inbuf)[0] != '@') {
(*outbuf)[0] = (*inbuf)[0];
(*inbytesleft) -= 2;
(*outbytesleft) -= 1;
(*inbuf) += 2;
(*outbuf) += 1;
continue;
}
if (*outbytesleft < 5) {
errno = E2BIG;
return -1;
}
snprintf(buf, 6, "@%04x", SVAL(*inbuf, 0));
memcpy(*outbuf, buf, 5);
(*inbytesleft) -= 2;
(*outbytesleft) -= 5;
(*inbuf) += 2;
(*outbuf) += 5;
}
if (*inbytesleft == 1) {
errno = EINVAL;
return -1;
}
if (*inbytesleft > 1) {
errno = E2BIG;
return -1;
}
return 0;
}
static size_t iconv_copy(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
int n;
n = MIN(*inbytesleft, *outbytesleft);
memmove(*outbuf, *inbuf, n);
(*inbytesleft) -= n;
(*outbytesleft) -= n;
(*inbuf) += n;
(*outbuf) += n;
if (*inbytesleft > 0) {
errno = E2BIG;
return -1;
}
return 0;
}
static size_t utf8_pull(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
while (*inbytesleft >= 1 && *outbytesleft >= 2) {
const unsigned char *c = (const unsigned char *)*inbuf;
unsigned char *uc = (unsigned char *)*outbuf;
int len = 1;
if ((c[0] & 0x80) == 0) {
uc[0] = c[0];
uc[1] = 0;
} else if ((c[0] & 0xf0) == 0xe0) {
if (*inbytesleft < 3) {
DEBUG(0,("short utf8 char\n"));
goto badseq;
}
uc[1] = ((c[0]&0xF)<<4) | ((c[1]>>2)&0xF);
uc[0] = (c[1]<<6) | (c[2]&0x3f);
len = 3;
} else if ((c[0] & 0xe0) == 0xc0) {
if (*inbytesleft < 2) {
DEBUG(0,("short utf8 char\n"));
goto badseq;
}
uc[1] = (c[0]>>2) & 0x7;
uc[0] = (c[0]<<6) | (c[1]&0x3f);
len = 2;
}
(*inbuf) += len;
(*inbytesleft) -= len;
(*outbytesleft) -= 2;
(*outbuf) += 2;
}
if (*inbytesleft > 0) {
errno = E2BIG;
return -1;
}
return 0;
badseq:
errno = EINVAL;
return -1;
}
static size_t utf8_push(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
while (*inbytesleft >= 2 && *outbytesleft >= 1) {
unsigned char *c = (unsigned char *)*outbuf;
const unsigned char *uc = (const unsigned char *)*inbuf;
int len=1;
if (uc[1] & 0xf8) {
if (*outbytesleft < 3) {
DEBUG(0,("short utf8 write\n"));
goto toobig;
}
c[0] = 0xe0 | (uc[1]>>4);
c[1] = 0x80 | ((uc[1]&0xF)<<2) | (uc[0]>>6);
c[2] = 0x80 | (uc[0]&0x3f);
len = 3;
} else if (uc[1] | (uc[0] & 0x80)) {
if (*outbytesleft < 2) {
DEBUG(0,("short utf8 write\n"));
goto toobig;
}
c[0] = 0xc0 | (uc[1]<<2) | (uc[0]>>6);
c[1] = 0x80 | (uc[0]&0x3f);
len = 2;
} else {
c[0] = uc[0];
}
(*inbytesleft) -= 2;
(*outbytesleft) -= len;
(*inbuf) += 2;
(*outbuf) += len;
}
if (*inbytesleft == 1) {
errno = EINVAL;
return -1;
}
if (*inbytesleft > 1) {
errno = E2BIG;
return -1;
}
return 0;
toobig:
errno = E2BIG;
return -1;
}

333
source/lib/interface.c Normal file
View File

@@ -0,0 +1,333 @@
/*
Unix SMB/CIFS implementation.
multiple interface 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"
static struct iface_struct *probed_ifaces;
static int total_probed;
static struct in_addr allones_ip;
struct in_addr loopback_ip;
static struct interface *local_interfaces;
#define ALLONES ((uint32)0xFFFFFFFF)
#define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
#define MKNETADDR(_IP, _NM) (_IP & _NM)
/****************************************************************************
Try and find an interface that matches an ip. If we cannot, return NULL
**************************************************************************/
static struct interface *iface_find(struct in_addr ip, BOOL CheckMask)
{
struct interface *i;
if (is_zero_ip(ip)) return local_interfaces;
for (i=local_interfaces;i;i=i->next)
if (CheckMask) {
if (same_net(i->ip,ip,i->nmask)) return i;
} else if ((i->ip).s_addr == ip.s_addr) return i;
return NULL;
}
/****************************************************************************
add an interface to the linked list of interfaces
****************************************************************************/
static void add_interface(struct in_addr ip, struct in_addr nmask)
{
struct interface *iface;
if (iface_find(ip, False)) {
DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip)));
return;
}
if (ip_equal(nmask, allones_ip)) {
DEBUG(3,("not adding non-broadcast interface %s\n",inet_ntoa(ip)));
return;
}
iface = (struct interface *)malloc(sizeof(*iface));
if (!iface) return;
ZERO_STRUCTPN(iface);
iface->ip = ip;
iface->nmask = nmask;
iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr);
DLIST_ADD(local_interfaces, iface);
DEBUG(2,("added interface ip=%s ",inet_ntoa(iface->ip)));
DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast)));
DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask)));
}
/****************************************************************************
interpret a single element from a interfaces= config line
This handles the following different forms:
1) wildcard interface name
2) DNS name
3) IP/masklen
4) ip/mask
5) bcast/mask
****************************************************************************/
static void interpret_interface(TALLOC_CTX *mem_ctx, const char *token)
{
struct in_addr ip, nmask;
char *p;
int i, added=0;
zero_ip(&ip);
zero_ip(&nmask);
/* first check if it is an interface name */
for (i=0;i<total_probed;i++) {
if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
add_interface(probed_ifaces[i].ip,
probed_ifaces[i].netmask);
added = 1;
}
}
if (added) return;
/* maybe it is a DNS name */
p = strchr_m(token,'/');
if (!p) {
ip = *interpret_addr2(mem_ctx, token);
for (i=0;i<total_probed;i++) {
if (ip.s_addr == probed_ifaces[i].ip.s_addr &&
!ip_equal(allones_ip, probed_ifaces[i].netmask)) {
add_interface(probed_ifaces[i].ip,
probed_ifaces[i].netmask);
return;
}
}
DEBUG(2,("can't determine netmask for %s\n", token));
return;
}
/* parse it into an IP address/netmasklength pair */
*p++ = 0;
ip = *interpret_addr2(mem_ctx, token);
if (strlen(p) > 2) {
nmask = *interpret_addr2(mem_ctx, p);
} else {
nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
}
/* maybe the first component was a broadcast address */
if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) ||
ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) {
for (i=0;i<total_probed;i++) {
if (same_net(ip, probed_ifaces[i].ip, nmask)) {
add_interface(probed_ifaces[i].ip, nmask);
return;
}
}
DEBUG(2,("Can't determine ip for broadcast address %s\n", token));
return;
}
add_interface(ip, nmask);
}
/****************************************************************************
load the list of network interfaces
****************************************************************************/
void load_interfaces(void)
{
const char **ptr;
int i;
struct iface_struct ifaces[MAX_INTERFACES];
TALLOC_CTX *mem_ctx;
ptr = lp_interfaces();
mem_ctx = talloc_init("load_interfaces");
if (!mem_ctx) {
DEBUG(2,("no memory to load interfaces \n"));
return;
}
allones_ip = *interpret_addr2(mem_ctx, "255.255.255.255");
loopback_ip = *interpret_addr2(mem_ctx, "127.0.0.1");
SAFE_FREE(probed_ifaces);
/* dump the current interfaces if any */
while (local_interfaces) {
struct interface *iface = local_interfaces;
DLIST_REMOVE(local_interfaces, local_interfaces);
ZERO_STRUCTPN(iface);
SAFE_FREE(iface);
}
/* probe the kernel for interfaces */
total_probed = get_interfaces(ifaces, MAX_INTERFACES);
if (total_probed > 0) {
probed_ifaces = memdup(ifaces, sizeof(ifaces[0])*total_probed);
}
/* if we don't have a interfaces line then use all broadcast capable
interfaces except loopback */
if (!ptr || !*ptr || !**ptr) {
if (total_probed <= 0) {
DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
exit(1);
}
for (i=0;i<total_probed;i++) {
if (probed_ifaces[i].netmask.s_addr != allones_ip.s_addr &&
probed_ifaces[i].ip.s_addr != loopback_ip.s_addr) {
add_interface(probed_ifaces[i].ip,
probed_ifaces[i].netmask);
}
}
goto exit;
}
if (ptr) {
while (*ptr) {
interpret_interface(mem_ctx, *ptr);
ptr++;
}
}
if (!local_interfaces) {
DEBUG(0,("WARNING: no network interfaces found\n"));
}
exit:
talloc_destroy(mem_ctx);
}
/****************************************************************************
return True if the list of probed interfaces has changed
****************************************************************************/
BOOL interfaces_changed(void)
{
int n;
struct iface_struct ifaces[MAX_INTERFACES];
n = get_interfaces(ifaces, MAX_INTERFACES);
if ((n > 0 )&& (n != total_probed ||
memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
return True;
}
return False;
}
/****************************************************************************
check if an IP is one of mine
**************************************************************************/
BOOL ismyip(struct in_addr ip)
{
struct interface *i;
for (i=local_interfaces;i;i=i->next)
if (ip_equal(i->ip,ip)) return True;
return False;
}
/****************************************************************************
check if a packet is from a local (known) net
**************************************************************************/
BOOL is_local_net(struct in_addr from)
{
struct interface *i;
for (i=local_interfaces;i;i=i->next) {
if((from.s_addr & i->nmask.s_addr) ==
(i->ip.s_addr & i->nmask.s_addr))
return True;
}
return False;
}
/****************************************************************************
how many interfaces do we have
**************************************************************************/
int iface_count(void)
{
int ret = 0;
struct interface *i;
for (i=local_interfaces;i;i=i->next)
ret++;
return ret;
}
/****************************************************************************
return IP of the Nth interface
**************************************************************************/
struct in_addr *iface_n_ip(int n)
{
struct interface *i;
for (i=local_interfaces;i && n;i=i->next)
n--;
if (i) return &i->ip;
return NULL;
}
/****************************************************************************
return bcast of the Nth interface
**************************************************************************/
struct in_addr *iface_n_bcast(int n)
{
struct interface *i;
for (i=local_interfaces;i && n;i=i->next)
n--;
if (i) return &i->bcast;
return NULL;
}
/* these 3 functions return the ip/bcast/nmask for the interface
most appropriate for the given ip address. If they can't find
an appropriate interface they return the requested field of the
first known interface. */
struct in_addr *iface_ip(struct in_addr ip)
{
struct interface *i = iface_find(ip, True);
return(i ? &i->ip : &local_interfaces->ip);
}
/*
return True if a IP is directly reachable on one of our interfaces
*/
BOOL iface_local(struct in_addr ip)
{
return iface_find(ip, True) ? True : False;
}

407
source/lib/interfaces.c Normal file
View File

@@ -0,0 +1,407 @@
/*
Unix SMB/CIFS implementation.
return a list of network interfaces
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.
*/
/* working out the interfaces for a OS is an incredibly non-portable
thing. We have several possible implementations below, and autoconf
tries each of them to see what works
Note that this file does _not_ include includes.h. That is so this code
can be called directly from the autoconf tests. That also means
this code cannot use any of the normal Samba debug stuff or defines.
This is standalone code.
*/
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <net/if.h>
#ifdef AUTOCONF_TEST
struct iface_struct {
char name[16];
struct in_addr ip;
struct in_addr netmask;
};
#else
#include "config.h"
#include "interfaces.h"
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifndef SIOCGIFCONF
#ifdef HAVE_SYS_SOCKIO_H
#include <sys/sockio.h>
#endif
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#ifdef __COMPAR_FN_T
#define QSORT_CAST (__compar_fn_t)
#endif
#ifndef QSORT_CAST
#define QSORT_CAST (int (*)(const void *, const void *))
#endif
#if HAVE_IFACE_IFCONF
/* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
It probably also works on any BSD style system. */
/****************************************************************************
get the netmask address for a local interface
****************************************************************************/
static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
{
struct ifconf ifc;
char buff[8192];
int fd, i, n;
struct ifreq *ifr=NULL;
int total = 0;
struct in_addr ipaddr;
struct in_addr nmask;
char *iname;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
return -1;
}
ifc.ifc_len = sizeof(buff);
ifc.ifc_buf = buff;
if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
close(fd);
return -1;
}
ifr = ifc.ifc_req;
n = ifc.ifc_len / sizeof(struct ifreq);
/* Loop through interfaces, looking for given IP address */
for (i=n-1;i>=0 && total < max_interfaces;i--) {
if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
continue;
}
iname = ifr[i].ifr_name;
ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr;
if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
continue;
}
if (!(ifr[i].ifr_flags & IFF_UP)) {
continue;
}
if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
continue;
}
nmask = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr;
strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
ifaces[total].ip = ipaddr;
ifaces[total].netmask = nmask;
total++;
}
close(fd);
return total;
}
#elif HAVE_IFACE_IFREQ
#ifndef I_STR
#include <sys/stropts.h>
#endif
/****************************************************************************
this should cover most of the streams based systems
Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
****************************************************************************/
static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
{
struct ifreq ifreq;
struct strioctl strioctl;
char buff[8192];
int fd, i, n;
struct ifreq *ifr=NULL;
int total = 0;
struct in_addr ipaddr;
struct in_addr nmask;
char *iname;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
return -1;
}
strioctl.ic_cmd = SIOCGIFCONF;
strioctl.ic_dp = buff;
strioctl.ic_len = sizeof(buff);
if (ioctl(fd, I_STR, &strioctl) < 0) {
close(fd);
return -1;
}
/* we can ignore the possible sizeof(int) here as the resulting
number of interface structures won't change */
n = strioctl.ic_len / sizeof(struct ifreq);
/* we will assume that the kernel returns the length as an int
at the start of the buffer if the offered size is a
multiple of the structure size plus an int */
if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
ifr = (struct ifreq *)(buff + sizeof(int));
} else {
ifr = (struct ifreq *)buff;
}
/* Loop through interfaces */
for (i = 0; i<n && total < max_interfaces; i++) {
ifreq = ifr[i];
strioctl.ic_cmd = SIOCGIFFLAGS;
strioctl.ic_dp = (char *)&ifreq;
strioctl.ic_len = sizeof(struct ifreq);
if (ioctl(fd, I_STR, &strioctl) != 0) {
continue;
}
if (!(ifreq.ifr_flags & IFF_UP)) {
continue;
}
strioctl.ic_cmd = SIOCGIFADDR;
strioctl.ic_dp = (char *)&ifreq;
strioctl.ic_len = sizeof(struct ifreq);
if (ioctl(fd, I_STR, &strioctl) != 0) {
continue;
}
ipaddr = (*(struct sockaddr_in *) &ifreq.ifr_addr).sin_addr;
iname = ifreq.ifr_name;
strioctl.ic_cmd = SIOCGIFNETMASK;
strioctl.ic_dp = (char *)&ifreq;
strioctl.ic_len = sizeof(struct ifreq);
if (ioctl(fd, I_STR, &strioctl) != 0) {
continue;
}
nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
ifaces[total].ip = ipaddr;
ifaces[total].netmask = nmask;
total++;
}
close(fd);
return total;
}
#elif HAVE_IFACE_AIX
/****************************************************************************
this one is for AIX (tested on 4.2)
****************************************************************************/
static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
{
char buff[8192];
int fd, i;
struct ifconf ifc;
struct ifreq *ifr=NULL;
struct in_addr ipaddr;
struct in_addr nmask;
char *iname;
int total = 0;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
return -1;
}
ifc.ifc_len = sizeof(buff);
ifc.ifc_buf = buff;
if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
close(fd);
return -1;
}
ifr = ifc.ifc_req;
/* Loop through interfaces */
i = ifc.ifc_len;
while (i > 0 && total < max_interfaces) {
unsigned inc;
inc = ifr->ifr_addr.sa_len;
if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
goto next;
}
ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
iname = ifr->ifr_name;
if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
goto next;
}
if (!(ifr->ifr_flags & IFF_UP)) {
goto next;
}
if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
goto next;
}
nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
ifaces[total].ip = ipaddr;
ifaces[total].netmask = nmask;
total++;
next:
/*
* Patch from Archie Cobbs (archie@whistle.com). The
* addresses in the SIOCGIFCONF interface list have a
* minimum size. Usually this doesn't matter, but if
* your machine has tunnel interfaces, etc. that have
* a zero length "link address", this does matter. */
if (inc < sizeof(ifr->ifr_addr))
inc = sizeof(ifr->ifr_addr);
inc += IFNAMSIZ;
ifr = (struct ifreq*) (((char*) ifr) + inc);
i -= inc;
}
close(fd);
return total;
}
#else /* a dummy version */
static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
{
return -1;
}
#endif
static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
{
int r;
r = strcmp(i1->name, i2->name);
if (r) return r;
r = ntohl(i1->ip.s_addr) - ntohl(i2->ip.s_addr);
if (r) return r;
r = ntohl(i1->netmask.s_addr) - ntohl(i2->netmask.s_addr);
return r;
}
/* this wrapper is used to remove duplicates from the interface list generated
above */
int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
{
int total, i, j;
total = _get_interfaces(ifaces, max_interfaces);
if (total <= 0) return total;
/* now we need to remove duplicates */
qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
for (i=1;i<total;) {
if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
for (j=i-1;j<total-1;j++) {
ifaces[j] = ifaces[j+1];
}
total--;
} else {
i++;
}
}
return total;
}
#ifdef AUTOCONF_TEST
/* this is the autoconf driver to test get_interfaces() */
#define MAX_INTERFACES 128
int main()
{
struct iface_struct ifaces[MAX_INTERFACES];
int total = get_interfaces(ifaces, MAX_INTERFACES);
int i;
printf("got %d interfaces:\n", total);
if (total <= 0) exit(1);
for (i=0;i<total;i++) {
printf("%-10s ", ifaces[i].name);
printf("IP=%s ", inet_ntoa(ifaces[i].ip));
printf("NETMASK=%s\n", inet_ntoa(ifaces[i].netmask));
}
return 0;
}
#endif

90
source/lib/ldap_escape.c Normal file
View File

@@ -0,0 +1,90 @@
/*
Unix SMB/CIFS implementation.
ldap filter argument escaping
Copyright (C) 1998, 1999, 2000 Luke Howard <lukeh@padl.com>,
Copyright (C) 2003 Andrew Bartlett <abartlet@samba.org>
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"
/**
* Escape a parameter to an LDAP filter string, so they cannot contain
* embeded ( ) * or \ chars which may cause it not to parse correctly.
*
* @param s The input string
*
* @return A string allocated with malloc(), containing the escaped string,
* and to be free()ed by the caller.
**/
char *escape_ldap_string_alloc(const char *s)
{
size_t len = strlen(s)+1;
char *output = malloc(len);
char *output_tmp;
const char *sub;
int i = 0;
char *p = output;
while (*s)
{
switch (*s)
{
case '*':
sub = "\\2a";
break;
case '(':
sub = "\\28";
break;
case ')':
sub = "\\29";
break;
case '\\':
sub = "\\5c";
break;
default:
sub = NULL;
break;
}
if (sub) {
len = len + 3;
output_tmp = realloc(output, len);
if (!output_tmp) {
SAFE_FREE(output);
return NULL;
}
output = output_tmp;
p = &output[i];
strncpy (p, sub, 3);
p += 3;
i += 3;
} else {
*p = *s;
p++;
i++;
}
s++;
}
*p = '\0';
return output;
}

175
source/lib/md4.c Normal file
View File

@@ -0,0 +1,175 @@
/*
Unix SMB/CIFS implementation.
a implementation of MD4 designed for use in the SMB authentication protocol
Copyright (C) Andrew Tridgell 1997-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"
/* NOTE: This code makes no attempt to be fast!
It assumes that a int is at least 32 bits long
*/
struct mdfour_state {
uint32 A, B, C, D;
};
static uint32 F(uint32 X, uint32 Y, uint32 Z)
{
return (X&Y) | ((~X)&Z);
}
static uint32 G(uint32 X, uint32 Y, uint32 Z)
{
return (X&Y) | (X&Z) | (Y&Z);
}
static uint32 H(uint32 X, uint32 Y, uint32 Z)
{
return X^Y^Z;
}
static uint32 lshift(uint32 x, int s)
{
x &= 0xFFFFFFFF;
return ((x<<s)&0xFFFFFFFF) | (x>>(32-s));
}
#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + (uint32)0x5A827999,s)
#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + (uint32)0x6ED9EBA1,s)
/* this applies md4 to 64 byte chunks */
static void mdfour64(struct mdfour_state *s, uint32 *M)
{
int j;
uint32 AA, BB, CC, DD;
uint32 X[16];
for (j=0;j<16;j++)
X[j] = M[j];
AA = s->A; BB = s->B; CC = s->C; DD = s->D;
ROUND1(s->A,s->B,s->C,s->D, 0, 3); ROUND1(s->D,s->A,s->B,s->C, 1, 7);
ROUND1(s->C,s->D,s->A,s->B, 2, 11); ROUND1(s->B,s->C,s->D,s->A, 3, 19);
ROUND1(s->A,s->B,s->C,s->D, 4, 3); ROUND1(s->D,s->A,s->B,s->C, 5, 7);
ROUND1(s->C,s->D,s->A,s->B, 6, 11); ROUND1(s->B,s->C,s->D,s->A, 7, 19);
ROUND1(s->A,s->B,s->C,s->D, 8, 3); ROUND1(s->D,s->A,s->B,s->C, 9, 7);
ROUND1(s->C,s->D,s->A,s->B, 10, 11); ROUND1(s->B,s->C,s->D,s->A, 11, 19);
ROUND1(s->A,s->B,s->C,s->D, 12, 3); ROUND1(s->D,s->A,s->B,s->C, 13, 7);
ROUND1(s->C,s->D,s->A,s->B, 14, 11); ROUND1(s->B,s->C,s->D,s->A, 15, 19);
ROUND2(s->A,s->B,s->C,s->D, 0, 3); ROUND2(s->D,s->A,s->B,s->C, 4, 5);
ROUND2(s->C,s->D,s->A,s->B, 8, 9); ROUND2(s->B,s->C,s->D,s->A, 12, 13);
ROUND2(s->A,s->B,s->C,s->D, 1, 3); ROUND2(s->D,s->A,s->B,s->C, 5, 5);
ROUND2(s->C,s->D,s->A,s->B, 9, 9); ROUND2(s->B,s->C,s->D,s->A, 13, 13);
ROUND2(s->A,s->B,s->C,s->D, 2, 3); ROUND2(s->D,s->A,s->B,s->C, 6, 5);
ROUND2(s->C,s->D,s->A,s->B, 10, 9); ROUND2(s->B,s->C,s->D,s->A, 14, 13);
ROUND2(s->A,s->B,s->C,s->D, 3, 3); ROUND2(s->D,s->A,s->B,s->C, 7, 5);
ROUND2(s->C,s->D,s->A,s->B, 11, 9); ROUND2(s->B,s->C,s->D,s->A, 15, 13);
ROUND3(s->A,s->B,s->C,s->D, 0, 3); ROUND3(s->D,s->A,s->B,s->C, 8, 9);
ROUND3(s->C,s->D,s->A,s->B, 4, 11); ROUND3(s->B,s->C,s->D,s->A, 12, 15);
ROUND3(s->A,s->B,s->C,s->D, 2, 3); ROUND3(s->D,s->A,s->B,s->C, 10, 9);
ROUND3(s->C,s->D,s->A,s->B, 6, 11); ROUND3(s->B,s->C,s->D,s->A, 14, 15);
ROUND3(s->A,s->B,s->C,s->D, 1, 3); ROUND3(s->D,s->A,s->B,s->C, 9, 9);
ROUND3(s->C,s->D,s->A,s->B, 5, 11); ROUND3(s->B,s->C,s->D,s->A, 13, 15);
ROUND3(s->A,s->B,s->C,s->D, 3, 3); ROUND3(s->D,s->A,s->B,s->C, 11, 9);
ROUND3(s->C,s->D,s->A,s->B, 7, 11); ROUND3(s->B,s->C,s->D,s->A, 15, 15);
s->A += AA;
s->B += BB;
s->C += CC;
s->D += DD;
s->A &= 0xFFFFFFFF;
s->B &= 0xFFFFFFFF;
s->C &= 0xFFFFFFFF;
s->D &= 0xFFFFFFFF;
for (j=0;j<16;j++)
X[j] = 0;
}
static void copy64(uint32 *M, const unsigned char *in)
{
int i;
for (i=0;i<16;i++)
M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
(in[i*4+1]<<8) | (in[i*4+0]<<0);
}
static void copy4(unsigned char *out, uint32 x)
{
out[0] = x&0xFF;
out[1] = (x>>8)&0xFF;
out[2] = (x>>16)&0xFF;
out[3] = (x>>24)&0xFF;
}
/* produce a md4 message digest from data of length n bytes */
void mdfour(unsigned char *out, const unsigned char *in, int n)
{
unsigned char buf[128];
uint32 M[16];
uint32 b = n * 8;
int i;
struct mdfour_state state;
state.A = 0x67452301;
state.B = 0xefcdab89;
state.C = 0x98badcfe;
state.D = 0x10325476;
while (n > 64) {
copy64(M, in);
mdfour64(&state, M);
in += 64;
n -= 64;
}
for (i=0;i<128;i++)
buf[i] = 0;
memcpy(buf, in, n);
buf[n] = 0x80;
if (n <= 55) {
copy4(buf+56, b);
copy64(M, buf);
mdfour64(&state, M);
} else {
copy4(buf+120, b);
copy64(M, buf);
mdfour64(&state, M);
copy64(M, buf+64);
mdfour64(&state, M);
}
for (i=0;i<128;i++)
buf[i] = 0;
copy64(M, buf);
copy4(out, state.A);
copy4(out+4, state.B);
copy4(out+8, state.C);
copy4(out+12, state.D);
}

247
source/lib/md5.c Normal file
View File

@@ -0,0 +1,247 @@
/*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
/* This code slightly modified to fit into Samba by
abartlet@samba.org Jun 2001 */
#include "includes.h"
#include "md5.h"
static void MD5Transform(uint32 buf[4], uint32 const in[16]);
/*
* Note: this code is harmless on little-endian machines.
*/
static void byteReverse(unsigned char *buf, unsigned longs)
{
uint32 t;
do {
t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
*(uint32 *) buf = t;
buf += 4;
} while (--longs);
}
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
void MD5Init(struct MD5Context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
{
register uint32 t;
/* Update bitcount */
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if (t) {
unsigned char *p = (unsigned char *) ctx->in + t;
t = 64 - t;
if (len < t) {
memmove(p, buf, len);
return;
}
memmove(p, buf, t);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *) ctx->in);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64) {
memmove(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *) ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memmove(ctx->in, buf, len);
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
{
unsigned int count;
unsigned char *p;
/* Compute number of bytes mod 64 */
count = (ctx->bits[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *) ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
} else {
/* Pad block to 56 bytes */
memset(p, 0, count - 8);
}
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
((uint32 *) ctx->in)[14] = ctx->bits[0];
((uint32 *) ctx->in)[15] = ctx->bits[1];
MD5Transform(ctx->buf, (uint32 *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
memmove(digest, ctx->buf, 16);
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
}
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void MD5Transform(uint32 buf[4], uint32 const in[16])
{
register uint32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}

566
source/lib/messages.c Normal file
View File

@@ -0,0 +1,566 @@
/*
Unix SMB/CIFS implementation.
Samba internal messaging functions
Copyright (C) Andrew Tridgell 2000
Copyright (C) 2001 by Martin Pool
Copyright (C) 2002 by Jeremy Allison
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.
*/
/**
@defgroup messages Internal messaging framework
@{
@file messages.c
@brief Module for internal messaging between Samba daemons.
The idea is that if a part of Samba wants to do communication with
another Samba process then it will do a message_register() of a
dispatch function, and use message_send_pid() to send messages to
that process.
The dispatch function is given the pid of the sender, and it can
use that to reply by message_send_pid(). See ping_message() for a
simple example.
@caution Dispatch functions must be able to cope with incoming
messages on an *odd* byte boundary.
This system doesn't have any inherent size limitations but is not
very efficient for large messages or when messages are sent in very
quick succession.
*/
#include "includes.h"
/* the locking database handle */
static TDB_CONTEXT *tdb;
static int received_signal;
/* change the message version with any incompatible changes in the protocol */
#define MESSAGE_VERSION 1
struct message_rec {
int msg_version;
int msg_type;
pid_t dest;
pid_t src;
size_t len;
};
/* we have a linked list of dispatch handlers */
static struct dispatch_fns {
struct dispatch_fns *next, *prev;
int msg_type;
void (*fn)(int msg_type, pid_t pid, void *buf, size_t len);
} *dispatch_fns;
/****************************************************************************
Notifications come in as signals.
****************************************************************************/
static void sig_usr1(void)
{
received_signal = 1;
sys_select_signal();
}
/****************************************************************************
A useful function for testing the message system.
****************************************************************************/
static void ping_message(int msg_type, pid_t src, void *buf, size_t len)
{
const char *msg = buf ? buf : "none";
DEBUG(1,("INFO: Received PING message from PID %u [%s]\n",(unsigned int)src, msg));
message_send_pid(src, MSG_PONG, buf, len, True);
}
/****************************************************************************
Initialise the messaging functions.
****************************************************************************/
BOOL message_init(void)
{
TALLOC_CTX *mem_ctx;
if (tdb) return True;
mem_ctx = talloc_init("message_init");
if (!mem_ctx) {
DEBUG(0,("ERROR: No memory to initialise messages database\n"));
return False;
}
tdb = tdb_open_log(lock_path(mem_ctx, "messages.tdb"),
0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
O_RDWR|O_CREAT,0600);
talloc_destroy(mem_ctx);
if (!tdb) {
DEBUG(0,("ERROR: Failed to initialise messages database\n"));
return False;
}
CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1);
message_register(MSG_PING, ping_message);
return True;
}
/*******************************************************************
Form a static tdb key from a pid.
******************************************************************/
static TDB_DATA message_key_pid(pid_t pid)
{
static char key[20];
TDB_DATA kbuf;
slprintf(key, sizeof(key)-1, "PID/%d", (int)pid);
kbuf.dptr = (char *)key;
kbuf.dsize = strlen(key)+1;
return kbuf;
}
/****************************************************************************
Notify a process that it has a message. If the process doesn't exist
then delete its record in the database.
****************************************************************************/
static BOOL message_notify(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);
if (kill(pid, SIGUSR1) == -1) {
if (errno == ESRCH) {
DEBUG(2,("pid %d doesn't exist - deleting messages record\n", (int)pid));
tdb_delete(tdb, message_key_pid(pid));
} else {
DEBUG(2,("message to process %d failed - %s\n", (int)pid, strerror(errno)));
}
return False;
}
return True;
}
/****************************************************************************
Send a message to a particular pid.
****************************************************************************/
static BOOL message_send_pid_internal(pid_t pid, int msg_type, const void *buf, size_t len,
BOOL duplicates_allowed, unsigned int timeout)
{
TDB_DATA kbuf;
TDB_DATA dbuf;
TDB_DATA old_dbuf;
struct message_rec rec;
char *ptr;
struct message_rec prec;
/*
* Doing kill with a non-positive pid causes messages to be
* sent to places we don't want.
*/
SMB_ASSERT(pid > 0);
rec.msg_version = MESSAGE_VERSION;
rec.msg_type = msg_type;
rec.dest = pid;
rec.src = getpid();
rec.len = len;
kbuf = message_key_pid(pid);
dbuf.dptr = (void *)malloc(len + sizeof(rec));
if (!dbuf.dptr)
return False;
memcpy(dbuf.dptr, &rec, sizeof(rec));
if (len > 0)
memcpy((void *)((char*)dbuf.dptr+sizeof(rec)), buf, len);
dbuf.dsize = len + sizeof(rec);
if (duplicates_allowed) {
/* If duplicates are allowed we can just append the message and return. */
/* lock the record for the destination */
if (timeout) {
if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) {
DEBUG(0,("message_send_pid_internal: failed to get chainlock with timeout %ul.\n", timeout));
return False;
}
} else {
if (tdb_chainlock(tdb, kbuf) == -1) {
DEBUG(0,("message_send_pid_internal: failed to get chainlock.\n"));
return False;
}
}
tdb_append(tdb, kbuf, dbuf);
tdb_chainunlock(tdb, kbuf);
SAFE_FREE(dbuf.dptr);
errno = 0; /* paranoia */
return message_notify(pid);
}
/* lock the record for the destination */
if (timeout) {
if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) {
DEBUG(0,("message_send_pid_internal: failed to get chainlock with timeout %ul.\n", timeout));
return False;
}
} else {
if (tdb_chainlock(tdb, kbuf) == -1) {
DEBUG(0,("message_send_pid_internal: failed to get chainlock.\n"));
return False;
}
}
old_dbuf = tdb_fetch(tdb, kbuf);
if (!old_dbuf.dptr) {
/* its a new record */
tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
tdb_chainunlock(tdb, kbuf);
SAFE_FREE(dbuf.dptr);
errno = 0; /* paranoia */
return message_notify(pid);
}
/* Not a new record. Check for duplicates. */
for(ptr = (char *)old_dbuf.dptr; ptr < old_dbuf.dptr + old_dbuf.dsize; ) {
/*
* First check if the message header matches, then, if it's a non-zero
* sized message, check if the data matches. If so it's a duplicate and
* we can discard it. JRA.
*/
if (!memcmp(ptr, &rec, sizeof(rec))) {
if (!len || (len && !memcmp( ptr + sizeof(rec), buf, len))) {
tdb_chainunlock(tdb, kbuf);
DEBUG(10,("message_send_pid_internal: discarding duplicate message.\n"));
SAFE_FREE(dbuf.dptr);
SAFE_FREE(old_dbuf.dptr);
return True;
}
}
memcpy(&prec, ptr, sizeof(prec));
ptr += sizeof(rec) + prec.len;
}
/* we're adding to an existing entry */
tdb_append(tdb, kbuf, dbuf);
tdb_chainunlock(tdb, kbuf);
SAFE_FREE(old_dbuf.dptr);
SAFE_FREE(dbuf.dptr);
errno = 0; /* paranoia */
return message_notify(pid);
}
/****************************************************************************
Send a message to a particular pid - no timeout.
****************************************************************************/
BOOL message_send_pid(pid_t pid, int msg_type, const void *buf, size_t len, BOOL duplicates_allowed)
{
return message_send_pid_internal(pid, msg_type, buf, len, duplicates_allowed, 0);
}
/****************************************************************************
Send a message to a particular pid, with timeout in seconds.
****************************************************************************/
BOOL message_send_pid_with_timeout(pid_t pid, int msg_type, const void *buf, size_t len,
BOOL duplicates_allowed, unsigned int timeout)
{
return message_send_pid_internal(pid, msg_type, buf, len, duplicates_allowed, timeout);
}
/****************************************************************************
Retrieve all messages for the current process.
****************************************************************************/
static BOOL retrieve_all_messages(char **msgs_buf, size_t *total_len)
{
TDB_DATA kbuf;
TDB_DATA dbuf;
TDB_DATA null_dbuf;
ZERO_STRUCT(null_dbuf);
*msgs_buf = NULL;
*total_len = 0;
kbuf = message_key_pid(getpid());
tdb_chainlock(tdb, kbuf);
dbuf = tdb_fetch(tdb, kbuf);
/*
* Replace with an empty record to keep the allocated
* space in the tdb.
*/
tdb_store(tdb, kbuf, null_dbuf, TDB_REPLACE);
tdb_chainunlock(tdb, kbuf);
if (dbuf.dptr == NULL || dbuf.dsize == 0) {
SAFE_FREE(dbuf.dptr);
return False;
}
*msgs_buf = dbuf.dptr;
*total_len = dbuf.dsize;
return True;
}
/****************************************************************************
Parse out the next message for the current process.
****************************************************************************/
static BOOL message_recv(char *msgs_buf, size_t total_len, int *msg_type, pid_t *src, char **buf, size_t *len)
{
struct message_rec rec;
char *ret_buf = *buf;
*buf = NULL;
*len = 0;
if (total_len - (ret_buf - msgs_buf) < sizeof(rec))
return False;
memcpy(&rec, ret_buf, sizeof(rec));
ret_buf += sizeof(rec);
if (rec.msg_version != MESSAGE_VERSION) {
DEBUG(0,("message version %d received (expected %d)\n", rec.msg_version, MESSAGE_VERSION));
return False;
}
if (rec.len > 0) {
if (total_len - (ret_buf - msgs_buf) < rec.len)
return False;
}
*len = rec.len;
*msg_type = rec.msg_type;
*src = rec.src;
*buf = ret_buf;
return True;
}
/****************************************************************************
Receive and dispatch any messages pending for this process.
Notice that all dispatch handlers for a particular msg_type get called,
so you can register multiple handlers for a message.
*NOTE*: Dispatch functions must be able to cope with incoming
messages on an *odd* byte boundary.
****************************************************************************/
void message_dispatch(void)
{
int msg_type;
pid_t src;
char *buf;
char *msgs_buf;
size_t len, total_len;
struct dispatch_fns *dfn;
int n_handled;
if (!received_signal)
return;
DEBUG(10,("message_dispatch: received_signal = %d\n", received_signal));
received_signal = 0;
if (!retrieve_all_messages(&msgs_buf, &total_len))
return;
for (buf = msgs_buf; message_recv(msgs_buf, total_len, &msg_type, &src, &buf, &len); buf += len) {
DEBUG(10,("message_dispatch: received msg_type=%d src_pid=%u\n",
msg_type, (unsigned int) src));
n_handled = 0;
for (dfn = dispatch_fns; dfn; dfn = dfn->next) {
if (dfn->msg_type == msg_type) {
DEBUG(10,("message_dispatch: processing message of type %d.\n", msg_type));
dfn->fn(msg_type, src, len ? (void *)buf : NULL, len);
n_handled++;
}
}
if (!n_handled) {
DEBUG(5,("message_dispatch: warning: no handlers registed for "
"msg_type %d in pid %u\n",
msg_type, (unsigned int)getpid()));
}
}
SAFE_FREE(msgs_buf);
}
/****************************************************************************
Register a dispatch function for a particular message type.
*NOTE*: Dispatch functions must be able to cope with incoming
messages on an *odd* byte boundary.
****************************************************************************/
void message_register(int msg_type,
void (*fn)(int msg_type, pid_t pid, void *buf, size_t len))
{
struct dispatch_fns *dfn;
dfn = (struct dispatch_fns *)malloc(sizeof(*dfn));
if (dfn != NULL) {
ZERO_STRUCTPN(dfn);
dfn->msg_type = msg_type;
dfn->fn = fn;
DLIST_ADD(dispatch_fns, dfn);
}
else {
DEBUG(0,("message_register: Not enough memory. malloc failed!\n"));
}
}
/****************************************************************************
De-register the function for a particular message type.
****************************************************************************/
void message_deregister(int msg_type)
{
struct dispatch_fns *dfn, *next;
for (dfn = dispatch_fns; dfn; dfn = next) {
next = dfn->next;
if (dfn->msg_type == msg_type) {
DLIST_REMOVE(dispatch_fns, dfn);
SAFE_FREE(dfn);
}
}
}
struct msg_all {
int msg_type;
uint32 msg_flag;
const void *buf;
size_t len;
BOOL duplicates;
int n_sent;
};
/****************************************************************************
Send one of the messages for the broadcast.
****************************************************************************/
static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
{
struct connections_data crec;
struct msg_all *msg_all = (struct msg_all *)state;
if (dbuf.dsize != sizeof(crec))
return 0;
memcpy(&crec, dbuf.dptr, sizeof(crec));
if (crec.cnum != -1)
return 0;
/* Don't send if the receiver hasn't registered an interest. */
if(!(crec.bcast_msg_flags & msg_all->msg_flag))
return 0;
/* If the msg send fails because the pid was not found (i.e. smbd died),
* the msg has already been deleted from the messages.tdb.*/
if (!message_send_pid(crec.pid, msg_all->msg_type,
msg_all->buf, msg_all->len,
msg_all->duplicates)) {
/* If the pid was not found delete the entry from connections.tdb */
if (errno == ESRCH) {
DEBUG(2,("pid %u doesn't exist - deleting connections %d [%s]\n",
(unsigned int)crec.pid, crec.cnum, crec.name));
tdb_delete(the_tdb, kbuf);
}
}
msg_all->n_sent++;
return 0;
}
/**
* Send a message to all smbd processes.
*
* It isn't very efficient, but should be OK for the sorts of
* applications that use it. When we need efficient broadcast we can add
* it.
*
* @param n_sent Set to the number of messages sent. This should be
* equal to the number of processes, but be careful for races.
*
* @retval True for success.
**/
BOOL message_send_all(TDB_CONTEXT *conn_tdb, int msg_type,
const void *buf, size_t len,
BOOL duplicates_allowed,
int *n_sent)
{
struct msg_all msg_all;
msg_all.msg_type = msg_type;
if (msg_type < 1000)
msg_all.msg_flag = FLAG_MSG_GENERAL;
else if (msg_type > 1000 && msg_type < 2000)
msg_all.msg_flag = FLAG_MSG_NMBD;
else if (msg_type > 2000 && msg_type < 3000)
msg_all.msg_flag = FLAG_MSG_PRINTING;
else if (msg_type > 3000 && msg_type < 4000)
msg_all.msg_flag = FLAG_MSG_SMBD;
else
return False;
msg_all.buf = buf;
msg_all.len = len;
msg_all.duplicates = duplicates_allowed;
msg_all.n_sent = 0;
tdb_traverse(conn_tdb, traverse_fn, &msg_all);
if (n_sent)
*n_sent = msg_all.n_sent;
return True;
}
/** @} **/

128
source/lib/module.c Normal file
View File

@@ -0,0 +1,128 @@
/*
Unix SMB/CIFS implementation.
module loading system
Copyright (C) Jelmer Vernooij 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"
#ifdef HAVE_DLOPEN
int smb_load_module(const char *module_name)
{
void *handle;
init_module_function *init;
int status;
const char *error;
/* Always try to use LAZY symbol resolving; if the plugin has
* backwards compatibility, there might be symbols in the
* plugin referencing to old (removed) functions
*/
handle = sys_dlopen(module_name, RTLD_LAZY);
if(!handle) {
DEBUG(0, ("Error loading module '%s': %s\n", module_name, sys_dlerror()));
return False;
}
init = sys_dlsym(handle, "init_module");
/* we must check sys_dlerror() to determine if it worked, because
sys_dlsym() can validly return NULL */
error = sys_dlerror();
if (error) {
DEBUG(0, ("Error trying to resolve symbol 'init_module' in %s: %s\n", module_name, error));
return False;
}
status = init();
DEBUG(2, ("Module '%s' loaded\n", module_name));
return status;
}
/* Load all modules in list and return number of
* modules that has been successfully loaded */
int smb_load_modules(const char **modules)
{
int i;
int success = 0;
for(i = 0; modules[i]; i++){
if(smb_load_module(modules[i])) {
success++;
}
}
DEBUG(2, ("%d modules successfully loaded\n", success));
return success;
}
int smb_probe_module(const char *subsystem, const char *module)
{
char *full_path;
int rc;
TALLOC_CTX *mem_ctx;
/* Check for absolute path */
if(module[0] == '/')return smb_load_module(module);
mem_ctx = talloc_init("smb_probe_module");
if (!mem_ctx) {
DEBUG(0,("No memory for loading modules\n"));
return False;
}
full_path = talloc_strdup(mem_ctx, lib_path(mem_ctx, subsystem));
full_path = talloc_asprintf(mem_ctx, "%s/%s.%s",
full_path, module, shlib_ext());
rc = smb_load_module(full_path);
talloc_destroy(mem_ctx);
return rc;
}
#else /* HAVE_DLOPEN */
int smb_load_module(const char *module_name)
{
DEBUG(0,("This samba executable has not been built with plugin support"));
return False;
}
int smb_load_modules(const char **modules)
{
DEBUG(0,("This samba executable has not been built with plugin support"));
return False;
}
int smb_probe_module(const char *subsystem, const char *module)
{
DEBUG(0,("This samba executable has not been built with plugin support, not probing"));
return False;
}
#endif /* HAVE_DLOPEN */
void init_modules(void)
{
if(lp_preload_modules())
smb_load_modules(lp_preload_modules());
/* FIXME: load static modules */
}

226
source/lib/ms_fnmatch.c Normal file
View File

@@ -0,0 +1,226 @@
/*
Unix SMB/CIFS implementation.
filename matching routine
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. */
/*
This module was originally based on fnmatch.c copyright by the Free
Software Foundation. It bears little resemblence to that code now
*/
#if FNMATCH_TEST
#include <stdio.h>
#include <stdlib.h>
#else
#include "includes.h"
#endif
/*
bugger. we need a separate wildcard routine for older versions
of the protocol. This is not yet perfect, but its a lot
better than what we had */
static int ms_fnmatch_lanman_core(const smb_ucs2_t *pattern,
const smb_ucs2_t *string)
{
const smb_ucs2_t *p = pattern, *n = string;
smb_ucs2_t c;
if (strcmp_wa(p, "?")==0 && strcmp_wa(n, ".")) goto match;
while ((c = *p++)) {
switch (c) {
case UCS2_CHAR('.'):
if (! *n) goto next;
if (*n != UCS2_CHAR('.')) goto nomatch;
n++;
break;
case UCS2_CHAR('?'):
if (! *n) goto next;
if ((*n == UCS2_CHAR('.') &&
n[1] != UCS2_CHAR('.')) || ! *n)
goto next;
n++;
break;
case UCS2_CHAR('>'):
if (! *n) goto next;
if (n[0] == UCS2_CHAR('.')) {
if (! n[1] && ms_fnmatch_lanman_core(p, n+1) == 0) goto match;
if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
goto nomatch;
}
n++;
break;
case UCS2_CHAR('*'):
if (! *n) goto next;
if (! *p) goto match;
for (; *n; n++) {
if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
}
break;
case UCS2_CHAR('<'):
for (; *n; n++) {
if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
if (*n == UCS2_CHAR('.') &&
!strchr_w(n+1,UCS2_CHAR('.'))) {
n++;
break;
}
}
break;
case UCS2_CHAR('"'):
if (*n == 0 && ms_fnmatch_lanman_core(p, n) == 0) goto match;
if (*n != UCS2_CHAR('.')) goto nomatch;
n++;
break;
default:
if (c != *n) goto nomatch;
n++;
}
}
if (! *n) goto match;
nomatch:
/*
if (verbose) printf("NOMATCH pattern=[%s] string=[%s]\n", pattern, string);
*/
return -1;
next:
if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
goto nomatch;
match:
/*
if (verbose) printf("MATCH pattern=[%s] string=[%s]\n", pattern, string);
*/
return 0;
}
static int ms_fnmatch_lanman1(const smb_ucs2_t *pattern, const smb_ucs2_t *string)
{
if (!strpbrk_wa(pattern, "?*<>\"")) {
smb_ucs2_t s[] = {UCS2_CHAR('.'), 0};
if (strcmp_wa(string,"..") == 0) string = s;
return strcasecmp_w(pattern, string);
}
if (strcmp_wa(string,"..") == 0 || strcmp_wa(string,".") == 0) {
smb_ucs2_t dot[] = {UCS2_CHAR('.'), 0};
smb_ucs2_t dotdot[] = {UCS2_CHAR('.'), UCS2_CHAR('.'), 0};
return ms_fnmatch_lanman_core(pattern, dotdot) &&
ms_fnmatch_lanman_core(pattern, dot);
}
return ms_fnmatch_lanman_core(pattern, string);
}
/* the following function was derived using the masktest utility -
after years of effort we finally have a perfect MS wildcard
matching routine!
NOTE: this matches only filenames with no directory component
Returns 0 on match, -1 on fail.
*/
static int ms_fnmatch_w(const smb_ucs2_t *pattern, const smb_ucs2_t *string,
enum protocol_types protocol)
{
const smb_ucs2_t *p = pattern, *n = string;
smb_ucs2_t c;
if (protocol <= PROTOCOL_LANMAN2) {
return ms_fnmatch_lanman1(pattern, string);
}
while ((c = *p++)) {
switch (c) {
case UCS2_CHAR('?'):
if (! *n) return -1;
n++;
break;
case UCS2_CHAR('>'):
if (n[0] == UCS2_CHAR('.')) {
if (! n[1] && ms_fnmatch_w(p, n+1, protocol) == 0) return 0;
if (ms_fnmatch_w(p, n, protocol) == 0) return 0;
return -1;
}
if (! *n) return ms_fnmatch_w(p, n, protocol);
n++;
break;
case UCS2_CHAR('*'):
for (; *n; n++) {
if (ms_fnmatch_w(p, n, protocol) == 0) return 0;
}
break;
case UCS2_CHAR('<'):
for (; *n; n++) {
if (ms_fnmatch_w(p, n, protocol) == 0) return 0;
if (*n == UCS2_CHAR('.') && !strchr_wa(n+1,'.')) {
n++;
break;
}
}
break;
case UCS2_CHAR('"'):
if (*n == 0 && ms_fnmatch_w(p, n, protocol) == 0) return 0;
if (*n != UCS2_CHAR('.')) return -1;
n++;
break;
default:
if (c != *n) return -1;
n++;
}
}
if (! *n) return 0;
return -1;
}
int ms_fnmatch(const char *pattern, const char *string, enum protocol_types protocol)
{
wpstring p, s;
int ret;
pstrcpy_wa(p, pattern);
pstrcpy_wa(s, string);
ret = ms_fnmatch_w(p, s, protocol);
/* DEBUG(0,("ms_fnmatch(%s,%s) -> %d\n", pattern, string, ret)); */
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);
}

142
source/lib/mutex.c Normal file
View File

@@ -0,0 +1,142 @@
/*
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"
static mutex_t mutex_list[MUTEX_MAX];
/* the registered mutex handlers */
static struct {
const char *name;
struct mutex_ops ops;
} mutex_handlers;
int mutex_lock_by_id(enum mutex_id id, const char *name)
{
return mutex_lock(&mutex_list[id], name);
}
int mutex_unlock_by_id(enum mutex_id id, const char *name)
{
return mutex_unlock(&mutex_list[id], name);
}
int mutex_init(mutex_t *mutex, const char *name)
{
if (mutex_handlers.ops.mutex_init) {
return mutex_handlers.ops.mutex_init(mutex, name);
}
return 0;
}
int mutex_destroy(mutex_t *mutex, const char *name)
{
if (mutex_handlers.ops.mutex_destroy) {
return mutex_handlers.ops.mutex_destroy(mutex, name);
}
return 0;
}
int mutex_lock(mutex_t *mutex, const char *name)
{
if (mutex_handlers.ops.mutex_lock) {
return mutex_handlers.ops.mutex_lock(mutex, name);
}
return 0;
}
int mutex_unlock(mutex_t *mutex, const char *name)
{
if (mutex_handlers.ops.mutex_unlock) {
return mutex_handlers.ops.mutex_unlock(mutex, name);
}
return 0;
}
/* read/write lock routines */
int rwlock_init(rwlock_t *rwlock, const char *name)
{
if (mutex_handlers.ops.rwlock_init) {
return mutex_handlers.ops.rwlock_init(rwlock, name);
}
return 0;
}
int rwlock_destroy(rwlock_t *rwlock, const char *name)
{
if (mutex_handlers.ops.rwlock_destroy) {
return mutex_handlers.ops.rwlock_destroy(rwlock, name);
}
return 0;
}
int rwlock_lock_write(rwlock_t *rwlock, const char *name)
{
if (mutex_handlers.ops.rwlock_lock_write) {
return mutex_handlers.ops.rwlock_lock_write(rwlock, name);
}
return 0;
}
int rwlock_lock_read(rwlock_t *rwlock, const char *name)
{
if (mutex_handlers.ops.rwlock_lock_read) {
return mutex_handlers.ops.rwlock_lock_read(rwlock, name);
}
return 0;
}
int rwlock_unlock(rwlock_t *rwlock, const char *name)
{
if (mutex_handlers.ops.rwlock_unlock) {
return mutex_handlers.ops.rwlock_unlock(rwlock, name);
}
return 0;
}
/*
register a set of mutex/rwlock handlers.
Should only be called once in the execution of smbd.
*/
BOOL register_mutex_handlers(const char *name, struct mutex_ops *ops)
{
if (mutex_handlers.name != NULL) {
/* it's already registered! */
DEBUG(2,("mutex handler '%s' already registered - failed '%s'\n",
mutex_handlers.name, name));
return False;
}
mutex_handlers.name = name;
mutex_handlers.ops = *ops;
if (mutex_handlers.ops.mutex_init) {
enum mutex_id id;
for (id=0; id < MUTEX_MAX; id++) {
mutex_handlers.ops.mutex_init(&mutex_list[id], "mutex_list");
}
}
DEBUG(2,("mutex handler '%s' registered\n", name));
return True;
}

126
source/lib/pam_errors.c Normal file
View File

@@ -0,0 +1,126 @@
/*
* Unix SMB/CIFS implementation.
* PAM error mapping functions
* 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"
#ifdef WITH_PAM
#include <security/pam_appl.h>
#if defined(PAM_AUTHTOK_RECOVERY_ERR) && !defined(PAM_AUTHTOK_RECOVER_ERR)
#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR
#endif
/* PAM -> NT_STATUS map */
static const struct {
int pam_code;
NTSTATUS ntstatus;
} pam_to_nt_status_map[] = {
{PAM_OPEN_ERR, NT_STATUS_UNSUCCESSFUL},
{PAM_SYMBOL_ERR, NT_STATUS_UNSUCCESSFUL},
{PAM_SERVICE_ERR, NT_STATUS_UNSUCCESSFUL},
{PAM_SYSTEM_ERR, NT_STATUS_UNSUCCESSFUL},
{PAM_BUF_ERR, NT_STATUS_UNSUCCESSFUL},
{PAM_PERM_DENIED, NT_STATUS_ACCESS_DENIED},
{PAM_AUTH_ERR, NT_STATUS_WRONG_PASSWORD},
{PAM_CRED_INSUFFICIENT, NT_STATUS_INSUFFICIENT_LOGON_INFO}, /* FIXME: Is this correct? */
{PAM_AUTHINFO_UNAVAIL, NT_STATUS_LOGON_FAILURE},
{PAM_USER_UNKNOWN, NT_STATUS_NO_SUCH_USER},
{PAM_MAXTRIES, NT_STATUS_REMOTE_SESSION_LIMIT}, /* FIXME: Is this correct? */
{PAM_NEW_AUTHTOK_REQD, NT_STATUS_PASSWORD_MUST_CHANGE},
{PAM_ACCT_EXPIRED, NT_STATUS_ACCOUNT_EXPIRED},
{PAM_SESSION_ERR, NT_STATUS_INSUFFICIENT_RESOURCES},
{PAM_CRED_UNAVAIL, NT_STATUS_NO_TOKEN}, /* FIXME: Is this correct? */
{PAM_CRED_EXPIRED, NT_STATUS_PASSWORD_EXPIRED}, /* FIXME: Is this correct? */
{PAM_CRED_ERR, NT_STATUS_UNSUCCESSFUL},
{PAM_AUTHTOK_ERR, NT_STATUS_UNSUCCESSFUL},
#ifdef PAM_AUTHTOK_RECOVER_ERR
{PAM_AUTHTOK_RECOVER_ERR, NT_STATUS_UNSUCCESSFUL},
#endif
{PAM_AUTHTOK_EXPIRED, NT_STATUS_PASSWORD_EXPIRED},
{PAM_SUCCESS, NT_STATUS_OK}
};
/* NT_STATUS -> PAM map */
static const struct {
NTSTATUS ntstatus;
int pam_code;
} nt_status_to_pam_map[] = {
{NT_STATUS_UNSUCCESSFUL, PAM_SYSTEM_ERR},
{NT_STATUS_NO_SUCH_USER, PAM_USER_UNKNOWN},
{NT_STATUS_WRONG_PASSWORD, PAM_AUTH_ERR},
{NT_STATUS_LOGON_FAILURE, PAM_AUTH_ERR},
{NT_STATUS_ACCOUNT_EXPIRED, PAM_ACCT_EXPIRED},
{NT_STATUS_PASSWORD_EXPIRED, PAM_AUTHTOK_EXPIRED},
{NT_STATUS_PASSWORD_MUST_CHANGE, PAM_NEW_AUTHTOK_REQD},
{NT_STATUS_OK, PAM_SUCCESS}
};
/*****************************************************************************
convert a PAM error to a NT status32 code
*****************************************************************************/
NTSTATUS pam_to_nt_status(int pam_error)
{
int i;
if (pam_error == 0) return NT_STATUS_OK;
for (i=0; NT_STATUS_V(pam_to_nt_status_map[i].ntstatus); i++) {
if (pam_error == pam_to_nt_status_map[i].pam_code)
return pam_to_nt_status_map[i].ntstatus;
}
return NT_STATUS_UNSUCCESSFUL;
}
/*****************************************************************************
convert an NT status32 code to a PAM error
*****************************************************************************/
int nt_status_to_pam(NTSTATUS nt_status)
{
int i;
if NT_STATUS_IS_OK(nt_status) return PAM_SUCCESS;
for (i=0; NT_STATUS_V(nt_status_to_pam_map[i].ntstatus); i++) {
if (NT_STATUS_EQUAL(nt_status,nt_status_to_pam_map[i].ntstatus))
return nt_status_to_pam_map[i].pam_code;
}
return PAM_SYSTEM_ERR;
}
#else
/*****************************************************************************
convert a PAM error to a NT status32 code
*****************************************************************************/
NTSTATUS pam_to_nt_status(int pam_error)
{
if (pam_error == 0) return NT_STATUS_OK;
return NT_STATUS_UNSUCCESSFUL;
}
/*****************************************************************************
convert an NT status32 code to a PAM error
*****************************************************************************/
int nt_status_to_pam(NTSTATUS nt_status)
{
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_OK)) return 0;
return 4; /* PAM_SYSTEM_ERR */
}
#endif

109
source/lib/pidfile.c Normal file
View File

@@ -0,0 +1,109 @@
/* this code is broken - there is a race condition with the unlink (tridge) */
/*
Unix SMB/CIFS implementation.
pidfile handling
Copyright (C) Andrew Tridgell 1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#ifndef O_NONBLOCK
#define O_NONBLOCK
#endif
/* return the pid in a pidfile. return 0 if the process (or pidfile)
does not exist */
pid_t pidfile_pid(const char *name)
{
int fd;
char pidstr[20];
unsigned ret;
pstring pidFile;
slprintf(pidFile, sizeof(pidFile)-1, "%s/%s.pid", lp_piddir(), name);
fd = sys_open(pidFile, O_NONBLOCK | O_RDONLY, 0644);
if (fd == -1) {
return 0;
}
ZERO_ARRAY(pidstr);
if (read(fd, pidstr, sizeof(pidstr)-1) <= 0) {
goto noproc;
}
ret = atoi(pidstr);
if (!process_exists((pid_t)ret)) {
goto noproc;
}
if (fcntl_lock(fd,SMB_F_SETLK,0,1,F_RDLCK)) {
/* we could get the lock - it can't be a Samba process */
goto noproc;
}
close(fd);
return (pid_t)ret;
noproc:
close(fd);
unlink(pidFile);
return 0;
}
/* create a pid file in the pid directory. open it and leave it locked */
void pidfile_create(const char *name)
{
int fd;
char buf[20];
pstring pidFile;
pid_t pid;
slprintf(pidFile, sizeof(pidFile)-1, "%s/%s.pid", lp_piddir(), name);
pid = pidfile_pid(name);
if (pid != 0) {
DEBUG(0,("ERROR: %s is already running. File %s exists and process id %d is running.\n",
name, pidFile, (int)pid));
exit(1);
}
fd = sys_open(pidFile, O_NONBLOCK | O_CREAT | O_WRONLY | O_EXCL, 0644);
if (fd == -1) {
DEBUG(0,("ERROR: can't open %s: Error was %s\n", pidFile,
strerror(errno)));
exit(1);
}
if (fcntl_lock(fd,SMB_F_SETLK,0,1,F_WRLCK)==False) {
DEBUG(0,("ERROR: %s : fcntl lock of file %s failed. Error was %s\n",
name, pidFile, strerror(errno)));
exit(1);
}
memset(buf, 0, sizeof(buf));
slprintf(buf, sizeof(buf) - 1, "%u\n", (unsigned int) getpid());
if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) {
DEBUG(0,("ERROR: can't write to file %s: %s\n",
pidFile, strerror(errno)));
exit(1);
}
/* Leave pid file open & locked for the duration... */
}

43
source/lib/popt/CHANGES Normal file
View File

@@ -0,0 +1,43 @@
1.3 ->
- heavy dose of const's
- poptParseArgvString() now NULL terminates the list
1.2.3 -> 1.3
- added support for single -
- misc bug fixes
- portability improvements
1.2.2 -> 1.2.3
- fixed memset() in help message generation (Dale Hawkins)
- added extern "C" stuff to popt.h for C++ compilers (Dale Hawkins)
- const'ified poptParseArgvString (Jeff Garzik)
1.2.1 -> 1.2.2
- fixed bug in chaind alias happens which seems to have only
affected --triggers in rpm
- added POPT_ARG_VAL
- popt.3 installed by default
1.2 -> 1.2.1
- added POPT_ARG_INTL_DOMAIN (Elliot Lee)
- updated Makefile's to be more GNUish (Elliot Lee)
1.1 -> 1.2
- added popt.3 man page (Robert Lynch)
- don't use mmap anymore (its lack of portability isn't worth the
trouble)
- added test script
- added support for exec
- removed support for *_POPT_ALIASES env variable -- it was a bad
idea
- reorganized into multiple source files
- added automatic help generation, POPT_AUTOHELP
- added table callbacks
- added table inclusion
- updated man page for new features
- added test scripts
1.0 -> 1.1
- moved to autoconf (Fred Fish)
- added STRERROR replacement (Norbert Warmuth)
- added const keywords (Bruce Perens)

22
source/lib/popt/COPYING Normal file
View File

@@ -0,0 +1,22 @@
Copyright (c) 1998 Red Hat Software
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of the X Consortium shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the X Consortium.

18
source/lib/popt/README Normal file
View File

@@ -0,0 +1,18 @@
This is the popt command line option parsing library. While it is similiar
to getopt(3), it contains a number of enhancements, including:
1) popt is fully reentrant
2) popt can parse arbitrary argv[] style arrays while
getopt(2) makes this quite difficult
3) popt allows users to alias command line arguments
4) popt provides convience functions for parsting strings
into argv[] style arrays
popt is used by rpm, the Red Hat install program, and many other Red Hat
utilities, all of which provide excellent examples of how to use popt.
Complete documentation on popt is available in popt.ps (included in this
tarball), which is excerpted with permission from the book "Linux
Application Development" by Michael K. Johnson and Erik Troan (availble
from Addison Wesley in May, 1998).
Comments on popt should be addressed to ewt@redhat.com.

0
source/lib/popt/dummy.in Normal file
View File

46
source/lib/popt/findme.c Normal file
View File

@@ -0,0 +1,46 @@
/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions, available from
ftp://ftp.redhat.com/pub/code/popt */
#include "system.h"
#include "findme.h"
const char * findProgramPath(const char * argv0) {
char * path = getenv("PATH");
char * pathbuf;
char * start, * chptr;
char * buf, *local = NULL;
/* If there is a / in the argv[0], it has to be an absolute
path */
if (strchr(argv0, '/'))
return xstrdup(argv0);
if (!path) return NULL;
local = start = pathbuf = malloc(strlen(path) + 1);
buf = malloc(strlen(path) + strlen(argv0) + 2);
strcpy(pathbuf, path);
chptr = NULL;
do {
if ((chptr = strchr(start, ':')))
*chptr = '\0';
sprintf(buf, "%s/%s", start, argv0);
if (!access(buf, X_OK)) {
if (local) free(local);
return buf;
}
if (chptr)
start = chptr + 1;
else
start = NULL;
} while (start && *start);
free(buf);
if (local) free(local);
return NULL;
}

10
source/lib/popt/findme.h Normal file
View File

@@ -0,0 +1,10 @@
/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions, available from
ftp://ftp.redhat.com/pub/code/popt */
#ifndef H_FINDME
#define H_FINDME
const char * findProgramPath(const char * argv0);
#endif

782
source/lib/popt/popt.c Normal file
View File

@@ -0,0 +1,782 @@
/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions, available from
ftp://ftp.redhat.com/pub/code/popt */
#include "system.h"
#include "findme.h"
#include "poptint.h"
#ifndef HAVE_STRERROR
static char * strerror(int errno) {
extern int sys_nerr;
extern char * sys_errlist[];
if ((0 <= errno) && (errno < sys_nerr))
return sys_errlist[errno];
else
return POPT_("unknown errno");
}
#endif
void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) {
if (con->execPath) xfree(con->execPath);
con->execPath = xstrdup(path);
con->execAbsolute = allowAbsolute;
}
static void invokeCallbacks(poptContext con, const struct poptOption * table,
int post) {
const struct poptOption * opt = table;
poptCallbackType cb;
while (opt->longName || opt->shortName || opt->arg) {
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
invokeCallbacks(con, opt->arg, post);
} else if (((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) &&
((!post && (opt->argInfo & POPT_CBFLAG_PRE)) ||
( post && (opt->argInfo & POPT_CBFLAG_POST)))) {
cb = (poptCallbackType)opt->arg;
cb(con, post ? POPT_CALLBACK_REASON_POST : POPT_CALLBACK_REASON_PRE,
NULL, NULL, opt->descrip);
}
opt++;
}
}
poptContext poptGetContext(const char * name, int argc, const char ** argv,
const struct poptOption * options, int flags) {
poptContext con = malloc(sizeof(*con));
memset(con, 0, sizeof(*con));
con->os = con->optionStack;
con->os->argc = argc;
con->os->argv = argv;
con->os->argb = NULL;
if (!(flags & POPT_CONTEXT_KEEP_FIRST))
con->os->next = 1; /* skip argv[0] */
con->leftovers = calloc( (argc + 1), sizeof(char *) );
con->options = options;
con->aliases = NULL;
con->numAliases = 0;
con->flags = flags;
con->execs = NULL;
con->numExecs = 0;
con->finalArgvAlloced = argc * 2;
con->finalArgv = calloc( con->finalArgvAlloced, sizeof(*con->finalArgv) );
con->execAbsolute = 1;
con->arg_strip = NULL;
if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
con->flags |= POPT_CONTEXT_POSIXMEHARDER;
if (name)
con->appName = strcpy(malloc(strlen(name) + 1), name);
invokeCallbacks(con, con->options, 0);
return con;
}
static void cleanOSE(struct optionStackEntry *os)
{
if (os->nextArg) {
xfree(os->nextArg);
os->nextArg = NULL;
}
if (os->argv) {
xfree(os->argv);
os->argv = NULL;
}
if (os->argb) {
PBM_FREE(os->argb);
os->argb = NULL;
}
}
void poptResetContext(poptContext con) {
int i;
while (con->os > con->optionStack) {
cleanOSE(con->os--);
}
if (con->os->argb) {
PBM_FREE(con->os->argb);
con->os->argb = NULL;
}
con->os->currAlias = NULL;
con->os->nextCharArg = NULL;
con->os->nextArg = NULL;
con->os->next = 1; /* skip argv[0] */
con->numLeftovers = 0;
con->nextLeftover = 0;
con->restLeftover = 0;
con->doExec = NULL;
for (i = 0; i < con->finalArgvCount; i++) {
if (con->finalArgv[i]) {
xfree(con->finalArgv[i]);
con->finalArgv[i] = NULL;
}
}
con->finalArgvCount = 0;
if (con->arg_strip) {
PBM_FREE(con->arg_strip);
con->arg_strip = NULL;
}
}
/* Only one of longName, shortName may be set at a time */
static int handleExec(poptContext con, char * longName, char shortName) {
int i;
i = con->numExecs - 1;
if (longName) {
while (i >= 0 && (!con->execs[i].longName ||
strcmp(con->execs[i].longName, longName))) i--;
} else {
while (i >= 0 &&
con->execs[i].shortName != shortName) i--;
}
if (i < 0) return 0;
if (con->flags & POPT_CONTEXT_NO_EXEC)
return 1;
if (con->doExec == NULL) {
con->doExec = con->execs + i;
return 1;
}
/* We already have an exec to do; remember this option for next
time 'round */
if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) {
con->finalArgvAlloced += 10;
con->finalArgv = realloc(con->finalArgv,
sizeof(*con->finalArgv) * con->finalArgvAlloced);
}
i = con->finalArgvCount++;
{ char *s = malloc((longName ? strlen(longName) : 0) + 3);
if (longName)
sprintf(s, "--%s", longName);
else
sprintf(s, "-%c", shortName);
con->finalArgv[i] = s;
}
return 1;
}
/* Only one of longName, shortName may be set at a time */
static int handleAlias(poptContext con, const char * longName, char shortName,
/*@keep@*/ const char * nextCharArg) {
int i;
if (con->os->currAlias && con->os->currAlias->longName && longName &&
!strcmp(con->os->currAlias->longName, longName))
return 0;
if (con->os->currAlias && shortName &&
shortName == con->os->currAlias->shortName)
return 0;
i = con->numAliases - 1;
if (longName) {
while (i >= 0 && (!con->aliases[i].longName ||
strcmp(con->aliases[i].longName, longName))) i--;
} else {
while (i >= 0 &&
con->aliases[i].shortName != shortName) i--;
}
if (i < 0) return 0;
if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH)
return POPT_ERROR_OPTSTOODEEP;
if (nextCharArg && *nextCharArg)
con->os->nextCharArg = nextCharArg;
con->os++;
con->os->next = 0;
con->os->stuffed = 0;
con->os->nextArg = NULL;
con->os->nextCharArg = NULL;
con->os->currAlias = con->aliases + i;
poptDupArgv(con->os->currAlias->argc, con->os->currAlias->argv,
&con->os->argc, &con->os->argv);
con->os->argb = NULL;
return 1;
}
static void execCommand(poptContext con) {
const char ** argv;
int pos = 0;
const char * script = con->doExec->script;
argv = malloc(sizeof(*argv) *
(6 + con->numLeftovers + con->finalArgvCount));
if (!con->execAbsolute && strchr(script, '/')) return;
if (!strchr(script, '/') && con->execPath) {
char *s = malloc(strlen(con->execPath) + strlen(script) + 2);
sprintf(s, "%s/%s", con->execPath, script);
argv[pos] = s;
} else {
argv[pos] = script;
}
pos++;
argv[pos] = findProgramPath(con->os->argv[0]);
if (argv[pos]) pos++;
argv[pos++] = ";";
memcpy(argv + pos, con->finalArgv, sizeof(*argv) * con->finalArgvCount);
pos += con->finalArgvCount;
if (con->numLeftovers) {
argv[pos++] = "--";
memcpy(argv + pos, con->leftovers, sizeof(*argv) * con->numLeftovers);
pos += con->numLeftovers;
}
argv[pos++] = NULL;
#ifdef __hpux
setresuid(getuid(), getuid(),-1);
#else
/*
* XXX " ... on BSD systems setuid() should be preferred over setreuid()"
* XXX sez' Timur Bakeyev <mc@bat.ru>
* XXX from Norbert Warmuth <nwarmuth@privat.circular.de>
*/
#if defined(HAVE_SETUID)
setuid(getuid());
#elif defined (HAVE_SETREUID)
setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */
#else
; /* Can't drop privileges */
#endif
#endif
execvp(argv[0], (char *const *)argv);
}
/*@observer@*/ static const struct poptOption *
findOption(const struct poptOption * table, const char * longName,
char shortName,
/*@out@*/ poptCallbackType * callback, /*@out@*/ const void ** callbackData,
int singleDash)
{
const struct poptOption * opt = table;
const struct poptOption * opt2;
const struct poptOption * cb = NULL;
/* This happens when a single - is given */
if (singleDash && !shortName && !*longName)
shortName = '-';
while (opt->longName || opt->shortName || opt->arg) {
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
opt2 = findOption(opt->arg, longName, shortName, callback,
callbackData, singleDash);
if (opt2) {
if (*callback && !*callbackData)
*callbackData = opt->descrip;
return opt2;
}
} else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) {
cb = opt;
} else if (longName && opt->longName &&
(!singleDash || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) &&
!strcmp(longName, opt->longName)) {
break;
} else if (shortName && shortName == opt->shortName) {
break;
}
opt++;
}
if (!opt->longName && !opt->shortName) return NULL;
*callbackData = NULL;
*callback = NULL;
if (cb) {
*callback = (poptCallbackType)cb->arg;
if (!(cb->argInfo & POPT_CBFLAG_INC_DATA))
*callbackData = cb->descrip;
}
return opt;
}
static const char *findNextArg(poptContext con, unsigned argx, int delete)
{
struct optionStackEntry * os = con->os;
const char * arg;
do {
int i;
arg = NULL;
while (os->next == os->argc && os > con->optionStack) os--;
if (os->next == os->argc && os == con->optionStack) break;
for (i = os->next; i < os->argc; i++) {
if (os->argb && PBM_ISSET(i, os->argb)) continue;
if (*os->argv[i] == '-') continue;
if (--argx > 0) continue;
arg = os->argv[i];
if (delete) {
if (os->argb == NULL) os->argb = PBM_ALLOC(os->argc);
PBM_SET(i, os->argb);
}
break;
}
if (os > con->optionStack) os--;
} while (arg == NULL);
return arg;
}
static /*@only@*/ const char * expandNextArg(poptContext con, const char * s)
{
const char *a;
size_t alen;
char *t, *te;
size_t tn = strlen(s) + 1;
char c;
te = t = malloc(tn);;
while ((c = *s++) != '\0') {
switch (c) {
#if 0 /* XXX can't do this */
case '\\': /* escape */
c = *s++;
break;
#endif
case '!':
if (!(s[0] == '#' && s[1] == ':' && s[2] == '+'))
break;
if ((a = findNextArg(con, 1, 1)) == NULL)
break;
s += 3;
alen = strlen(a);
tn += alen;
*te = '\0';
t = realloc(t, tn);
te = t + strlen(t);
strncpy(te, a, alen); te += alen;
continue;
/*@notreached@*/ break;
default:
break;
}
*te++ = c;
}
*te = '\0';
t = realloc(t, strlen(t)+1); /* XXX memory leak, hard to plug */
return t;
}
static void poptStripArg(poptContext con, int which)
{
if(con->arg_strip == NULL) {
con->arg_strip = PBM_ALLOC(con->optionStack[0].argc);
}
PBM_SET(which, con->arg_strip);
}
/* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
int poptGetNextOpt(poptContext con)
{
const struct poptOption * opt = NULL;
int done = 0;
/* looks a bit tricky to get rid of alloca properly in this fn */
#if HAVE_ALLOCA_H
#define ALLOCA(x) alloca(x)
#else
#define ALLOCA(x) malloc(x)
#endif
while (!done) {
const char * origOptString = NULL;
poptCallbackType cb = NULL;
const void * cbData = NULL;
const char * longArg = NULL;
int canstrip = 0;
while (!con->os->nextCharArg && con->os->next == con->os->argc
&& con->os > con->optionStack) {
cleanOSE(con->os--);
}
if (!con->os->nextCharArg && con->os->next == con->os->argc) {
invokeCallbacks(con, con->options, 1);
if (con->doExec) execCommand(con);
return -1;
}
/* Process next long option */
if (!con->os->nextCharArg) {
char * localOptString, * optString;
int thisopt;
if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) {
con->os->next++;
continue;
}
thisopt=con->os->next;
origOptString = con->os->argv[con->os->next++];
if (con->restLeftover || *origOptString != '-') {
con->leftovers[con->numLeftovers++] = origOptString;
if (con->flags & POPT_CONTEXT_POSIXMEHARDER)
con->restLeftover = 1;
continue;
}
/* Make a copy we can hack at */
localOptString = optString =
strcpy(ALLOCA(strlen(origOptString) + 1),
origOptString);
if (!optString[0])
return POPT_ERROR_BADOPT;
if (optString[1] == '-' && !optString[2]) {
con->restLeftover = 1;
continue;
} else {
char *oe;
int singleDash;
optString++;
if (*optString == '-')
singleDash = 0, optString++;
else
singleDash = 1;
/* XXX aliases with arg substitution need "--alias=arg" */
if (handleAlias(con, optString, '\0', NULL))
continue;
if (handleExec(con, optString, '\0'))
continue;
/* Check for "--long=arg" option. */
for (oe = optString; *oe && *oe != '='; oe++)
;
if (*oe == '=') {
*oe++ = '\0';
/* XXX longArg is mapped back to persistent storage. */
longArg = origOptString + (oe - localOptString);
}
opt = findOption(con->options, optString, '\0', &cb, &cbData,
singleDash);
if (!opt && !singleDash)
return POPT_ERROR_BADOPT;
}
if (!opt) {
con->os->nextCharArg = origOptString + 1;
} else {
if(con->os == con->optionStack &&
opt->argInfo & POPT_ARGFLAG_STRIP) {
canstrip = 1;
poptStripArg(con, thisopt);
}
}
}
/* Process next short option */
if (con->os->nextCharArg) {
origOptString = con->os->nextCharArg;
con->os->nextCharArg = NULL;
if (handleAlias(con, NULL, *origOptString,
origOptString + 1)) {
origOptString++;
continue;
}
if (handleExec(con, NULL, *origOptString))
continue;
opt = findOption(con->options, NULL, *origOptString, &cb,
&cbData, 0);
if (!opt)
return POPT_ERROR_BADOPT;
origOptString++;
if (*origOptString)
con->os->nextCharArg = origOptString;
}
if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) {
*((int *)opt->arg) = 1;
} else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) {
if (opt->arg)
*((int *) opt->arg) = opt->val;
} else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
if (con->os->nextArg) {
xfree(con->os->nextArg);
con->os->nextArg = NULL;
}
if (longArg) {
con->os->nextArg = expandNextArg(con, longArg);
} else if (con->os->nextCharArg) {
con->os->nextArg = expandNextArg(con, con->os->nextCharArg);
con->os->nextCharArg = NULL;
} else {
while (con->os->next == con->os->argc &&
con->os > con->optionStack) {
cleanOSE(con->os--);
}
if (con->os->next == con->os->argc)
return POPT_ERROR_NOARG;
/* make sure this isn't part of a short arg or the
result of an alias expansion */
if(con->os == con->optionStack &&
opt->argInfo & POPT_ARGFLAG_STRIP &&
canstrip) {
poptStripArg(con, con->os->next);
}
con->os->nextArg = expandNextArg(con, con->os->argv[con->os->next++]);
}
if (opt->arg) {
long aLong;
char *end;
switch (opt->argInfo & POPT_ARG_MASK) {
case POPT_ARG_STRING:
/* XXX memory leak, hard to plug */
*((const char **) opt->arg) = xstrdup(con->os->nextArg);
break;
case POPT_ARG_INT:
case POPT_ARG_LONG:
aLong = strtol(con->os->nextArg, &end, 0);
if (!(end && *end == '\0'))
return POPT_ERROR_BADNUMBER;
if (aLong == LONG_MIN || aLong == LONG_MAX)
return POPT_ERROR_OVERFLOW;
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) {
*((long *) opt->arg) = aLong;
} else {
if (aLong > INT_MAX || aLong < INT_MIN)
return POPT_ERROR_OVERFLOW;
*((int *) opt->arg) = aLong;
}
break;
default:
fprintf(stdout, POPT_("option type (%d) not implemented in popt\n"),
opt->argInfo & POPT_ARG_MASK);
exit(EXIT_FAILURE);
}
}
}
if (cb)
cb(con, POPT_CALLBACK_REASON_OPTION, opt, con->os->nextArg, cbData);
else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL))
done = 1;
if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) {
con->finalArgvAlloced += 10;
con->finalArgv = realloc(con->finalArgv,
sizeof(*con->finalArgv) * con->finalArgvAlloced);
}
{ char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + 3);
if (opt->longName)
sprintf(s, "--%s", opt->longName);
else
sprintf(s, "-%c", opt->shortName);
con->finalArgv[con->finalArgvCount++] = s;
}
if (opt->arg && (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE
&& (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL) {
con->finalArgv[con->finalArgvCount++] = xstrdup(con->os->nextArg);
}
}
return opt->val;
}
const char * poptGetOptArg(poptContext con) {
const char * ret = con->os->nextArg;
con->os->nextArg = NULL;
return ret;
}
const char * poptGetArg(poptContext con) {
if (con->numLeftovers == con->nextLeftover) return NULL;
return con->leftovers[con->nextLeftover++];
}
const char * poptPeekArg(poptContext con) {
if (con->numLeftovers == con->nextLeftover) return NULL;
return con->leftovers[con->nextLeftover];
}
const char ** poptGetArgs(poptContext con) {
if (con->numLeftovers == con->nextLeftover) return NULL;
/* some apps like [like RPM ;-) ] need this NULL terminated */
con->leftovers[con->numLeftovers] = NULL;
return (con->leftovers + con->nextLeftover);
}
void poptFreeContext(poptContext con) {
int i;
poptResetContext(con);
if (con->os->argb) free(con->os->argb);
for (i = 0; i < con->numAliases; i++) {
if (con->aliases[i].longName) xfree(con->aliases[i].longName);
free(con->aliases[i].argv);
}
for (i = 0; i < con->numExecs; i++) {
if (con->execs[i].longName) xfree(con->execs[i].longName);
xfree(con->execs[i].script);
}
if (con->execs) xfree(con->execs);
free(con->leftovers);
free(con->finalArgv);
if (con->appName) xfree(con->appName);
if (con->aliases) free(con->aliases);
if (con->otherHelp) xfree(con->otherHelp);
if (con->execPath) xfree(con->execPath);
if (con->arg_strip) PBM_FREE(con->arg_strip);
free(con);
}
int poptAddAlias(poptContext con, struct poptAlias newAlias,
/*@unused@*/ int flags)
{
int aliasNum = con->numAliases++;
struct poptAlias * alias;
/* SunOS won't realloc(NULL, ...) */
if (!con->aliases)
con->aliases = malloc(sizeof(newAlias) * con->numAliases);
else
con->aliases = realloc(con->aliases,
sizeof(newAlias) * con->numAliases);
alias = con->aliases + aliasNum;
alias->longName = (newAlias.longName)
? strcpy(malloc(strlen(newAlias.longName) + 1), newAlias.longName)
: NULL;
alias->shortName = newAlias.shortName;
alias->argc = newAlias.argc;
alias->argv = newAlias.argv;
return 0;
}
const char * poptBadOption(poptContext con, int flags) {
struct optionStackEntry * os;
if (flags & POPT_BADOPTION_NOALIAS)
os = con->optionStack;
else
os = con->os;
return os->argv[os->next - 1];
}
#define POPT_ERROR_NOARG -10
#define POPT_ERROR_BADOPT -11
#define POPT_ERROR_OPTSTOODEEP -13
#define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
#define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
const char *poptStrerror(const int error) {
switch (error) {
case POPT_ERROR_NOARG:
return POPT_("missing argument");
case POPT_ERROR_BADOPT:
return POPT_("unknown option");
case POPT_ERROR_OPTSTOODEEP:
return POPT_("aliases nested too deeply");
case POPT_ERROR_BADQUOTE:
return POPT_("error in paramter quoting");
case POPT_ERROR_BADNUMBER:
return POPT_("invalid numeric value");
case POPT_ERROR_OVERFLOW:
return POPT_("number too large or too small");
case POPT_ERROR_ERRNO:
return strerror(errno);
default:
return POPT_("unknown error");
}
}
int poptStuffArgs(poptContext con, const char ** argv) {
int argc;
if ((con->os - con->optionStack) == POPT_OPTION_DEPTH)
return POPT_ERROR_OPTSTOODEEP;
for (argc = 0; argv[argc]; argc++)
;
con->os++;
con->os->next = 0;
con->os->nextArg = NULL;
con->os->nextCharArg = NULL;
con->os->currAlias = NULL;
poptDupArgv(argc, argv, &con->os->argc, &con->os->argv);
con->os->argb = NULL;
con->os->stuffed = 1;
return 0;
}
const char * poptGetInvocationName(poptContext con) {
return con->os->argv[0];
}
int poptStrippedArgv(poptContext con, int argc, char **argv)
{
int i,j=1, numargs=argc;
for(i=1; i<argc; i++) {
if(PBM_ISSET(i, con->arg_strip)) {
numargs--;
}
}
for(i=1; i<argc; i++) {
if(PBM_ISSET(i, con->arg_strip)) {
continue;
} else {
if(j<numargs) {
argv[j++]=argv[i];
} else {
argv[j++]='\0';
}
}
}
return(numargs);
}

130
source/lib/popt/popt.h Normal file
View File

@@ -0,0 +1,130 @@
/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions, available from
ftp://ftp.redhat.com/pub/code/popt */
#ifndef H_POPT
#define H_POPT
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h> /* for FILE * */
#define POPT_OPTION_DEPTH 10
#define POPT_ARG_NONE 0
#define POPT_ARG_STRING 1
#define POPT_ARG_INT 2
#define POPT_ARG_LONG 3
#define POPT_ARG_INCLUDE_TABLE 4 /* arg points to table */
#define POPT_ARG_CALLBACK 5 /* table-wide callback... must be
set first in table; arg points
to callback, descrip points to
callback data to pass */
#define POPT_ARG_INTL_DOMAIN 6 /* set the translation domain
for this table and any
included tables; arg points
to the domain string */
#define POPT_ARG_VAL 7 /* arg should take value val */
#define POPT_ARG_MASK 0x0000FFFF
#define POPT_ARGFLAG_ONEDASH 0x80000000 /* allow -longoption */
#define POPT_ARGFLAG_DOC_HIDDEN 0x40000000 /* don't show in help/usage */
#define POPT_ARGFLAG_STRIP 0x20000000 /* strip this arg from argv (only applies to long args) */
#define POPT_CBFLAG_PRE 0x80000000 /* call the callback before parse */
#define POPT_CBFLAG_POST 0x40000000 /* call the callback after parse */
#define POPT_CBFLAG_INC_DATA 0x20000000 /* use data from the include line,
not the subtable */
#define POPT_ERROR_NOARG -10
#define POPT_ERROR_BADOPT -11
#define POPT_ERROR_OPTSTOODEEP -13
#define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
#define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
#define POPT_ERROR_BADNUMBER -17
#define POPT_ERROR_OVERFLOW -18
/* poptBadOption() flags */
#define POPT_BADOPTION_NOALIAS (1 << 0) /* don't go into an alias */
/* poptGetContext() flags */
#define POPT_CONTEXT_NO_EXEC (1 << 0) /* ignore exec expansions */
#define POPT_CONTEXT_KEEP_FIRST (1 << 1) /* pay attention to argv[0] */
#define POPT_CONTEXT_POSIXMEHARDER (1 << 2) /* options can't follow args */
struct poptOption {
/*@observer@*/ /*@null@*/ const char * longName; /* may be NULL */
char shortName; /* may be '\0' */
int argInfo;
/*@shared@*/ /*@null@*/ void * arg; /* depends on argInfo */
int val; /* 0 means don't return, just update flag */
/*@shared@*/ /*@null@*/ const char * descrip; /* description for autohelp -- may be NULL */
/*@shared@*/ /*@null@*/ const char * argDescrip; /* argument description for autohelp */
};
struct poptAlias {
/*@owned@*/ /*@null@*/ const char * longName; /* may be NULL */
char shortName; /* may be '\0' */
int argc;
/*@owned@*/ const char ** argv; /* must be free()able */
};
extern struct poptOption poptHelpOptions[];
#define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \
0, "Help options", NULL },
typedef struct poptContext_s * poptContext;
#ifndef __cplusplus
typedef struct poptOption * poptOption;
#endif
enum poptCallbackReason { POPT_CALLBACK_REASON_PRE,
POPT_CALLBACK_REASON_POST,
POPT_CALLBACK_REASON_OPTION };
typedef void (*poptCallbackType)(poptContext con,
enum poptCallbackReason reason,
const struct poptOption * opt,
const char * arg, const void * data);
/*@only@*/ poptContext poptGetContext(/*@keep@*/ const char * name,
int argc, /*@keep@*/ const char ** argv,
/*@keep@*/ const struct poptOption * options, int flags);
void poptResetContext(poptContext con);
/* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
int poptGetNextOpt(poptContext con);
/* returns NULL if no argument is available */
/*@observer@*/ /*@null@*/ const char * poptGetOptArg(poptContext con);
/* returns NULL if no more options are available */
/*@observer@*/ /*@null@*/ const char * poptGetArg(poptContext con);
/*@observer@*/ /*@null@*/ const char * poptPeekArg(poptContext con);
/*@observer@*/ /*@null@*/ const char ** poptGetArgs(poptContext con);
/* returns the option which caused the most recent error */
/*@observer@*/ const char * poptBadOption(poptContext con, int flags);
void poptFreeContext( /*@only@*/ poptContext con);
int poptStuffArgs(poptContext con, /*@keep@*/ const char ** argv);
int poptAddAlias(poptContext con, struct poptAlias alias, int flags);
int poptReadConfigFile(poptContext con, const char * fn);
/* like above, but reads /etc/popt and $HOME/.popt along with environment
vars */
int poptReadDefaultConfig(poptContext con, int useEnv);
/* argv should be freed -- this allows ', ", and \ quoting, but ' is treated
the same as " and both may include \ quotes */
int poptDupArgv(int argc, const char **argv,
/*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr);
int poptParseArgvString(const char * s,
/*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr);
/*@observer@*/ const char *poptStrerror(const int error);
void poptSetExecPath(poptContext con, const char * path, int allowAbsolute);
void poptPrintHelp(poptContext con, FILE * f, int flags);
void poptPrintUsage(poptContext con, FILE * f, int flags);
void poptSetOtherOptionHelp(poptContext con, const char * text);
/*@observer@*/ const char * poptGetInvocationName(poptContext con);
/* shuffles argv pointers to remove stripped args, returns new argc */
int poptStrippedArgv(poptContext con, int argc, char **argv);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,142 @@
/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions, available from
ftp://ftp.redhat.com/pub/code/popt */
#include "system.h"
#include "poptint.h"
static void configLine(poptContext con, char * line) {
int nameLength = strlen(con->appName);
char * opt;
struct poptAlias alias;
char * entryType;
char * longName = NULL;
char shortName = '\0';
if (strncmp(line, con->appName, nameLength)) return;
line += nameLength;
if (!*line || !isspace(*line)) return;
while (*line && isspace(*line)) line++;
entryType = line;
while (!*line || !isspace(*line)) line++;
*line++ = '\0';
while (*line && isspace(*line)) line++;
if (!*line) return;
opt = line;
while (!*line || !isspace(*line)) line++;
*line++ = '\0';
while (*line && isspace(*line)) line++;
if (!*line) return;
if (opt[0] == '-' && opt[1] == '-')
longName = opt + 2;
else if (opt[0] == '-' && !opt[2])
shortName = opt[1];
if (!strcmp(entryType, "alias")) {
if (poptParseArgvString(line, &alias.argc, &alias.argv)) return;
alias.longName = longName, alias.shortName = shortName;
poptAddAlias(con, alias, 0);
} else if (!strcmp(entryType, "exec")) {
con->execs = realloc(con->execs,
sizeof(*con->execs) * (con->numExecs + 1));
if (longName)
con->execs[con->numExecs].longName = xstrdup(longName);
else
con->execs[con->numExecs].longName = NULL;
con->execs[con->numExecs].shortName = shortName;
con->execs[con->numExecs].script = xstrdup(line);
con->numExecs++;
}
}
int poptReadConfigFile(poptContext con, const char * fn) {
char * file=NULL, * chptr, * end;
char * buf=NULL, * dst;
int fd, rc;
int fileLength;
fd = open(fn, O_RDONLY);
if (fd < 0) {
if (errno == ENOENT)
return 0;
else
return POPT_ERROR_ERRNO;
}
fileLength = lseek(fd, 0, SEEK_END);
(void) lseek(fd, 0, 0);
file = malloc(fileLength + 1);
if (read(fd, file, fileLength) != fileLength) {
rc = errno;
close(fd);
errno = rc;
if (file) free(file);
return POPT_ERROR_ERRNO;
}
close(fd);
dst = buf = malloc(fileLength + 1);
chptr = file;
end = (file + fileLength);
while (chptr < end) {
switch (*chptr) {
case '\n':
*dst = '\0';
dst = buf;
while (*dst && isspace(*dst)) dst++;
if (*dst && *dst != '#') {
configLine(con, dst);
}
chptr++;
break;
case '\\':
*dst++ = *chptr++;
if (chptr < end) {
if (*chptr == '\n')
dst--, chptr++;
/* \ at the end of a line does not insert a \n */
else
*dst++ = *chptr++;
}
break;
default:
*dst++ = *chptr++;
break;
}
}
free(file);
free(buf);
return 0;
}
int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv) {
char * fn, * home;
int rc;
if (!con->appName) return 0;
rc = poptReadConfigFile(con, "/etc/popt");
if (rc) return rc;
if (getuid() != geteuid()) return 0;
if ((home = getenv("HOME"))) {
fn = malloc(strlen(home) + 20);
strcpy(fn, home);
strcat(fn, "/.popt");
rc = poptReadConfigFile(con, fn);
free(fn);
if (rc) return rc;
}
return 0;
}

301
source/lib/popt/popthelp.c Normal file
View File

@@ -0,0 +1,301 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions, available from
ftp://ftp.redhat.com/pub/code/popt */
#include "system.h"
#include "poptint.h"
static void displayArgs(poptContext con,
/*@unused@*/ enum poptCallbackReason foo,
struct poptOption * key,
/*@unused@*/ const char * arg, /*@unused@*/ void * data) {
if (key->shortName== '?')
poptPrintHelp(con, stdout, 0);
else
poptPrintUsage(con, stdout, 0);
exit(0);
}
struct poptOption poptHelpOptions[] = {
{ NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
{ "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
{ "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
{ NULL, '\0', 0, NULL, 0, NULL, NULL }
} ;
/*@observer@*/ /*@null@*/ static const char *
getTableTranslationDomain(const struct poptOption *table)
{
const struct poptOption *opt;
for(opt = table;
opt->longName || opt->shortName || opt->arg;
opt++) {
if(opt->argInfo == POPT_ARG_INTL_DOMAIN)
return opt->arg;
}
return NULL;
}
/*@observer@*/ /*@null@*/ static const char *
getArgDescrip(const struct poptOption * opt, const char *translation_domain)
{
if (!(opt->argInfo & POPT_ARG_MASK)) return NULL;
if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2))
if (opt->argDescrip) return POPT_(opt->argDescrip);
if (opt->argDescrip) return D_(translation_domain, opt->argDescrip);
return POPT_("ARG");
}
static void singleOptionHelp(FILE * f, int maxLeftCol,
const struct poptOption * opt,
const char *translation_domain) {
int indentLength = maxLeftCol + 5;
int lineLength = 79 - indentLength;
const char * help = D_(translation_domain, opt->descrip);
int helpLength;
const char * ch;
char format[10];
char * left;
const char * argDescrip = getArgDescrip(opt, translation_domain);
left = malloc(maxLeftCol + 1);
*left = '\0';
if (opt->longName && opt->shortName)
sprintf(left, "-%c, --%s", opt->shortName, opt->longName);
else if (opt->shortName)
sprintf(left, "-%c", opt->shortName);
else if (opt->longName)
sprintf(left, "--%s", opt->longName);
if (!*left) return ;
if (argDescrip) {
strcat(left, "=");
strcat(left, argDescrip);
}
if (help)
fprintf(f," %-*s ", maxLeftCol, left);
else {
fprintf(f," %s\n", left);
goto out;
}
helpLength = strlen(help);
while (helpLength > lineLength) {
ch = help + lineLength - 1;
while (ch > help && !isspace(*ch)) ch--;
if (ch == help) break; /* give up */
while (ch > (help + 1) && isspace(*ch)) ch--;
ch++;
sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), indentLength);
fprintf(f, format, help, " ");
help = ch;
while (isspace(*help) && *help) help++;
helpLength = strlen(help);
}
if (helpLength) fprintf(f, "%s\n", help);
out:
free(left);
}
static int maxArgWidth(const struct poptOption * opt,
const char * translation_domain) {
int max = 0;
int this;
const char * s;
while (opt->longName || opt->shortName || opt->arg) {
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
this = maxArgWidth(opt->arg, translation_domain);
if (this > max) max = this;
} else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
this = opt->shortName ? 2 : 0;
if (opt->longName) {
if (this) this += 2;
this += strlen(opt->longName) + 2;
}
s = getArgDescrip(opt, translation_domain);
if (s)
this += strlen(s) + 1;
if (this > max) max = this;
}
opt++;
}
return max;
}
static void singleTableHelp(FILE * f, const struct poptOption * table,
int left,
const char *translation_domain) {
const struct poptOption * opt;
const char *sub_transdom;
opt = table;
while (opt->longName || opt->shortName || opt->arg) {
if ((opt->longName || opt->shortName) &&
!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
singleOptionHelp(f, left, opt, translation_domain);
opt++;
}
opt = table;
while (opt->longName || opt->shortName || opt->arg) {
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
sub_transdom = getTableTranslationDomain(opt->arg);
if(!sub_transdom)
sub_transdom = translation_domain;
if (opt->descrip)
fprintf(f, "\n%s\n", D_(sub_transdom, opt->descrip));
singleTableHelp(f, opt->arg, left, sub_transdom);
}
opt++;
}
}
static int showHelpIntro(poptContext con, FILE * f) {
int len = 6;
const char * fn;
fprintf(f, POPT_("Usage:"));
if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
fn = con->optionStack->argv[0];
if (strchr(fn, '/')) fn = strchr(fn, '/') + 1;
fprintf(f, " %s", fn);
len += strlen(fn) + 1;
}
return len;
}
void poptPrintHelp(poptContext con, FILE * f, /*@unused@*/ int flags) {
int leftColWidth;
showHelpIntro(con, f);
if (con->otherHelp)
fprintf(f, " %s\n", con->otherHelp);
else
fprintf(f, " %s\n", POPT_("[OPTION...]"));
leftColWidth = maxArgWidth(con->options, NULL);
singleTableHelp(f, con->options, leftColWidth, NULL);
}
static int singleOptionUsage(FILE * f, int cursor,
const struct poptOption * opt,
const char *translation_domain) {
int len = 3;
char shortStr[2] = { '\0', '\0' };
const char * item = shortStr;
const char * argDescrip = getArgDescrip(opt, translation_domain);
if (opt->shortName) {
if (!(opt->argInfo & POPT_ARG_MASK))
return cursor; /* we did these already */
len++;
*shortStr = opt->shortName;
shortStr[1] = '\0';
} else if (opt->longName) {
len += 1 + strlen(opt->longName);
item = opt->longName;
}
if (len == 3) return cursor;
if (argDescrip)
len += strlen(argDescrip) + 1;
if ((cursor + len) > 79) {
fprintf(f, "\n ");
cursor = 7;
}
fprintf(f, " [-%s%s%s%s]", opt->shortName ? "" : "-", item,
argDescrip ? (opt->shortName ? " " : "=") : "",
argDescrip ? argDescrip : "");
return cursor + len + 1;
}
static int singleTableUsage(FILE * f, int cursor, const struct poptOption * table,
const char *translation_domain) {
const struct poptOption * opt;
opt = table;
while (opt->longName || opt->shortName || opt->arg) {
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN)
translation_domain = (const char *)opt->arg;
else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
cursor = singleTableUsage(f, cursor, opt->arg,
translation_domain);
else if ((opt->longName || opt->shortName) &&
!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
cursor = singleOptionUsage(f, cursor, opt, translation_domain);
opt++;
}
return cursor;
}
static int showShortOptions(const struct poptOption * opt, FILE * f,
char * str) {
char s[300]; /* this is larger then the ascii set, so
it should do just fine */
s[0] = '\0';
if (str == NULL) {
memset(s, 0, sizeof(s));
str = s;
}
while (opt->longName || opt->shortName || opt->arg) {
if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
str[strlen(str)] = opt->shortName;
else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
showShortOptions(opt->arg, f, str);
opt++;
}
if (s != str || !*s)
return 0;
fprintf(f, " [-%s]", s);
return strlen(s) + 4;
}
void poptPrintUsage(poptContext con, FILE * f, /*@unused@*/ int flags) {
int cursor;
cursor = showHelpIntro(con, f);
cursor += showShortOptions(con->options, f, NULL);
singleTableUsage(f, cursor, con->options, NULL);
if (con->otherHelp) {
cursor += strlen(con->otherHelp) + 1;
if (cursor > 79) fprintf(f, "\n ");
fprintf(f, " %s", con->otherHelp);
}
fprintf(f, "\n");
}
void poptSetOtherOptionHelp(poptContext con, const char * text) {
if (con->otherHelp) xfree(con->otherHelp);
con->otherHelp = xstrdup(text);
}

71
source/lib/popt/poptint.h Normal file
View File

@@ -0,0 +1,71 @@
/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions, available from
ftp://ftp.redhat.com/pub/code/popt */
#ifndef H_POPTINT
#define H_POPTINT
/* Bit mask macros. */
typedef unsigned int __pbm_bits;
#define __PBM_NBITS (8 * sizeof (__pbm_bits))
#define __PBM_IX(d) ((d) / __PBM_NBITS)
#define __PBM_MASK(d) ((__pbm_bits) 1 << ((d) % __PBM_NBITS))
typedef struct {
__pbm_bits bits[1];
} pbm_set;
#define __PBM_BITS(set) ((set)->bits)
#define PBM_ALLOC(d) calloc(__PBM_IX (d) + 1, sizeof(__pbm_bits))
#define PBM_FREE(s) free(s);
#define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d))
#define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d))
#define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0)
struct optionStackEntry {
int argc;
/*@only@*/ const char ** argv;
/*@only@*/ pbm_set * argb;
int next;
/*@only@*/ const char * nextArg;
/*@keep@*/ const char * nextCharArg;
/*@dependent@*/ struct poptAlias * currAlias;
int stuffed;
};
struct execEntry {
const char * longName;
char shortName;
const char * script;
};
struct poptContext_s {
struct optionStackEntry optionStack[POPT_OPTION_DEPTH];
/*@dependent@*/ struct optionStackEntry * os;
/*@owned@*/ const char ** leftovers;
int numLeftovers;
int nextLeftover;
/*@keep@*/ const struct poptOption * options;
int restLeftover;
/*@only@*/ const char * appName;
/*@only@*/ struct poptAlias * aliases;
int numAliases;
int flags;
struct execEntry * execs;
int numExecs;
/*@only@*/ const char ** finalArgv;
int finalArgvCount;
int finalArgvAlloced;
/*@dependent@*/ struct execEntry * doExec;
/*@only@*/ const char * execPath;
int execAbsolute;
/*@only@*/ const char * otherHelp;
pbm_set * arg_strip;
};
#define xfree(_a) free((void *)_a)
#define POPT_(foo) (foo)
#define D_(dom, str) (str)
#define N_(foo) (foo)
#endif

102
source/lib/popt/poptparse.c Normal file
View File

@@ -0,0 +1,102 @@
/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions, available from
ftp://ftp.redhat.com/pub/code/popt */
#include "system.h"
#define POPT_ARGV_ARRAY_GROW_DELTA 5
int poptDupArgv(int argc, const char **argv,
int * argcPtr, const char *** argvPtr)
{
size_t nb = (argc + 1) * sizeof(*argv);
const char ** argv2;
char * dst;
int i;
for (i = 0; i < argc; i++) {
if (argv[i] == NULL)
return POPT_ERROR_NOARG;
nb += strlen(argv[i]) + 1;
}
dst = malloc(nb);
argv2 = (void *) dst;
dst += (argc + 1) * sizeof(*argv);
for (i = 0; i < argc; i++) {
argv2[i] = dst;
dst += strlen(strcpy(dst, argv[i])) + 1;
}
argv2[argc] = NULL;
*argvPtr = argv2;
*argcPtr = argc;
return 0;
}
int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
{
const char * src;
char quote = '\0';
int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
const char ** argv = malloc(sizeof(*argv) * argvAlloced);
int argc = 0;
int buflen = strlen(s) + 1;
char *buf0 = calloc(buflen, 1);
char *buf = buf0;
argv[argc] = buf;
for (src = s; *src; src++) {
if (quote == *src) {
quote = '\0';
} else if (quote) {
if (*src == '\\') {
src++;
if (!*src) {
free(argv);
free(buf0);
return POPT_ERROR_BADQUOTE;
}
if (*src != quote) *buf++ = '\\';
}
*buf++ = *src;
} else if (isspace(*src)) {
if (*argv[argc]) {
buf++, argc++;
if (argc == argvAlloced) {
argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
argv = realloc(argv, sizeof(*argv) * argvAlloced);
}
argv[argc] = buf;
}
} else switch (*src) {
case '"':
case '\'':
quote = *src;
break;
case '\\':
src++;
if (!*src) {
free(argv);
free(buf0);
return POPT_ERROR_BADQUOTE;
}
/*@fallthrough@*/
default:
*buf++ = *src;
break;
}
}
if (strlen(argv[argc])) {
argc++, buf++;
}
(void) poptDupArgv(argc, argv, argcPtr, argvPtr);
free(argv);
free(buf0);
return 0;
}

53
source/lib/popt/system.h Normal file
View File

@@ -0,0 +1,53 @@
#include "config.h"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#if HAVE_MCHECK_H
#include <mcheck.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef __NeXT
/* access macros are not declared in non posix mode in unistd.h -
don't try to use posix on NeXTstep 3.3 ! */
#include <libc.h>
#endif
/* AIX requires this to be the first thing in the file. */
#ifndef __GNUC__
# if HAVE_ALLOCA_H
# include <alloca.h>
# else
# ifdef _AIX
#pragma alloca
# else
# ifndef alloca /* predefined by HP cc +Olibcalls */
char *alloca ();
# endif
# endif
# endif
#elif defined(__GNUC__) && defined(__STRICT_ANSI__)
#define alloca __builtin_alloca
#endif
/*@only@*/ char * xstrdup (const char *str);
#if HAVE_MCHECK_H && defined(__GNUC__)
#define vmefail() (fprintf(stderr, "virtual memory exhausted.\n"), exit(EXIT_FAILURE), NULL)
#define xstrdup(_str) (strcpy((malloc(strlen(_str)+1) ? : vmefail()), (_str)))
#else
#define xstrdup(_str) strdup(_str)
#endif /* HAVE_MCHECK_H && defined(__GNUC__) */
#include "popt.h"

327
source/lib/popt_common.c Normal file
View File

@@ -0,0 +1,327 @@
/*
Unix SMB/CIFS implementation.
Common popt routines
Copyright (C) Tim Potter 2001,2002
Copyright (C) Jelmer Vernooij 2002,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"
/* Handle command line options:
* -d,--debuglevel
* -s,--configfile
* -O,--socket-options
* -V,--version
* -l,--log-base
* -n,--netbios-name
* -W,--workgroup
* -i,--scope
*/
extern pstring user_socket_options;
extern BOOL AllowDebugChange;
struct user_auth_info cmdline_auth_info;
static void popt_common_callback(poptContext con,
enum poptCallbackReason reason,
const struct poptOption *opt,
const char *arg, const void *data)
{
pstring logfile;
const char *pname;
/* Find out basename of current program */
pname = strrchr_m(poptGetInvocationName(con),'/');
if (!pname)
pname = poptGetInvocationName(con);
else
pname++;
if (reason == POPT_CALLBACK_REASON_PRE) {
pstr_sprintf(logfile, "%s/log.%s", dyn_LOGFILEBASE, pname);
lp_set_cmdline("log file", logfile);
return;
}
switch(opt->val) {
case 'd':
lp_set_cmdline("log level", arg);
break;
case 'V':
printf( "Version %s\n", SAMBA_VERSION );
exit(0);
break;
case 's':
if (arg) {
pstrcpy(dyn_CONFIGFILE, arg);
}
break;
case 'l':
if (arg) {
pstr_sprintf(logfile, "%s/log.%s", arg, pname);
lp_set_cmdline("log file", logfile);
}
break;
case 'W':
lp_set_cmdline("workgroup", arg);
break;
case 'n':
lp_set_cmdline("netbios name", arg);
break;
case 'i':
lp_set_cmdline("netbios scope", arg);
break;
}
}
struct poptOption popt_common_connection[] = {
{ NULL, 0, POPT_ARG_CALLBACK, popt_common_callback },
{ "socket-options", 'O', POPT_ARG_STRING, NULL, 'O', "socket options to use",
"SOCKETOPTIONS" },
{ "netbiosname", 'n', POPT_ARG_STRING, NULL, 'n', "Primary netbios name", "NETBIOSNAME" },
{ "workgroup", 'W', POPT_ARG_STRING, NULL, 'W', "Set the workgroup name", "WORKGROUP" },
{ "scope", 'i', POPT_ARG_STRING, NULL, 'i', "Use this Netbios scope", "SCOPE" },
POPT_TABLEEND
};
struct poptOption popt_common_samba[] = {
{ NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE, popt_common_callback },
{ "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Set debug level", "DEBUGLEVEL" },
{ "configfile", 's', POPT_ARG_STRING, NULL, 's', "Use alternative configuration file", "CONFIGFILE" },
{ "log-basename", 'l', POPT_ARG_STRING, NULL, 'l', "Basename for log/debug files", "LOGFILEBASE" },
{ "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" },
POPT_TABLEEND
};
struct poptOption popt_common_version[] = {
{ NULL, 0, POPT_ARG_CALLBACK, popt_common_callback },
{ "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" },
POPT_TABLEEND
};
/****************************************************************************
* get a password from a a file or file descriptor
* exit on failure
* ****************************************************************************/
static void get_password_file(struct user_auth_info *a)
{
int fd = -1;
char *p;
BOOL close_it = False;
pstring spec;
char pass[128];
if ((p = getenv("PASSWD_FD")) != NULL) {
pstrcpy(spec, "descriptor ");
pstrcat(spec, p);
sscanf(p, "%d", &fd);
close_it = False;
} else if ((p = getenv("PASSWD_FILE")) != NULL) {
fd = sys_open(p, O_RDONLY, 0);
pstrcpy(spec, p);
if (fd < 0) {
fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
spec, strerror(errno));
exit(1);
}
close_it = True;
}
for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
p && p - pass < sizeof(pass);) {
switch (read(fd, p, 1)) {
case 1:
if (*p != '\n' && *p != '\0') {
*++p = '\0'; /* advance p, and null-terminate pass */
break;
}
case 0:
if (p - pass) {
*p = '\0'; /* null-terminate it, just in case... */
p = NULL; /* then force the loop condition to become false */
break;
} else {
fprintf(stderr, "Error reading password from file %s: %s\n",
spec, "empty password\n");
exit(1);
}
default:
fprintf(stderr, "Error reading password from file %s: %s\n",
spec, strerror(errno));
exit(1);
}
}
pstrcpy(a->password, pass);
if (close_it)
close(fd);
}
static void get_credentials_file(const char *file, struct user_auth_info *info)
{
XFILE *auth;
fstring buf;
uint16 len = 0;
char *ptr, *val, *param;
if ((auth=x_fopen(file, O_RDONLY, 0)) == NULL)
{
/* fail if we can't open the credentials file */
d_printf("ERROR: Unable to open credentials file!\n");
exit(-1);
}
while (!x_feof(auth))
{
/* get a line from the file */
if (!x_fgets(buf, sizeof(buf), auth))
continue;
len = strlen(buf);
if ((len) && (buf[len-1]=='\n'))
{
buf[len-1] = '\0';
len--;
}
if (len == 0)
continue;
/* break up the line into parameter & value.
* will need to eat a little whitespace possibly */
param = buf;
if (!(ptr = strchr_m (buf, '=')))
continue;
val = ptr+1;
*ptr = '\0';
/* eat leading white space */
while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
val++;
if (strwicmp("password", param) == 0)
{
pstrcpy(info->password, val);
info->got_pass = True;
}
else if (strwicmp("username", param) == 0)
pstrcpy(info->username, val);
//else if (strwicmp("domain", param) == 0)
// set_global_myworkgroup(val);
memset(buf, 0, sizeof(buf));
}
x_fclose(auth);
}
/* Handle command line options:
* -U,--user
* -A,--authentication-file
* -k,--use-kerberos
* -N,--no-pass
*/
static void popt_common_credentials_callback(poptContext con,
enum poptCallbackReason reason,
const struct poptOption *opt,
const char *arg, const void *data)
{
char *p;
if (reason == POPT_CALLBACK_REASON_PRE) {
cmdline_auth_info.use_kerberos = False;
cmdline_auth_info.got_pass = False;
pstrcpy(cmdline_auth_info.username, "GUEST");
if (getenv("LOGNAME"))pstrcpy(cmdline_auth_info.username,getenv("LOGNAME"));
if (getenv("USER")) {
pstrcpy(cmdline_auth_info.username,getenv("USER"));
if ((p = strchr_m(cmdline_auth_info.username,'%'))) {
*p = 0;
pstrcpy(cmdline_auth_info.password,p+1);
cmdline_auth_info.got_pass = True;
memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(cmdline_auth_info.password));
}
}
if (getenv("PASSWD")) {
pstrcpy(cmdline_auth_info.password,getenv("PASSWD"));
cmdline_auth_info.got_pass = True;
}
if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
get_password_file(&cmdline_auth_info);
cmdline_auth_info.got_pass = True;
}
return;
}
switch(opt->val) {
case 'U':
{
char *lp;
pstrcpy(cmdline_auth_info.username,arg);
if ((lp=strchr_m(cmdline_auth_info.username,'%'))) {
*lp = 0;
pstrcpy(cmdline_auth_info.password,lp+1);
cmdline_auth_info.got_pass = True;
memset(strchr_m(arg,'%')+1,'X',strlen(cmdline_auth_info.password));
}
}
break;
case 'A':
get_credentials_file(arg, &cmdline_auth_info);
break;
case 'k':
#ifndef HAVE_KRB5
d_printf("No kerberos support compiled in\n");
exit(1);
#else
cmdline_auth_info.use_kerberos = True;
cmdline_auth_info.got_pass = True;
#endif
break;
}
}
struct poptOption popt_common_credentials[] = {
{ NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE, popt_common_credentials_callback },
{ "user", 'U', POPT_ARG_STRING, NULL, 'U', "Set the network username", "USERNAME" },
{ "no-pass", 'N', POPT_ARG_NONE, &cmdline_auth_info.got_pass, True, "Don't ask for a password" },
{ "kerberos", 'k', POPT_ARG_NONE, &cmdline_auth_info.use_kerberos, True, "Use kerberos (active directory) authentication" },
{ "authentication-file", 'A', POPT_ARG_STRING, NULL, 'A', "Get the credentials from a file", "FILE" },
POPT_TABLEEND
};

159
source/lib/readline.c Normal file
View File

@@ -0,0 +1,159 @@
/*
Unix SMB/CIFS implementation.
Samba readline wrapper implementation
Copyright (C) Simo Sorce 2001
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.
*/
#include "includes.h"
#ifdef HAVE_LIBREADLINE
# ifdef HAVE_READLINE_READLINE_H
# include <readline/readline.h>
# ifdef HAVE_READLINE_HISTORY_H
# include <readline/history.h>
# endif
# else
# ifdef HAVE_READLINE_H
# include <readline.h>
# ifdef HAVE_HISTORY_H
# include <history.h>
# endif
# else
# undef HAVE_LIBREADLINE
# endif
# endif
#endif
#ifdef HAVE_NEW_LIBREADLINE
# define RL_COMPLETION_CAST (rl_completion_func_t *)
#else
/* This type is missing from libreadline<4.0 (approximately) */
# define RL_COMPLETION_CAST
#endif /* HAVE_NEW_LIBREADLINE */
/****************************************************************************
Display the prompt and wait for input. Call callback() regularly
****************************************************************************/
static char *smb_readline_replacement(const char *prompt, void (*callback)(void),
char **(completion_fn)(const char *text, int start, int end))
{
fd_set fds;
static pstring line;
struct timeval timeout;
int fd = x_fileno(x_stdin);
char *ret;
do_debug("%s", prompt);
while (1) {
timeout.tv_sec = 5;
timeout.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(fd,&fds);
if (sys_select_intr(fd+1,&fds,NULL,NULL,&timeout) == 1) {
ret = x_fgets(line, sizeof(line), x_stdin);
return ret;
}
if (callback)
callback();
}
}
/****************************************************************************
Display the prompt and wait for input. Call callback() regularly.
****************************************************************************/
char *smb_readline(const char *prompt, void (*callback)(void),
char **(completion_fn)(const char *text, int start, int end))
{
#if HAVE_LIBREADLINE
if (isatty(x_fileno(x_stdin))) {
char *ret;
/* Aargh! Readline does bizzare things with the terminal width
that mucks up expect(1). Set CLI_NO_READLINE in the environment
to force readline not to be used. */
if (getenv("CLI_NO_READLINE"))
return smb_readline_replacement(prompt, callback, completion_fn);
if (completion_fn) {
/* The callback prototype has changed slightly between
different versions of Readline, so the same function
works in all of them to date, but we get compiler
warnings in some. */
rl_attempted_completion_function = RL_COMPLETION_CAST completion_fn;
}
if (callback)
rl_event_hook = (Function *)callback;
ret = readline(prompt);
if (ret && *ret)
add_history(ret);
return ret;
} else
#endif
return smb_readline_replacement(prompt, callback, completion_fn);
}
/****************************************************************************
* return line buffer text
****************************************************************************/
const char *smb_readline_get_line_buffer(void)
{
#if defined(HAVE_LIBREADLINE)
return rl_line_buffer;
#else
return NULL;
#endif
}
/****************************************************************************
* set completion append character
***************************************************************************/
void smb_readline_ca_char(char c)
{
#if defined(HAVE_LIBREADLINE)
rl_completion_append_character = c;
#endif
}
/****************************************************************************
history
****************************************************************************/
int cmd_history(void)
{
#if defined(HAVE_LIBREADLINE)
HIST_ENTRY **hlist;
int i;
hlist = history_list();
for (i = 0; hlist && hlist[i]; i++) {
DEBUG(0, ("%d: %s\n", i, hlist[i]->line));
}
#else
DEBUG(0,("no history without readline support\n"));
#endif
return 0;
}

467
source/lib/replace.c Normal file
View File

@@ -0,0 +1,467 @@
/*
Unix SMB/CIFS implementation.
replacement routines for broken systems
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"
void replace_dummy(void);
void replace_dummy(void) {}
#ifndef HAVE_FTRUNCATE
/*******************************************************************
ftruncate for operating systems that don't have it
********************************************************************/
int ftruncate(int f,SMB_OFF_T l)
{
struct flock fl;
fl.l_whence = 0;
fl.l_len = 0;
fl.l_start = l;
fl.l_type = F_WRLCK;
return fcntl(f, F_FREESP, &fl);
}
#endif /* HAVE_FTRUNCATE */
#ifndef HAVE_STRLCPY
/* like strncpy but does not 0 fill the buffer and always null
terminates. bufsize is the size of the destination buffer */
size_t strlcpy(char *d, const char *s, size_t bufsize)
{
size_t len = strlen(s);
size_t ret = len;
if (bufsize <= 0) return 0;
if (len >= bufsize) len = bufsize-1;
memcpy(d, s, len);
d[len] = 0;
return ret;
}
#endif
#ifndef HAVE_STRLCAT
/* like strncat but does not 0 fill the buffer and always null
terminates. bufsize is the length of the buffer, which should
be one more than the maximum resulting string length */
size_t strlcat(char *d, const char *s, size_t bufsize)
{
size_t len1 = strlen(d);
size_t len2 = strlen(s);
size_t ret = len1 + len2;
if (len1+len2 >= bufsize) {
len2 = bufsize - (len1+1);
}
if (len2 > 0) {
memcpy(d+len1, s, len2);
d[len1+len2] = 0;
}
return ret;
}
#endif
#ifndef HAVE_MKTIME
/*******************************************************************
a mktime() replacement for those who don't have it - contributed by
C.A. Lademann <cal@zls.com>
Corrections by richard.kettlewell@kewill.com
********************************************************************/
#define MINUTE 60
#define HOUR 60*MINUTE
#define DAY 24*HOUR
#define YEAR 365*DAY
time_t mktime(struct tm *t)
{
struct tm *u;
time_t epoch = 0;
int n;
int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
y, m, i;
if(t->tm_year < 70)
return((time_t)-1);
n = t->tm_year + 1900 - 1;
epoch = (t->tm_year - 70) * YEAR +
((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
y = t->tm_year + 1900;
m = 0;
for(i = 0; i < t->tm_mon; i++) {
epoch += mon [m] * DAY;
if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
epoch += DAY;
if(++m > 11) {
m = 0;
y++;
}
}
epoch += (t->tm_mday - 1) * DAY;
epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
if((u = localtime(&epoch)) != NULL) {
t->tm_sec = u->tm_sec;
t->tm_min = u->tm_min;
t->tm_hour = u->tm_hour;
t->tm_mday = u->tm_mday;
t->tm_mon = u->tm_mon;
t->tm_year = u->tm_year;
t->tm_wday = u->tm_wday;
t->tm_yday = u->tm_yday;
t->tm_isdst = u->tm_isdst;
}
return(epoch);
}
#endif /* !HAVE_MKTIME */
#ifndef HAVE_RENAME
/* Rename a file. (from libiberty in GNU binutils) */
int rename(const char *zfrom, const char *zto)
{
if (link (zfrom, zto) < 0)
{
if (errno != EEXIST)
return -1;
if (unlink (zto) < 0
|| link (zfrom, zto) < 0)
return -1;
}
return unlink (zfrom);
}
#endif /* HAVE_RENAME */
#ifndef HAVE_INNETGR
#if defined(HAVE_SETNETGRENT) && defined(HAVE_GETNETGRENT) && defined(HAVE_ENDNETGRENT)
/*
* Search for a match in a netgroup. This replaces it on broken systems.
*/
int innetgr(const char *group,const char *host,const char *user,const char *dom)
{
char *hst, *usr, *dm;
setnetgrent(group);
while (getnetgrent(&hst, &usr, &dm)) {
if (((host == 0) || (hst == 0) || !strcmp(host, hst)) &&
((user == 0) || (usr == 0) || !strcmp(user, usr)) &&
((dom == 0) || (dm == 0) || !strcmp(dom, dm))) {
endnetgrent();
return (1);
}
}
endnetgrent();
return (0);
}
#endif /* HAVE_SETNETGRENT HAVE_GETNETGRENT HAVE_ENDNETGRENT */
#endif /* HAVE_INNETGR */
#ifndef HAVE_INITGROUPS
/****************************************************************************
some systems don't have an initgroups call
****************************************************************************/
int initgroups(char *name,gid_t id)
{
#ifndef HAVE_SETGROUPS
static int done;
if (!done) {
DEBUG(1,("WARNING: running without setgroups\n"));
done=1;
}
/* yikes! no SETGROUPS or INITGROUPS? how can this work? */
return(0);
#else /* HAVE_SETGROUPS */
gid_t *grouplst = NULL;
int max_gr = groups_max();
int ret;
int i,j;
struct group *g;
char *gr;
if((grouplst = (gid_t *)malloc(sizeof(gid_t) * max_gr)) == NULL) {
DEBUG(0,("initgroups: malloc fail !\n"));
return -1;
}
grouplst[0] = id;
i = 1;
while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
if (g->gr_gid == id)
continue;
j = 0;
gr = g->gr_mem[0];
while (gr && (*gr != (char)NULL)) {
if (strcmp(name,gr) == 0) {
grouplst[i] = g->gr_gid;
i++;
gr = (char *)NULL;
break;
}
gr = g->gr_mem[++j];
}
}
endgrent();
ret = sys_setgroups(i,grouplst);
SAFE_FREE(grouplst);
return ret;
#endif /* HAVE_SETGROUPS */
}
#endif /* HAVE_INITGROUPS */
#if (defined(SecureWare) && defined(SCO))
/* This is needed due to needing the nap() function but we don't want
to include the Xenix libraries since that will break other things...
BTW: system call # 0x0c28 is the same as calling nap() */
long nap(long milliseconds) {
return syscall(0x0c28, milliseconds);
}
#endif
#ifndef HAVE_MEMMOVE
/*******************************************************************
safely copies memory, ensuring no overlap problems.
this is only used if the machine does not have it's own memmove().
this is not the fastest algorithm in town, but it will do for our
needs.
********************************************************************/
void *memmove(void *dest,const void *src,int size)
{
unsigned long d,s;
int i;
if (dest==src || !size) return(dest);
d = (unsigned long)dest;
s = (unsigned long)src;
if ((d >= (s+size)) || (s >= (d+size))) {
/* no overlap */
memcpy(dest,src,size);
return(dest);
}
if (d < s) {
/* we can forward copy */
if (s-d >= sizeof(int) &&
!(s%sizeof(int)) &&
!(d%sizeof(int)) &&
!(size%sizeof(int))) {
/* do it all as words */
int *idest = (int *)dest;
int *isrc = (int *)src;
size /= sizeof(int);
for (i=0;i<size;i++) idest[i] = isrc[i];
} else {
/* simplest */
char *cdest = (char *)dest;
char *csrc = (char *)src;
for (i=0;i<size;i++) cdest[i] = csrc[i];
}
} else {
/* must backward copy */
if (d-s >= sizeof(int) &&
!(s%sizeof(int)) &&
!(d%sizeof(int)) &&
!(size%sizeof(int))) {
/* do it all as words */
int *idest = (int *)dest;
int *isrc = (int *)src;
size /= sizeof(int);
for (i=size-1;i>=0;i--) idest[i] = isrc[i];
} else {
/* simplest */
char *cdest = (char *)dest;
char *csrc = (char *)src;
for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
}
}
return(dest);
}
#endif /* HAVE_MEMMOVE */
#ifndef HAVE_STRDUP
/****************************************************************************
duplicate a string
****************************************************************************/
char *strdup(const char *s)
{
size_t len;
char *ret;
if (!s) return(NULL);
len = strlen(s)+1;
ret = (char *)malloc(len);
if (!ret) return(NULL);
memcpy(ret,s,len);
return(ret);
}
#endif /* HAVE_STRDUP */
#if 0 /* REWRITE: not thread safe */
#ifdef REPLACE_INET_NTOA
char *rep_inet_ntoa(struct in_addr ip)
{
unsigned char *p = (unsigned char *)&ip.s_addr;
static char buf[18];
slprintf(buf, 17, "%d.%d.%d.%d",
(int)p[0], (int)p[1], (int)p[2], (int)p[3]);
return buf;
}
#endif /* REPLACE_INET_NTOA */
#endif
#ifndef HAVE_STRTOUL
#ifndef ULONG_MAX
#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF */
#endif
/*
* Convert a string to an unsigned long integer.
* Taken from libg++ - libiberty code.
*
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
unsigned long strtoul(const char *nptr, char **endptr, int base)
{
const char *s = nptr;
unsigned long acc;
int c;
unsigned long cutoff;
int neg = 0, any, cutlim;
/*
* See strtol for comments as to the logic used.
*/
do {
c = *s++;
} while (isspace(c));
if (c == '-') {
neg = 1;
c = *s++;
} else if (c == '+')
c = *s++;
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
cutlim = (int)((unsigned long)ULONG_MAX % (unsigned long)base);
for (acc = 0, any = 0;; c = *s++) {
if (isdigit(c))
c -= '0';
else if (isalpha(c))
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = ULONG_MAX;
errno = ERANGE;
} else if (neg)
acc = -acc;
if (endptr != 0)
*endptr = (char *) (any ? s - 1 : nptr);
return (acc);
}
#endif /* HAVE_STRTOUL */
#ifndef HAVE_SETLINEBUF
int setlinebuf(FILE *stream)
{
return setvbuf(stream, (char *)NULL, _IOLBF, 0);
}
#endif /* HAVE_SETLINEBUF */
#ifndef HAVE_VSYSLOG
#ifdef HAVE_SYSLOG
void vsyslog (int facility_priority, char *format, va_list arglist)
{
char *msg = NULL;
vasprintf(&msg, format, arglist);
if (!msg)
return;
syslog(facility_priority, "%s", msg);
SAFE_FREE(msg);
}
#endif /* HAVE_SYSLOG */
#endif /* HAVE_VSYSLOG */
#ifndef HAVE_TIMEGM
/*
yes, I know this looks insane, but its really needed. The function in the
Linux timegm() manpage does not work on solaris.
*/
time_t timegm(struct tm *tm)
{
struct tm tm2, tm3;
time_t t;
tm2 = *tm;
t = mktime(&tm2);
tm3 = *localtime(&t);
tm2 = *tm;
tm2.tm_isdst = tm3.tm_isdst;
t = mktime(&tm2);
t -= TimeDiff(t);
return t;
}
#endif
#ifndef HAVE_SETENV
int setenv(const char *name, const char *value, int overwrite)
{
char *p = NULL;
int ret = -1;
asprintf(&p, "%s=%s", name, value);
if (overwrite || getenv(name)) {
if (p) ret = putenv(p);
} else {
ret = 0;
}
return ret;
}
#endif

159
source/lib/select.c Normal file
View File

@@ -0,0 +1,159 @@
/*
Unix SMB/Netbios implementation.
Version 3.0
Samba select/poll implementation
Copyright (C) Andrew Tridgell 1992-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
/* This is here because it allows us to avoid a nasty race in signal handling.
We need to guarantee that when we get a signal we get out of a select immediately
but doing that involves a race condition. We can avoid the race by getting the
signal handler to write to a pipe that is in the select/poll list
This means all Samba signal handlers should call sys_select_signal().
*/
static pid_t initialised;
static int select_pipe[2];
static VOLATILE unsigned pipe_written, pipe_read;
/*******************************************************************
Call this from all Samba signal handlers if you want to avoid a
nasty signal race condition.
********************************************************************/
void sys_select_signal(void)
{
char c = 1;
if (!initialised) return;
if (pipe_written > pipe_read+256) return;
if (write(select_pipe[1], &c, 1) == 1) pipe_written++;
}
/*******************************************************************
Like select() but avoids the signal race using a pipe
it also guuarantees that fds on return only ever contains bits set
for file descriptors that were readable.
********************************************************************/
int sys_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval)
{
int ret, saved_errno;
fd_set *readfds2, readfds_buf;
if (initialised != getpid()) {
pipe(select_pipe);
/*
* These next two lines seem to fix a bug with the Linux
* 2.0.x kernel (and probably other UNIXes as well) where
* the one byte read below can block even though the
* select returned that there is data in the pipe and
* the pipe_written variable was incremented. Thanks to
* HP for finding this one. JRA.
*/
if(set_blocking(select_pipe[0],0)==-1)
smb_panic("select_pipe[0]: O_NONBLOCK failed.\n");
if(set_blocking(select_pipe[1],0)==-1)
smb_panic("select_pipe[1]: O_NONBLOCK failed.\n");
initialised = getpid();
}
maxfd = MAX(select_pipe[0]+1, maxfd);
/* If readfds is NULL we need to provide our own set. */
if (readfds) {
readfds2 = readfds;
} else {
readfds2 = &readfds_buf;
FD_ZERO(readfds2);
}
FD_SET(select_pipe[0], readfds2);
errno = 0;
ret = select(maxfd,readfds2,writefds,errorfds,tval);
if (ret <= 0) {
FD_ZERO(readfds2);
if (writefds)
FD_ZERO(writefds);
if (errorfds)
FD_ZERO(errorfds);
}
if (FD_ISSET(select_pipe[0], readfds2)) {
char c;
saved_errno = errno;
if (read(select_pipe[0], &c, 1) == 1) {
pipe_read++;
}
errno = saved_errno;
FD_CLR(select_pipe[0], readfds2);
ret--;
if (ret == 0) {
ret = -1;
errno = EINTR;
}
}
return ret;
}
/*******************************************************************
Similar to sys_select() but catch EINTR and continue.
This is what sys_select() used to do in Samba.
********************************************************************/
int sys_select_intr(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval)
{
int ret;
fd_set *readfds2, readfds_buf, *writefds2, writefds_buf, *errorfds2, errorfds_buf;
struct timeval tval2, *ptval;
readfds2 = (readfds ? &readfds_buf : NULL);
writefds2 = (writefds ? &writefds_buf : NULL);
errorfds2 = (errorfds ? &errorfds_buf : NULL);
ptval = (tval ? &tval2 : NULL);
do {
if (readfds)
readfds_buf = *readfds;
if (writefds)
writefds_buf = *writefds;
if (errorfds)
errorfds_buf = *errorfds;
if (tval)
tval2 = *tval;
ret = sys_select(maxfd, readfds2, writefds2, errorfds2, ptval);
} while (ret == -1 && errno == EINTR);
if (readfds)
*readfds = readfds_buf;
if (writefds)
*writefds = writefds_buf;
if (errorfds)
*errorfds = errorfds_buf;
return ret;
}

382
source/lib/sendfile.c Normal file
View File

@@ -0,0 +1,382 @@
/*
Unix SMB/Netbios implementation.
Version 2.2.x / 3.0.x
sendfile implementations.
Copyright (C) Jeremy Allison 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.
*/
/*
* This file handles the OS dependent sendfile implementations.
* The API is such that it returns -1 on error, else returns the
* number of bytes written.
*/
#include "includes.h"
#if defined(LINUX_SENDFILE_API)
#include <sys/sendfile.h>
#ifndef MSG_MORE
#define MSG_MORE 0x8000
#endif
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
{
size_t total=0;
ssize_t ret;
size_t hdr_len = 0;
/*
* Send the header first.
* Use MSG_MORE to cork the TCP output until sendfile is called.
*/
if (header) {
hdr_len = header->length;
while (total < hdr_len) {
ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
if (ret == -1)
return -1;
total += ret;
}
}
total = count;
while (total) {
ssize_t nwritten;
do {
#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
nwritten = sendfile64(tofd, fromfd, &offset, total);
#else
nwritten = sendfile(tofd, fromfd, &offset, total);
#endif
} while (nwritten == -1 && errno == EINTR);
if (nwritten == -1)
return -1;
if (nwritten == 0)
return -1; /* I think we're at EOF here... */
total -= nwritten;
}
return count + hdr_len;
}
#elif defined(LINUX_BROKEN_SENDFILE_API)
/*
* We must use explicit 32 bit types here. This code path means Linux
* won't do proper 64-bit sendfile. JRA.
*/
extern int32 sendfile (int out_fd, int in_fd, int32 *offset, uint32 count);
#ifndef MSG_MORE
#define MSG_MORE 0x8000
#endif
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
{
size_t total=0;
ssize_t ret;
ssize_t hdr_len = 0;
uint32 small_total = 0;
int32 small_offset;
/*
* Fix for broken Linux 2.4 systems with no working sendfile64().
* If the offset+count > 2 GB then pretend we don't have the
* system call sendfile at all. The upper layer catches this
* and uses a normal read. JRA.
*/
if ((sizeof(SMB_OFF_T) >= 8) && (offset + count > (SMB_OFF_T)0x7FFFFFFF)) {
errno = ENOSYS;
return -1;
}
/*
* Send the header first.
* Use MSG_MORE to cork the TCP output until sendfile is called.
*/
if (header) {
hdr_len = header->length;
while (total < hdr_len) {
ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
if (ret == -1)
return -1;
total += ret;
}
}
small_total = (uint32)count;
small_offset = (int32)offset;
while (small_total) {
int32 nwritten;
do {
nwritten = sendfile(tofd, fromfd, &small_offset, small_total);
} while (nwritten == -1 && errno == EINTR);
if (nwritten == -1)
return -1;
if (nwritten == 0)
return -1; /* I think we're at EOF here... */
small_total -= nwritten;
}
return count + hdr_len;
}
#elif defined(SOLARIS_SENDFILE_API)
/*
* Solaris sendfile code written by Pierre Belanger <belanger@pobox.com>.
*/
#include <sys/sendfile.h>
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
{
int sfvcnt;
size_t total, xferred;
struct sendfilevec vec[2];
ssize_t hdr_len = 0;
if (header) {
sfvcnt = 2;
vec[0].sfv_fd = SFV_FD_SELF;
vec[0].sfv_flag = 0;
vec[0].sfv_off = header->data;
vec[0].sfv_len = hdr_len = header->length;
vec[1].sfv_fd = fromfd;
vec[1].sfv_flag = 0;
vec[1].sfv_off = offset;
vec[1].sfv_len = count;
} else {
sfvcnt = 1;
vec[0].sfv_fd = fromfd;
vec[0].sfv_flag = 0;
vec[0].sfv_off = offset;
vec[0].sfv_len = count;
}
total = count + hdr_len;
while (total) {
ssize_t nwritten;
/*
* Although not listed in the API error returns, this is almost certainly
* a slow system call and will be interrupted by a signal with EINTR. JRA.
*/
xferred = 0;
#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILEV64)
nwritten = sendfilev64(tofd, vec, sfvcnt, &xferred);
#else
nwritten = sendfilev(tofd, vec, sfvcnt, &xferred);
#endif
if (nwritten == -1 && errno == EINTR) {
if (xferred == 0)
continue; /* Nothing written yet. */
else
nwritten = xferred;
}
if (nwritten == -1)
return -1;
if (nwritten == 0)
return -1; /* I think we're at EOF here... */
/*
* If this was a short (signal interrupted) write we may need
* to subtract it from the header data, or null out the header
* data altogether if we wrote more than vec[0].sfv_len bytes.
* We move vec[1].* to vec[0].* and set sfvcnt to 1
*/
if (sfvcnt == 2 && nwritten >= vec[0].sfv_len) {
vec[1].sfv_off += nwritten - vec[0].sfv_len;
vec[1].sfv_len -= nwritten - vec[0].sfv_len;
/* Move vec[1].* to vec[0].* and set sfvcnt to 1 */
vec[0] = vec[1];
sfvcnt = 1;
} else {
vec[0].sfv_off += nwritten;
vec[0].sfv_len -= nwritten;
}
total -= nwritten;
}
return count + hdr_len;
}
#elif defined(HPUX_SENDFILE_API)
#include <sys/socket.h>
#include <sys/uio.h>
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
{
size_t total=0;
struct iovec hdtrl[2];
size_t hdr_len = 0;
if (header) {
/* Set up the header/trailer iovec. */
hdtrl[0].iov_base = header->data;
hdtrl[0].iov_len = hdr_len = header->length;
} else {
hdtrl[0].iov_base = NULL;
hdtrl[0].iov_len = hdr_len = 0;
}
hdtrl[1].iov_base = NULL;
hdtrl[1].iov_base = 0;
total = count;
while (total + hdtrl[0].iov_len) {
ssize_t nwritten;
/*
* HPUX guarantees that if any data was written before
* a signal interrupt then sendfile returns the number of
* bytes written (which may be less than requested) not -1.
* nwritten includes the header data sent.
*/
do {
#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
nwritten = sendfile64(tofd, fromfd, offset, total, &hdtrl[0], 0);
#else
nwritten = sendfile(tofd, fromfd, offset, total, &hdtrl[0], 0);
#endif
} while (nwritten == -1 && errno == EINTR);
if (nwritten == -1)
return -1;
if (nwritten == 0)
return -1; /* I think we're at EOF here... */
/*
* If this was a short (signal interrupted) write we may need
* to subtract it from the header data, or null out the header
* data altogether if we wrote more than hdtrl[0].iov_len bytes.
* We change nwritten to be the number of file bytes written.
*/
if (hdtrl[0].iov_base && hdtrl[0].iov_len) {
if (nwritten >= hdtrl[0].iov_len) {
nwritten -= hdtrl[0].iov_len;
hdtrl[0].iov_base = NULL;
hdtrl[0].iov_len = 0;
} else {
/* iov_base is defined as a void *... */
hdtrl[0].iov_base = ((char *)hdtrl[0].iov_base) + nwritten;
hdtrl[0].iov_len -= nwritten;
nwritten = 0;
}
}
total -= nwritten;
offset += nwritten;
}
return count + hdr_len;
}
#elif defined(FREEBSD_SENDFILE_API)
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
{
size_t total=0;
struct sf_hdtr hdr;
struct iovec hdtrl;
size_t hdr_len = 0;
hdr.headers = &hdtrl;
hdr.hdr_cnt = 1;
hdr.trailers = NULL;
hdr.trl_cnt = 0;
/* Set up the header iovec. */
if (header) {
hdtrl.iov_base = header->data;
hdtrl.iov_len = hdr_len = header->length;
} else {
hdtrl.iov_base = NULL;
hdtrl.iov_len = 0;
}
total = count;
while (total + hdtrl.iov_len) {
SMB_OFF_T nwritten;
int ret;
/*
* FreeBSD sendfile returns 0 on success, -1 on error.
* Remember, the tofd and fromfd are reversed..... :-).
* nwritten includes the header data sent.
*/
do {
ret = sendfile(fromfd, tofd, offset, total, &hdr, &nwritten, 0);
} while (ret == -1 && errno == EINTR);
if (ret == -1)
return -1;
if (nwritten == 0)
return -1; /* I think we're at EOF here... */
/*
* If this was a short (signal interrupted) write we may need
* to subtract it from the header data, or null out the header
* data altogether if we wrote more than hdtrl.iov_len bytes.
* We change nwritten to be the number of file bytes written.
*/
if (hdtrl.iov_base && hdtrl.iov_len) {
if (nwritten >= hdtrl.iov_len) {
nwritten -= hdtrl.iov_len;
hdtrl.iov_base = NULL;
hdtrl.iov_len = 0;
} else {
hdtrl.iov_base += nwritten;
hdtrl.iov_len -= nwritten;
nwritten = 0;
}
}
total -= nwritten;
offset += nwritten;
}
return count + hdr_len;
}
#else /* No sendfile implementation. Return error. */
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
{
/* No sendfile syscall. */
errno = ENOSYS;
return -1;
}
#endif

58
source/lib/server_mutex.c Normal file
View File

@@ -0,0 +1,58 @@
/*
Unix SMB/CIFS implementation.
Authenticate against a remote domain
Copyright (C) Andrew Tridgell 1992-2002
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"
/* For reasons known only to MS, many of their NT/Win2k versions
need serialised access only. Two connections at the same time
may (in certain situations) cause connections to be reset,
or access to be denied.
This locking allows smbd's mutlithread architecture to look
like the single-connection that NT makes. */
static char *mutex_server_name;
/* FIXME. ref_count should be allocated per name... JRA. */
size_t ref_count;
BOOL grab_server_mutex(const char *name)
{
mutex_server_name = strdup(name);
if (!mutex_server_name) {
DEBUG(0,("grab_server_mutex: malloc failed for %s\n", name));
return False;
}
if (!secrets_named_mutex(mutex_server_name, 10, &ref_count)) {
DEBUG(10,("grab_server_mutex: failed for %s\n", name));
SAFE_FREE(mutex_server_name);
return False;
}
return True;
}
void release_server_mutex(void)
{
if (mutex_server_name) {
secrets_named_mutex_release(mutex_server_name, &ref_count);
SAFE_FREE(mutex_server_name);
}
}

139
source/lib/signal.c Normal file
View File

@@ -0,0 +1,139 @@
/*
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"
/****************************************************************************
Catch child exits and reap the child zombie status.
****************************************************************************/
static void sig_cld(int signum)
{
while (sys_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);
}

200
source/lib/smbpasswd.c Normal file
View File

@@ -0,0 +1,200 @@
/*
Unix SMB/CIFS implementation.
smbpasswd file format routines
Copyright (C) Andrew Tridgell 1992-1998
Modified by Jeremy Allison 1995.
Modified by Gerald (Jerry) Carter 2000-2001
Copyright (C) Tim Potter 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 lib/smbpasswd.c
The smbpasswd file is used to store encrypted passwords in a similar
fashion to the /etc/passwd file. The format is colon separated fields
with one user per line like so:
<username>:<uid>:<lanman hash>:<nt hash>:<acb info>:<last change time>
The username and uid must correspond to an entry in the /etc/passwd
file. The lanman and nt password hashes are 32 hex digits corresponding
to the 16-byte lanman and nt hashes respectively.
The password last change time is stored as a string of the format
LCD-<change time> where the change time is expressed as an
'N' No password
'D' Disabled
'H' Homedir required
'T' Temp account.
'U' User account (normal)
'M' MNS logon user account - what is this ?
'W' Workstation account
'S' Server account
'L' Locked account
'X' No Xpiry on password
'I' Interdomain trust account
*/
#include "includes.h"
/*! Convert 32 hex characters into a 16 byte array. */
BOOL smbpasswd_gethexpwd(char *p, unsigned char *pwd)
{
int i;
unsigned char lonybble, hinybble;
const char *hexchars = "0123456789ABCDEF";
char *p1, *p2;
if (!p) return (False);
for (i = 0; i < 32; i += 2)
{
hinybble = toupper(p[i]);
lonybble = toupper(p[i + 1]);
p1 = strchr_m(hexchars, hinybble);
p2 = strchr_m(hexchars, lonybble);
if (!p1 || !p2)
{
return (False);
}
hinybble = PTR_DIFF(p1, hexchars);
lonybble = PTR_DIFF(p2, hexchars);
pwd[i / 2] = (hinybble << 4) | lonybble;
}
return (True);
}
/*! Convert a 16-byte array into 32 hex characters. */
void smbpasswd_sethexpwd(fstring p, unsigned char *pwd, uint16 acb_info)
{
if (pwd != NULL) {
int i;
for (i = 0; i < 16; i++)
slprintf(&p[i*2], 3, "%02X", pwd[i]);
} else {
if (acb_info & ACB_PWNOTREQ)
safe_strcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33);
else
safe_strcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33);
}
}
/*! Decode the account control bits (ACB) info from a string. */
uint16 smbpasswd_decode_acb_info(const char *p)
{
uint16 acb_info = 0;
BOOL finished = False;
/*
* Check if the account type bits have been encoded after the
* NT password (in the form [NDHTUWSLXI]).
*/
if (*p != '[') return 0;
for (p++; *p && !finished; p++)
{
switch (*p) {
case 'N': /* 'N'o password. */
acb_info |= ACB_PWNOTREQ;
break;
case 'D': /* 'D'isabled. */
acb_info |= ACB_DISABLED;
break;
case 'H': /* 'H'omedir required. */
acb_info |= ACB_HOMDIRREQ;
break;
case 'T': /* 'T'emp account. */
acb_info |= ACB_TEMPDUP;
break;
case 'U': /* 'U'ser account (normal). */
acb_info |= ACB_NORMAL;
break;
case 'M': /* 'M'NS logon user account. What is this ? */
acb_info |= ACB_MNS;
break;
case 'W': /* 'W'orkstation account. */
acb_info |= ACB_WSTRUST;
break;
case 'S': /* 'S'erver account. */
acb_info |= ACB_SVRTRUST;
break;
case 'L': /* 'L'ocked account. */
acb_info |= ACB_AUTOLOCK;
break;
case 'X': /* No 'X'piry on password */
acb_info |= ACB_PWNOEXP;
break;
case 'I': /* 'I'nterdomain trust account. */
acb_info |= ACB_DOMTRUST;
break;
case ' ':
break;
case ':':
case '\n':
case '\0':
case ']':
default:
finished = True;
break;
}
}
return acb_info;
}
/*! Encode account control bits (ACBs) into a string. */
char *smbpasswd_encode_acb_info(uint16 acb_info)
{
static fstring acct_str;
size_t i = 0;
acct_str[i++] = '[';
if (acb_info & ACB_PWNOTREQ ) acct_str[i++] = 'N';
if (acb_info & ACB_DISABLED ) acct_str[i++] = 'D';
if (acb_info & ACB_HOMDIRREQ) acct_str[i++] = 'H';
if (acb_info & ACB_TEMPDUP ) acct_str[i++] = 'T';
if (acb_info & ACB_NORMAL ) acct_str[i++] = 'U';
if (acb_info & ACB_MNS ) acct_str[i++] = 'M';
if (acb_info & ACB_WSTRUST ) acct_str[i++] = 'W';
if (acb_info & ACB_SVRTRUST ) acct_str[i++] = 'S';
if (acb_info & ACB_AUTOLOCK ) acct_str[i++] = 'L';
if (acb_info & ACB_PWNOEXP ) acct_str[i++] = 'X';
if (acb_info & ACB_DOMTRUST ) acct_str[i++] = 'I';
for ( ; i < NEW_PW_FORMAT_SPACE_PADDED_LEN - 2 ; i++ )
acct_str[i] = ' ';
i = NEW_PW_FORMAT_SPACE_PADDED_LEN - 2;
acct_str[i++] = ']';
acct_str[i++] = '\0';
return acct_str;
}

171
source/lib/smbrun.c Normal file
View File

@@ -0,0 +1,171 @@
/*
Unix SMB/CIFS implementation.
run a command as a specified user
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"
/* need to move this from here!! need some sleep ... */
struct current_user current_user;
/****************************************************************************
This is a utility function of smbrun().
****************************************************************************/
static int setup_out_fd(void)
{
int fd;
pstring path;
slprintf(path, sizeof(path)-1, "%s/smb.XXXXXX", tmpdir());
/* now create the file */
fd = smb_mkstemp(path);
if (fd == -1) {
DEBUG(0,("setup_out_fd: Failed to create file %s. (%s)\n",
path, strerror(errno) ));
return -1;
}
DEBUG(10,("setup_out_fd: Created tmp file %s\n", path ));
/* Ensure file only kept around by open fd. */
unlink(path);
return fd;
}
/****************************************************************************
run a command being careful about uid/gid handling and putting the output in
outfd (or discard it if outfd is NULL).
****************************************************************************/
int smbrun(char *cmd, int *outfd)
{
pid_t pid;
uid_t uid = current_user.uid;
gid_t gid = current_user.gid;
/*
* Lose any kernel oplock capabilities we may have.
*/
oplock_set_capability(False, False);
/* point our stdout at the file we want output to go into */
if (outfd && ((*outfd = setup_out_fd()) == -1)) {
return -1;
}
/* in this method we will exec /bin/sh with the correct
arguments, after first setting stdout to point at the file */
/*
* We need to temporarily stop CatchChild from eating
* SIGCLD signals as it also eats the exit status code. JRA.
*/
CatchChildLeaveStatus();
if ((pid=fork()) < 0) {
DEBUG(0,("smbrun: fork failed with error %s\n", strerror(errno) ));
CatchChild();
if (outfd) {
close(*outfd);
*outfd = -1;
}
return errno;
}
if (pid) {
/*
* Parent.
*/
int status=0;
pid_t wpid;
/* the parent just waits for the child to exit */
while((wpid = sys_waitpid(pid,&status,0)) < 0) {
if(errno == EINTR) {
errno = 0;
continue;
}
break;
}
CatchChild();
if (wpid != pid) {
DEBUG(2,("waitpid(%d) : %s\n",(int)pid,strerror(errno)));
if (outfd) {
close(*outfd);
*outfd = -1;
}
return -1;
}
/* Reset the seek pointer. */
if (outfd) {
sys_lseek(*outfd, 0, SEEK_SET);
}
#if defined(WIFEXITED) && defined(WEXITSTATUS)
if (WIFEXITED(status)) {
return WEXITSTATUS(status);
}
#endif
return status;
}
CatchChild();
/* we are in the child. we exec /bin/sh to do the work for us. we
don't directly exec the command we want because it may be a
pipeline or anything else the config file specifies */
/* point our stdout at the file we want output to go into */
if (outfd) {
close(1);
if (sys_dup2(*outfd,1) != 1) {
DEBUG(2,("Failed to create stdout file descriptor\n"));
close(*outfd);
exit(80);
}
}
/* now completely lose our privileges. This is a fairly paranoid
way of doing it, but it does work on all systems that I know of */
become_user_permanently(uid, gid);
if (getuid() != uid || geteuid() != uid ||
getgid() != gid || getegid() != gid) {
/* we failed to lose our privileges - do not execute
the command */
exit(81); /* we can't print stuff at this stage,
instead use exit codes for debugging */
}
execl("/bin/sh","sh","-c",cmd,NULL);
/* not reached */
exit(82);
return 1;
}

978
source/lib/snprintf.c Normal file
View File

@@ -0,0 +1,978 @@
/*
* Copyright Patrick Powell 1995
* This code is based on code written by Patrick Powell (papowell@astart.com)
* It may be used for any purpose as long as this notice remains intact
* on all source code distributions
*/
/**************************************************************
* Original:
* Patrick Powell Tue Apr 11 09:48:21 PDT 1995
* A bombproof version of doprnt (dopr) included.
* Sigh. This sort of thing is always nasty do deal with. Note that
* the version here does not include floating point...
*
* snprintf() is used instead of sprintf() as it does limit checks
* for string length. This covers a nasty loophole.
*
* The other functions are there to prevent NULL pointers from
* causing nast effects.
*
* More Recently:
* Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
* This was ugly. It is still ugly. I opted out of floating point
* numbers, but the formatter understands just about everything
* from the normal C string format, at least as far as I can tell from
* the Solaris 2.5 printf(3S) man page.
*
* Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
* Ok, added some minimal floating point support, which means this
* probably requires libm on most operating systems. Don't yet
* support the exponent (e,E) and sigfig (g,G). Also, fmtint()
* was pretty badly broken, it just wasn't being exercised in ways
* which showed it, so that's been fixed. Also, formated the code
* to mutt conventions, and removed dead code left over from the
* original. Also, there is now a builtin-test, just compile with:
* gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
* and run snprintf for results.
*
* Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
* The PGP code was using unsigned hexadecimal formats.
* Unfortunately, unsigned formats simply didn't work.
*
* Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
* The original code assumed that both snprintf() and vsnprintf() were
* missing. Some systems only have snprintf() but not vsnprintf(), so
* the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
*
* Andrew Tridgell (tridge@samba.org) Oct 1998
* fixed handling of %.0f
* added test for HAVE_LONG_DOUBLE
*
* tridge@samba.org, idra@samba.org, April 2001
* got rid of fcvt code (twas buggy and made testing harder)
* added C99 semantics
*
**************************************************************/
#ifndef NO_CONFIG_H /* for some tests */
#include "config.h"
#else
#define NULL 0
#endif
#ifdef TEST_SNPRINTF /* need math library headers for testing */
#include <math.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
#include <sys/types.h>
#include <stdarg.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
/* only include stdio.h if we are not re-defining snprintf or vsnprintf */
#include <stdio.h>
/* make the compiler happy with an empty file */
void dummy_snprintf(void) {}
#else
#ifdef HAVE_LONG_DOUBLE
#define LDOUBLE long double
#else
#define LDOUBLE double
#endif
#ifdef HAVE_LONG_LONG
#define LLONG long long
#else
#define LLONG long
#endif
/* free memory if the pointer is valid and zero the pointer */
#ifndef SAFE_FREE
#define SAFE_FREE(x) do { if ((x) != NULL) {free((x)); (x)=NULL;} } while(0)
#endif
#ifndef VA_COPY
#ifdef HAVE_VA_COPY
#define VA_COPY(dest, src) __va_copy(dest, src)
#else
#define VA_COPY(dest, src) (dest) = (src)
#endif
#endif
static size_t dopr(char *buffer, size_t maxlen, const char *format,
va_list args_in);
static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
char *value, int flags, int min, int max);
static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
long value, int base, int min, int max, int flags);
static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
LDOUBLE fvalue, int min, int max, int flags);
static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
/*
* dopr(): poor man's version of doprintf
*/
/* format read states */
#define DP_S_DEFAULT 0
#define DP_S_FLAGS 1
#define DP_S_MIN 2
#define DP_S_DOT 3
#define DP_S_MAX 4
#define DP_S_MOD 5
#define DP_S_CONV 6
#define DP_S_DONE 7
/* format flags - Bits */
#define DP_F_MINUS (1 << 0)
#define DP_F_PLUS (1 << 1)
#define DP_F_SPACE (1 << 2)
#define DP_F_NUM (1 << 3)
#define DP_F_ZERO (1 << 4)
#define DP_F_UP (1 << 5)
#define DP_F_UNSIGNED (1 << 6)
/* Conversion Flags */
#define DP_C_SHORT 1
#define DP_C_LONG 2
#define DP_C_LDOUBLE 3
#define DP_C_LLONG 4
#define char_to_int(p) ((p)- '0')
#ifndef MAX
#define MAX(p,q) (((p) >= (q)) ? (p) : (q))
#endif
static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
{
char ch;
LLONG value;
LDOUBLE fvalue;
char *strvalue;
int min;
int max;
int state;
int flags;
int cflags;
size_t currlen;
va_list args;
VA_COPY(args, args_in);
state = DP_S_DEFAULT;
currlen = flags = cflags = min = 0;
max = -1;
ch = *format++;
while (state != DP_S_DONE) {
if (ch == '\0')
state = DP_S_DONE;
switch(state) {
case DP_S_DEFAULT:
if (ch == '%')
state = DP_S_FLAGS;
else
dopr_outch (buffer, &currlen, maxlen, ch);
ch = *format++;
break;
case DP_S_FLAGS:
switch (ch) {
case '-':
flags |= DP_F_MINUS;
ch = *format++;
break;
case '+':
flags |= DP_F_PLUS;
ch = *format++;
break;
case ' ':
flags |= DP_F_SPACE;
ch = *format++;
break;
case '#':
flags |= DP_F_NUM;
ch = *format++;
break;
case '0':
flags |= DP_F_ZERO;
ch = *format++;
break;
default:
state = DP_S_MIN;
break;
}
break;
case DP_S_MIN:
if (isdigit((unsigned char)ch)) {
min = 10*min + char_to_int (ch);
ch = *format++;
} else if (ch == '*') {
min = va_arg (args, int);
ch = *format++;
state = DP_S_DOT;
} else {
state = DP_S_DOT;
}
break;
case DP_S_DOT:
if (ch == '.') {
state = DP_S_MAX;
ch = *format++;
} else {
state = DP_S_MOD;
}
break;
case DP_S_MAX:
if (isdigit((unsigned char)ch)) {
if (max < 0)
max = 0;
max = 10*max + char_to_int (ch);
ch = *format++;
} else if (ch == '*') {
max = va_arg (args, int);
ch = *format++;
state = DP_S_MOD;
} else {
state = DP_S_MOD;
}
break;
case DP_S_MOD:
switch (ch) {
case 'h':
cflags = DP_C_SHORT;
ch = *format++;
break;
case 'l':
cflags = DP_C_LONG;
ch = *format++;
if (ch == 'l') { /* It's a long long */
cflags = DP_C_LLONG;
ch = *format++;
}
break;
case 'L':
cflags = DP_C_LDOUBLE;
ch = *format++;
break;
default:
break;
}
state = DP_S_CONV;
break;
case DP_S_CONV:
switch (ch) {
case 'd':
case 'i':
if (cflags == DP_C_SHORT)
value = va_arg (args, int);
else if (cflags == DP_C_LONG)
value = va_arg (args, long int);
else if (cflags == DP_C_LLONG)
value = va_arg (args, LLONG);
else
value = va_arg (args, int);
fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
break;
case 'o':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned int);
else if (cflags == DP_C_LONG)
value = (long)va_arg (args, unsigned long int);
else if (cflags == DP_C_LLONG)
value = (long)va_arg (args, unsigned LLONG);
else
value = (long)va_arg (args, unsigned int);
fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
break;
case 'u':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned int);
else if (cflags == DP_C_LONG)
value = (long)va_arg (args, unsigned long int);
else if (cflags == DP_C_LLONG)
value = (LLONG)va_arg (args, unsigned LLONG);
else
value = (long)va_arg (args, unsigned int);
fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
break;
case 'X':
flags |= DP_F_UP;
case 'x':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned int);
else if (cflags == DP_C_LONG)
value = (long)va_arg (args, unsigned long int);
else if (cflags == DP_C_LLONG)
value = (LLONG)va_arg (args, unsigned LLONG);
else
value = (long)va_arg (args, unsigned int);
fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
break;
case 'f':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
/* um, floating point? */
fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
break;
case 'E':
flags |= DP_F_UP;
case 'e':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
break;
case 'G':
flags |= DP_F_UP;
case 'g':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
break;
case 'c':
dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
break;
case 's':
strvalue = va_arg (args, char *);
if (!strvalue) strvalue = "(NULL)";
if (max == -1) {
max = strlen(strvalue);
}
if (min > 0 && max >= 0 && min > max) max = min;
fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
break;
case 'p':
strvalue = va_arg (args, void *);
fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
break;
case 'n':
if (cflags == DP_C_SHORT) {
short int *num;
num = va_arg (args, short int *);
*num = currlen;
} else if (cflags == DP_C_LONG) {
long int *num;
num = va_arg (args, long int *);
*num = (long int)currlen;
} else if (cflags == DP_C_LLONG) {
LLONG *num;
num = va_arg (args, LLONG *);
*num = (LLONG)currlen;
} else {
int *num;
num = va_arg (args, int *);
*num = currlen;
}
break;
case '%':
dopr_outch (buffer, &currlen, maxlen, ch);
break;
case 'w':
/* not supported yet, treat as next char */
ch = *format++;
break;
default:
/* Unknown, skip */
break;
}
ch = *format++;
state = DP_S_DEFAULT;
flags = cflags = min = 0;
max = -1;
break;
case DP_S_DONE:
break;
default:
/* hmm? */
break; /* some picky compilers need this */
}
}
if (maxlen != 0) {
if (currlen < maxlen - 1)
buffer[currlen] = '\0';
else if (maxlen > 0)
buffer[maxlen - 1] = '\0';
}
return currlen;
}
static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
char *value, int flags, int min, int max)
{
int padlen, strln; /* amount to pad */
int cnt = 0;
#ifdef DEBUG_SNPRINTF
printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
#endif
if (value == 0) {
value = "<NULL>";
}
for (strln = 0; value[strln]; ++strln); /* strlen */
padlen = min - strln;
if (padlen < 0)
padlen = 0;
if (flags & DP_F_MINUS)
padlen = -padlen; /* Left Justify */
while ((padlen > 0) && (cnt < max)) {
dopr_outch (buffer, currlen, maxlen, ' ');
--padlen;
++cnt;
}
while (*value && (cnt < max)) {
dopr_outch (buffer, currlen, maxlen, *value++);
++cnt;
}
while ((padlen < 0) && (cnt < max)) {
dopr_outch (buffer, currlen, maxlen, ' ');
++padlen;
++cnt;
}
}
/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
long value, int base, int min, int max, int flags)
{
int signvalue = 0;
unsigned long uvalue;
char convert[20];
int place = 0;
int spadlen = 0; /* amount to space pad */
int zpadlen = 0; /* amount to zero pad */
int caps = 0;
if (max < 0)
max = 0;
uvalue = value;
if(!(flags & DP_F_UNSIGNED)) {
if( value < 0 ) {
signvalue = '-';
uvalue = -value;
} else {
if (flags & DP_F_PLUS) /* Do a sign (+/i) */
signvalue = '+';
else if (flags & DP_F_SPACE)
signvalue = ' ';
}
}
if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
do {
convert[place++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")
[uvalue % (unsigned)base ];
uvalue = (uvalue / (unsigned)base );
} while(uvalue && (place < 20));
if (place == 20) place--;
convert[place] = 0;
zpadlen = max - place;
spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
if (zpadlen < 0) zpadlen = 0;
if (spadlen < 0) spadlen = 0;
if (flags & DP_F_ZERO) {
zpadlen = MAX(zpadlen, spadlen);
spadlen = 0;
}
if (flags & DP_F_MINUS)
spadlen = -spadlen; /* Left Justifty */
#ifdef DEBUG_SNPRINTF
printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
zpadlen, spadlen, min, max, place);
#endif
/* Spaces */
while (spadlen > 0) {
dopr_outch (buffer, currlen, maxlen, ' ');
--spadlen;
}
/* Sign */
if (signvalue)
dopr_outch (buffer, currlen, maxlen, signvalue);
/* Zeros */
if (zpadlen > 0) {
while (zpadlen > 0) {
dopr_outch (buffer, currlen, maxlen, '0');
--zpadlen;
}
}
/* Digits */
while (place > 0)
dopr_outch (buffer, currlen, maxlen, convert[--place]);
/* Left Justified spaces */
while (spadlen < 0) {
dopr_outch (buffer, currlen, maxlen, ' ');
++spadlen;
}
}
static LDOUBLE abs_val(LDOUBLE value)
{
LDOUBLE result = value;
if (value < 0)
result = -value;
return result;
}
static LDOUBLE POW10(int exp)
{
LDOUBLE result = 1;
while (exp) {
result *= 10;
exp--;
}
return result;
}
static LLONG ROUND(LDOUBLE value)
{
LLONG intpart;
intpart = (LLONG)value;
value = value - intpart;
if (value >= 0.5) intpart++;
return intpart;
}
/* a replacement for modf that doesn't need the math library. Should
be portable, but slow */
static double my_modf(double x0, double *iptr)
{
int i;
long l;
double x = x0;
double f = 1.0;
for (i=0;i<100;i++) {
l = (long)x;
if (l <= (x+1) && l >= (x-1)) break;
x *= 0.1;
f *= 10.0;
}
if (i == 100) {
/* yikes! the number is beyond what we can handle. What do we do? */
(*iptr) = 0;
return 0;
}
if (i != 0) {
double i2;
double ret;
ret = my_modf(x0-l*f, &i2);
(*iptr) = l*f + i2;
return ret;
}
(*iptr) = l;
return x - (*iptr);
}
static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
LDOUBLE fvalue, int min, int max, int flags)
{
int signvalue = 0;
double ufvalue;
char iconvert[311];
char fconvert[311];
int iplace = 0;
int fplace = 0;
int padlen = 0; /* amount to pad */
int zpadlen = 0;
int caps = 0;
int index;
double intpart;
double fracpart;
double temp;
/*
* AIX manpage says the default is 0, but Solaris says the default
* is 6, and sprintf on AIX defaults to 6
*/
if (max < 0)
max = 6;
ufvalue = abs_val (fvalue);
if (fvalue < 0) {
signvalue = '-';
} else {
if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
signvalue = '+';
} else {
if (flags & DP_F_SPACE)
signvalue = ' ';
}
}
#if 0
if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
#endif
#if 0
if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
#endif
/*
* Sorry, we only support 16 digits past the decimal because of our
* conversion method
*/
if (max > 16)
max = 16;
/* We "cheat" by converting the fractional part to integer by
* multiplying by a factor of 10
*/
temp = ufvalue;
my_modf(temp, &intpart);
fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
if (fracpart >= POW10(max)) {
intpart++;
fracpart -= POW10(max);
}
/* Convert integer part */
do {
temp = intpart*0.1;
my_modf(temp, &intpart);
index = (int) ((temp -intpart +0.05)* 10.0);
/* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
/* printf ("%llf, %f, %x\n", temp, intpart, index); */
iconvert[iplace++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")[index];
} while (intpart && (iplace < 311));
if (iplace == 311) iplace--;
iconvert[iplace] = 0;
/* Convert fractional part */
if (fracpart)
{
do {
temp = fracpart*0.1;
my_modf(temp, &fracpart);
index = (int) ((temp -fracpart +0.05)* 10.0);
/* index = (int) ((((temp/10) -fracpart) +0.05) *10); */
/* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */
fconvert[fplace++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")[index];
} while(fracpart && (fplace < 311));
if (fplace == 311) fplace--;
}
fconvert[fplace] = 0;
/* -1 for decimal point, another -1 if we are printing a sign */
padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
zpadlen = max - fplace;
if (zpadlen < 0) zpadlen = 0;
if (padlen < 0)
padlen = 0;
if (flags & DP_F_MINUS)
padlen = -padlen; /* Left Justifty */
if ((flags & DP_F_ZERO) && (padlen > 0)) {
if (signvalue) {
dopr_outch (buffer, currlen, maxlen, signvalue);
--padlen;
signvalue = 0;
}
while (padlen > 0) {
dopr_outch (buffer, currlen, maxlen, '0');
--padlen;
}
}
while (padlen > 0) {
dopr_outch (buffer, currlen, maxlen, ' ');
--padlen;
}
if (signvalue)
dopr_outch (buffer, currlen, maxlen, signvalue);
while (iplace > 0)
dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
#ifdef DEBUG_SNPRINTF
printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
#endif
/*
* Decimal point. This should probably use locale to find the correct
* char to print out.
*/
if (max > 0) {
dopr_outch (buffer, currlen, maxlen, '.');
while (zpadlen > 0) {
dopr_outch (buffer, currlen, maxlen, '0');
--zpadlen;
}
while (fplace > 0)
dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
}
while (padlen < 0) {
dopr_outch (buffer, currlen, maxlen, ' ');
++padlen;
}
}
static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
{
if (*currlen < maxlen) {
buffer[(*currlen)] = c;
}
(*currlen)++;
}
/* yes this really must be a ||. Don't muck with this (tridge) */
#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
{
return dopr(str, count, fmt, args);
}
#endif
/* yes this really must be a ||. Don't muck wiith this (tridge)
*
* The logic for these two is that we need our own definition if the
* OS *either* has no definition of *sprintf, or if it does have one
* that doesn't work properly according to the autoconf test. Perhaps
* these should really be smb_snprintf to avoid conflicts with buggy
* linkers? -- mbp
*/
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_SNPRINTF)
int snprintf(char *str,size_t count,const char *fmt,...)
{
size_t ret;
va_list ap;
va_start(ap, fmt);
ret = vsnprintf(str, count, fmt, ap);
va_end(ap);
return ret;
}
#endif
#endif
#ifndef HAVE_VASPRINTF
int vasprintf(char **ptr, const char *format, va_list ap)
{
int ret;
va_list ap2;
VA_COPY(ap2, ap);
ret = vsnprintf(NULL, 0, format, ap2);
if (ret <= 0) return ret;
(*ptr) = (char *)malloc(ret+1);
if (!*ptr) return -1;
VA_COPY(ap2, ap);
ret = vsnprintf(*ptr, ret+1, format, ap2);
return ret;
}
#endif
#ifndef HAVE_ASPRINTF
int asprintf(char **ptr, const char *format, ...)
{
va_list ap;
int ret;
*ptr = NULL;
va_start(ap, format);
ret = vasprintf(ptr, format, ap);
va_end(ap);
return ret;
}
#endif
#ifdef TEST_SNPRINTF
int sprintf(char *str,const char *fmt,...);
int main (void)
{
char buf1[1024];
char buf2[1024];
char *fp_fmt[] = {
"%1.1f",
"%-1.5f",
"%1.5f",
"%123.9f",
"%10.5f",
"% 10.5f",
"%+22.9f",
"%+4.9f",
"%01.3f",
"%4f",
"%3.1f",
"%3.2f",
"%.0f",
"%f",
"-16.16f",
NULL
};
double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
0.9996, 1.996, 4.136, 5.030201, 0};
char *int_fmt[] = {
"%-1.5d",
"%1.5d",
"%123.9d",
"%5.5d",
"%10.5d",
"% 10.5d",
"%+22.33d",
"%01.3d",
"%4d",
"%d",
NULL
};
long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
char *str_fmt[] = {
"10.5s",
"5.10s",
"10.1s",
"0.10s",
"10.0s",
"1.10s",
"%s",
"%.1s",
"%.10s",
"%10s",
NULL
};
char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
int x, y;
int fail = 0;
int num = 0;
printf ("Testing snprintf format codes against system sprintf...\n");
for (x = 0; fp_fmt[x] ; x++) {
for (y = 0; fp_nums[y] != 0 ; y++) {
int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]);
int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
sprintf (buf2, fp_fmt[x], fp_nums[y]);
if (strcmp (buf1, buf2)) {
printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
fp_fmt[x], buf1, buf2);
fail++;
}
if (l1 != l2) {
printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]);
fail++;
}
num++;
}
}
for (x = 0; int_fmt[x] ; x++) {
for (y = 0; int_nums[y] != 0 ; y++) {
int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]);
int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
sprintf (buf2, int_fmt[x], int_nums[y]);
if (strcmp (buf1, buf2)) {
printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
int_fmt[x], buf1, buf2);
fail++;
}
if (l1 != l2) {
printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]);
fail++;
}
num++;
}
}
for (x = 0; str_fmt[x] ; x++) {
for (y = 0; str_vals[y] != 0 ; y++) {
int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]);
int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
sprintf (buf2, str_fmt[x], str_vals[y]);
if (strcmp (buf1, buf2)) {
printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
str_fmt[x], buf1, buf2);
fail++;
}
if (l1 != l2) {
printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]);
fail++;
}
num++;
}
}
printf ("%d tests failed out of %d.\n", fail, num);
printf("seeing how many digits we support\n");
{
double v0 = 0.12345678901234567890123456789012345678901;
for (x=0; x<100; x++) {
double p = pow(10, x);
double r = v0*p;
snprintf(buf1, sizeof(buf1), "%1.1f", r);
sprintf(buf2, "%1.1f", r);
if (strcmp(buf1, buf2)) {
printf("we seem to support %d digits\n", x-1);
break;
}
}
}
return 0;
}
#endif /* SNPRINTF_TEST */

188
source/lib/substitute.c Normal file
View File

@@ -0,0 +1,188 @@
/*
Unix SMB/CIFS implementation.
string substitution functions
Copyright (C) Andrew Tridgell 1992-2000
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
/* oh bugger - I realy didn't want to have a top-level context
anywhere, but until we change all lp_*() calls to take a context
argument this is needed */
static struct substitute_context *sub;
void sub_set_context(struct substitute_context *subptr)
{
sub = subptr;
}
/*
setup a string in the negotiate structure, using alpha_strcpy with SAFE_NETBIOS_CHARS
*/
static void setup_string(char **dest, const char *str)
{
char *s;
s = strdup(str);
if (!s) {
return;
}
alpha_strcpy(s, str, SAFE_NETBIOS_CHARS, strlen(s)+1);
trim_string(s," "," ");
strlower(s);
SAFE_FREE(*dest);
(*dest) = s;
}
void sub_set_local_machine(const char *local_machine)
{
if (!sub) return;
setup_string(&sub->local_machine, local_machine);
}
void sub_set_remote_machine(const char *remote_machine)
{
if (!sub) return;
setup_string(&sub->remote_machine, remote_machine);
}
void sub_set_remote_proto(const char *str)
{
if (!sub) return;
setup_string(&sub->remote_proto, str);
}
void sub_set_remote_arch(const char *str)
{
if (!sub) return;
setup_string(&sub->remote_arch, str);
}
const char *sub_get_remote_machine(void)
{
if (!sub) return "UNKNOWN";
return sub->remote_machine;
}
const char *sub_get_local_machine(void)
{
if (!sub) return "UNKNOWN";
return sub->local_machine;
}
/*
setup the string used by %U substitution
*/
void sub_set_user_name(const char *name)
{
if (!sub) return;
setup_string(&sub->user_name, name);
}
/****************************************************************************
FOO
****************************************************************************/
void standard_sub_basic(char *str,size_t len)
{
}
/****************************************************************************
Do some standard substitutions in a string.
This function will return an allocated string that have to be freed.
****************************************************************************/
char *talloc_sub_basic(TALLOC_CTX *mem_ctx, const char *smb_name, const char *str)
{
return talloc_strdup(mem_ctx, str);
}
char *alloc_sub_basic(const char *smb_name, const char *str)
{
return strdup(str);
}
/****************************************************************************
Do some specific substitutions in a string.
This function will return an allocated string that have to be freed.
****************************************************************************/
char *talloc_sub_specified(TALLOC_CTX *mem_ctx,
const char *input_string,
const char *username,
const char *domain,
uid_t uid,
gid_t gid)
{
return talloc_strdup(mem_ctx, input_string);
}
char *alloc_sub_specified(const char *input_string,
const char *username,
const char *domain,
uid_t uid,
gid_t gid)
{
return strdup(input_string);
}
char *talloc_sub_advanced(TALLOC_CTX *mem_ctx,
int snum,
const char *user,
const char *connectpath,
gid_t gid,
const char *smb_name,
char *str)
{
return talloc_strdup(mem_ctx, str);
}
char *alloc_sub_advanced(int snum, const char *user,
const char *connectpath, gid_t gid,
const char *smb_name, char *str)
{
return strdup(str);
}
/****************************************************************************
Do some standard substitutions in a string.
****************************************************************************/
void standard_sub_conn(struct tcon_context *conn, char *str, size_t len)
{
}
char *talloc_sub_conn(TALLOC_CTX *mem_ctx, struct tcon_context *conn, char *str)
{
return talloc_strdup(mem_ctx, str);
}
char *alloc_sub_conn(struct tcon_context *conn, char *str)
{
return strdup(str);
}
/****************************************************************************
Like standard_sub but by snum.
****************************************************************************/
void standard_sub_snum(int snum, char *str, size_t len)
{
}

3198
source/lib/sysacls.c Normal file

File diff suppressed because it is too large Load Diff

1114
source/lib/system.c Normal file

File diff suppressed because it is too large Load Diff

119
source/lib/system_smbd.c Normal file
View File

@@ -0,0 +1,119 @@
/*
Unix SMB/CIFS implementation.
system call wrapper interface.
Copyright (C) Andrew Tridgell 2002
Copyright (C) Andrew Barteltt 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.
*/
/*
This file may assume linkage with smbd - for things like become_root()
etc.
*/
#include "includes.h"
#ifndef HAVE_GETGROUPLIST
/*
This is a *much* faster way of getting the list of groups for a user
without changing the current supplemenrary group list. The old
method used getgrent() which could take 20 minutes on a really big
network with hundeds of thousands of groups and users. The new method
takes a couple of seconds.
NOTE!! this function only works if it is called as root!
*/
static int getgrouplist_internals(const char *user, gid_t gid, gid_t *groups, int *grpcnt)
{
gid_t *gids_saved;
int ret, ngrp_saved, num_gids;
if (non_root_mode()) {
*grpcnt = 0;
return 0;
}
/* work out how many groups we need to save */
ngrp_saved = getgroups(0, NULL);
if (ngrp_saved == -1) {
/* this shouldn't happen */
return -1;
}
gids_saved = (gid_t *)malloc(sizeof(gid_t) * (ngrp_saved+1));
if (!gids_saved) {
errno = ENOMEM;
return -1;
}
ngrp_saved = getgroups(ngrp_saved, gids_saved);
if (ngrp_saved == -1) {
SAFE_FREE(gids_saved);
/* very strange! */
return -1;
}
if (initgroups(user, gid) != 0) {
DEBUG(0, ("getgrouplist_internals: initgroups() failed!\n"));
SAFE_FREE(gids_saved);
return -1;
}
/* this must be done to cope with systems that put the current egid in the
return from getgroups() */
save_re_gid();
set_effective_gid(gid);
setgid(gid);
num_gids = getgroups(0, NULL);
if (num_gids + 1 > *grpcnt) {
*grpcnt = num_gids + 1;
ret = -1;
} else {
ret = getgroups(*grpcnt - 1, &groups[1]);
if (ret >= 0) {
groups[0] = gid;
*grpcnt = ret + 1;
}
}
restore_re_gid();
if (setgroups(ngrp_saved, gids_saved) != 0) {
/* yikes! */
DEBUG(0,("ERROR: getgrouplist: failed to reset group list!\n"));
smb_panic("getgrouplist: failed to reset group list!\n");
free(gids_saved);
return -1;
}
free(gids_saved);
return ret;
}
#endif
int sys_getgrouplist(const char *user, gid_t gid, gid_t *groups, int *grpcnt)
{
#ifdef HAVE_GETGROUPLIST
return getgrouplist(user, gid, groups, grpcnt);
#else
int retval;
become_root();
retval = getgrouplist_internals(user, gid, groups, grpcnt);
unbecome_root();
return retval;
#endif
}

515
source/lib/talloc.c Normal file
View File

@@ -0,0 +1,515 @@
/*
Samba Unix SMB/CIFS implementation.
Samba temporary memory allocation functions
Copyright (C) Andrew Tridgell 2000
Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
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.
*/
/**
@defgroup talloc Simple memory allocator
@{
This is a very simple temporary memory allocator. To use it do the following:
1) when you first want to allocate a pool of meomry use
talloc_init() and save the resulting context pointer somewhere
2) to allocate memory use talloc()
3) when _all_ of the memory allocated using this context is no longer needed
use talloc_destroy()
talloc does not zero the memory. It guarantees memory of a
TALLOC_ALIGN alignment
@sa talloc.h
*/
/**
* @todo We could allocate both the talloc_chunk structure, and the
* memory it contains all in one allocation, which might be a bit
* faster and perhaps use less memory overhead.
*
* That smells like a premature optimization, though. -- mbp
**/
/**
* If you want testing for memory corruption, link with dmalloc or use
* Insure++. It doesn't seem useful to duplicate them here.
**/
#include "includes.h"
struct talloc_chunk {
struct talloc_chunk *next;
size_t size;
void *ptr;
};
struct talloc_ctx {
struct talloc_chunk *list;
off_t total_alloc_size;
/** The name recorded for this pool, if any. Should describe
* the purpose for which it was allocated. The string is
* allocated within the pool. **/
char *name;
/** Pointer to the next allocate talloc pool, so that we can
* summarize all talloc memory usage. **/
struct talloc_ctx *next, *prev;
};
/**
* Start of linked list of all talloc pools.
*
* @todo We should turn the global list off when using Insure++,
* otherwise all the memory will be seen as still reachable.
**/
static TALLOC_CTX *list_head;
/**
* Add to the global list
**/
static void talloc_enroll(TALLOC_CTX *t)
{
#if 0
/* disabled enrole/disenrole until we have __thread support */
MUTEX_LOCK_BY_ID(MUTEX_TALLOC);
DLIST_ADD(list_head, t);
MUTEX_UNLOCK_BY_ID(MUTEX_TALLOC);
#endif
}
static void talloc_disenroll(TALLOC_CTX *t)
{
#if 0
/* disabled enrole/disenrole until we have __thread support */
MUTEX_LOCK_BY_ID(MUTEX_TALLOC);
DLIST_REMOVE(list_head, t);
MUTEX_UNLOCK_BY_ID(MUTEX_TALLOC);
#endif
}
/** Create a new talloc context. **/
static TALLOC_CTX *talloc_init_internal(void)
{
TALLOC_CTX *t;
t = (TALLOC_CTX *)malloc(sizeof(TALLOC_CTX));
if (t) {
t->list = NULL;
t->total_alloc_size = 0;
t->name = NULL;
talloc_enroll(t);
}
return t;
}
/**
* Create a new talloc context, with a name specifying its purpose.
**/
TALLOC_CTX *talloc_init(char const *fmt, ...)
{
TALLOC_CTX *t;
va_list ap;
t = talloc_init_internal();
if (t && fmt) {
/*
* t->name must not be talloced.
* as destroying the pool would destroy it. JRA.
*/
t->name = NULL;
va_start(ap, fmt);
vasprintf(&t->name, fmt, ap);
va_end(ap);
if (!t->name) {
talloc_destroy(t);
t = NULL;
}
}
return t;
}
/** Allocate a bit of memory from the specified pool **/
void *talloc(TALLOC_CTX *t, size_t size)
{
void *p;
struct talloc_chunk *tc;
if (!t || size == 0) return NULL;
p = malloc(size);
if (p) {
tc = malloc(sizeof(*tc));
if (tc) {
tc->ptr = p;
tc->size = size;
tc->next = t->list;
t->list = tc;
t->total_alloc_size += size;
}
else {
SAFE_FREE(p);
}
}
return p;
}
/** A talloc version of realloc */
void *talloc_realloc(TALLOC_CTX *t, void *ptr, size_t size)
{
struct talloc_chunk *tc;
void *new_ptr;
/* size zero is equivalent to free() */
if (!t || size == 0)
return NULL;
/* realloc(NULL) is equavalent to malloc() */
if (ptr == NULL)
return talloc(t, size);
for (tc=t->list; tc; tc=tc->next) {
if (tc->ptr == ptr) {
new_ptr = Realloc(ptr, size);
if (new_ptr) {
t->total_alloc_size += (size - tc->size);
tc->size = size;
tc->ptr = new_ptr;
}
return new_ptr;
}
}
return NULL;
}
/** Destroy all the memory allocated inside @p t, but not @p t
* itself. */
void talloc_destroy_pool(TALLOC_CTX *t)
{
struct talloc_chunk *c;
if (!t)
return;
while (t->list) {
c = t->list->next;
SAFE_FREE(t->list->ptr);
SAFE_FREE(t->list);
t->list = c;
}
t->total_alloc_size = 0;
}
/** Destroy a whole pool including the context */
void talloc_destroy(TALLOC_CTX *t)
{
if (!t)
return;
talloc_destroy_pool(t);
talloc_disenroll(t);
SAFE_FREE(t->name);
SAFE_FREE(t);
}
/** Return the current total size of the pool. */
size_t talloc_pool_size(TALLOC_CTX *t)
{
return t->total_alloc_size;
}
const char *talloc_pool_name(TALLOC_CTX const *t)
{
if (t) return t->name;
return NULL;
}
/** talloc and zero memory. */
void *talloc_zero(TALLOC_CTX *t, size_t size)
{
void *p = talloc(t, size);
if (p) {
memset(p, '\0', size);
}
return p;
}
/** memdup with a talloc. */
void *talloc_memdup(TALLOC_CTX *t, const void *p, size_t size)
{
void *newp = talloc(t,size);
if (newp) {
memcpy(newp, p, size);
}
return newp;
}
/** strdup with a talloc */
char *talloc_strdup(TALLOC_CTX *t, const char *p)
{
return talloc_memdup(t, p, strlen(p) + 1);
}
/** strndup with a talloc */
char *talloc_strndup(TALLOC_CTX *t, const char *p, size_t n)
{
size_t len = strnlen(p, n);
char *ret;
ret = talloc(t, len + 1);
if (!ret) { return NULL; }
memcpy(ret, p, len);
ret[len] = 0;
return ret;
}
/** strdup_w with a talloc */
smb_ucs2_t *talloc_strdup_w(TALLOC_CTX *t, const smb_ucs2_t *p)
{
if (p)
return talloc_memdup(t, p, (strlen_w(p) + 1) * sizeof(smb_ucs2_t));
return NULL;
}
/**
* Perform string formatting, and return a pointer to newly allocated
* memory holding the result, inside a memory pool.
**/
char *talloc_asprintf(TALLOC_CTX *t, const char *fmt, ...)
{
va_list ap;
char *ret;
va_start(ap, fmt);
ret = talloc_vasprintf(t, fmt, ap);
va_end(ap);
return ret;
}
char *talloc_vasprintf(TALLOC_CTX *t, const char *fmt, va_list ap)
{
int len;
char *ret;
va_list ap2;
VA_COPY(ap2, ap);
len = vsnprintf(NULL, 0, fmt, ap2);
ret = talloc(t, len+1);
if (ret) {
VA_COPY(ap2, ap);
vsnprintf(ret, len+1, fmt, ap2);
}
return ret;
}
/**
* Realloc @p s to append the formatted result of @p fmt and return @p
* s, which may have moved. Good for gradually accumulating output
* into a string buffer.
**/
char *talloc_asprintf_append(TALLOC_CTX *t, char *s,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
s = talloc_vasprintf_append(t, s, fmt, ap);
va_end(ap);
return s;
}
/**
* Realloc @p s to append the formatted result of @p fmt and @p ap,
* and return @p s, which may have moved. Good for gradually
* accumulating output into a string buffer.
**/
char *talloc_vasprintf_append(TALLOC_CTX *t, char *s,
const char *fmt, va_list ap)
{
int len, s_len;
va_list ap2;
VA_COPY(ap2, ap);
s_len = strlen(s);
len = vsnprintf(NULL, 0, fmt, ap2);
s = talloc_realloc(t, s, s_len + len+1);
if (!s) return NULL;
VA_COPY(ap2, ap);
vsnprintf(s+s_len, len+1, fmt, ap2);
return s;
}
/**
* Return a human-readable description of all talloc memory usage.
* The result is allocated from @p t.
**/
char *talloc_describe_all(TALLOC_CTX *rt)
{
int n_pools = 0, total_chunks = 0;
size_t total_bytes = 0;
TALLOC_CTX *it;
char *s;
if (!rt) return NULL;
s = talloc_asprintf(rt, "global talloc allocations in pid: %u\n",
(unsigned) getpid());
s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n",
"name", "chunks", "bytes");
s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n",
"----------------------------------------",
"--------",
"--------");
MUTEX_LOCK_BY_ID(MUTEX_TALLOC);
for (it = list_head; it; it = it->next) {
size_t bytes;
int n_chunks;
fstring what;
n_pools++;
talloc_get_allocation(it, &bytes, &n_chunks);
if (it->name)
fstrcpy(what, it->name);
else
slprintf(what, sizeof(what), "@%p", it);
s = talloc_asprintf_append(rt, s, "%-40s %8u %8u\n",
what,
(unsigned) n_chunks,
(unsigned) bytes);
total_bytes += bytes;
total_chunks += n_chunks;
}
MUTEX_UNLOCK_BY_ID(MUTEX_TALLOC);
s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n",
"----------------------------------------",
"--------",
"--------");
s = talloc_asprintf_append(rt, s, "%-40s %8u %8u\n",
"TOTAL",
(unsigned) total_chunks, (unsigned) total_bytes);
return s;
}
/**
* Return an estimated memory usage for the specified pool. This does
* not include memory used by the underlying malloc implementation.
**/
void talloc_get_allocation(TALLOC_CTX *t,
size_t *total_bytes,
int *n_chunks)
{
struct talloc_chunk *chunk;
if (t) {
*total_bytes = 0;
*n_chunks = 0;
for (chunk = t->list; chunk; chunk = chunk->next) {
n_chunks[0]++;
*total_bytes += chunk->size;
}
}
}
/*
move a lump of memory from one talloc context to another
return the ptr on success, or NULL if it could not be found
in the old context or could not be transferred
*/
const void *talloc_steal(TALLOC_CTX *old_ctx, TALLOC_CTX *new_ctx, const void *ptr)
{
struct talloc_chunk *tc, *tc2;
if (!ptr || !old_ctx->list) return NULL;
/* as a special case, see if its the first element in the
list */
if (old_ctx->list->ptr == ptr) {
tc = old_ctx->list;
old_ctx->list = old_ctx->list->next;
tc->next = new_ctx->list;
new_ctx->list = tc;
old_ctx->total_alloc_size -= tc->size;
new_ctx->total_alloc_size += tc->size;
return ptr;
}
/* find it in the old context */
for (tc=old_ctx->list; tc->next; tc=tc->next) {
if (tc->next->ptr == ptr) break;
}
if (!tc->next) return NULL;
/* move it to the new context */
tc2 = tc->next;
tc->next = tc->next->next;
tc2->next = new_ctx->list;
new_ctx->list = tc2;
old_ctx->total_alloc_size -= tc2->size;
new_ctx->total_alloc_size += tc2->size;
return ptr;
}
/** @} */

58
source/lib/tallocmsg.c Normal file
View File

@@ -0,0 +1,58 @@
/*
samba -- Unix SMB/CIFS implementation.
Copyright (C) 2001, 2002 by Martin Pool
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 tallocmsg.c
*
* Glue code between talloc profiling and the Samba messaging system.
**/
/**
* Respond to a POOL_USAGE message by sending back string form of memory
* usage stats.
**/
void msg_pool_usage(int msg_type, pid_t src_pid,
void *UNUSED(buf), size_t UNUSED(len))
{
char *reply;
TALLOC_CTX *reply_pool = talloc_init("msg_pool_usage");
SMB_ASSERT(msg_type == MSG_REQ_POOL_USAGE);
DEBUG(2,("Got POOL_USAGE\n"));
reply = talloc_describe_all(reply_pool);
message_send_pid(src_pid, MSG_POOL_USAGE,
reply, strlen(reply)+1, True);
talloc_destroy(reply_pool);
}
/**
* Register handler for MSG_REQ_POOL_USAGE
**/
void register_msg_pool_usage(void)
{
message_register(MSG_REQ_POOL_USAGE, msg_pool_usage);
DEBUG(2, ("Registered MSG_REQ_POOL_USAGE\n"));
}

65
source/lib/talloctort.c Normal file
View File

@@ -0,0 +1,65 @@
/*
Unix SMB/CIFS implementation.
Samba temporary memory allocation functions -- torturer
Copyright (C) 2001 by Martin Pool <mbp@samba.org>
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"
#define NCTX 10
#define NOBJ 20
int main(void)
{
int i;
TALLOC_CTX *ctx[NCTX];
for (i = 0; i < NCTX; i++) {
ctx[i] = talloc_init("torture(%d)", i);
}
for (i = 0; i < NCTX; i++) {
int j;
for (j = 0; j < NOBJ; j++) {
char *p;
size_t size = 1<<(i/3+j);
p = talloc(ctx[i], size);
if (!p) {
fprintf(stderr,
"failed to talloc %.0f bytes\n",
(double) size);
exit(1);
}
memset(p, 'A' + j, size);
}
}
for (i = 0; i < NCTX; i++) {
printf("talloc@%p %-40s %dkB\n", ctx[i],
talloc_pool_name(ctx[i]),
talloc_pool_size(ctx[i]) >> 10);
}
printf("%s", talloc_describe_all(ctx[0]));
for (i = NCTX - 1; i >= 0; i--)
talloc_destroy(ctx[i]);
return 0;
}

167
source/lib/tdb/README Normal file
View File

@@ -0,0 +1,167 @@
tdb - a trivial database system
tridge@linuxcare.com December 1999
==================================
This is a simple database API. It was inspired by the realisation that
in Samba we have several ad-hoc bits of code that essentially
implement small databases for sharing structures between parts of
Samba. As I was about to add another I realised that a generic
database module was called for to replace all the ad-hoc bits.
I based the interface on gdbm. I couldn't use gdbm as we need to be
able to have multiple writers to the databases at one time.
Compilation
-----------
add HAVE_MMAP=1 to use mmap instead of read/write
add TDB_DEBUG=1 for verbose debug info
add NOLOCK=1 to disable locking code
Testing
-------
Compile tdbtest.c and link with gdbm for testing. tdbtest will perform
identical operations via tdb and gdbm then make sure the result is the
same
Also included is tdbtool, which allows simple database manipulation
on the commandline.
tdbtest and tdbtool are not built as part of Samba, but are included
for completeness.
Interface
---------
The interface is very similar to gdbm except for the following:
- different open interface. The tdb_open call is more similar to a
traditional open()
- no tdbm_reorganise() function
- no tdbm_sync() function. No operations are cached in the library anyway
- added a tdb_traverse() function for traversing the whole database
A general rule for using tdb is that the caller frees any returned
TDB_DATA structures. Just call free(p.dptr) to free a TDB_DATA
return value called p. This is the same as gdbm.
here is a full list of tdb functions with brief descriptions.
----------------------------------------------------------------------
TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
int open_flags, mode_t mode)
open the database, creating it if necessary
The open_flags and mode are passed straight to the open call on the database
file. A flags value of O_WRONLY is invalid
The hash size is advisory, use zero for a default value.
return is NULL on error
possible tdb_flags are:
TDB_CLEAR_IF_FIRST - clear database if we are the only one with it open
TDB_INTERNAL - don't use a file, instaed store the data in
memory. The filename is ignored in this case.
TDB_NOLOCK - don't do any locking
TDB_NOMMAP - don't use mmap
----------------------------------------------------------------------
char *tdb_error(TDB_CONTEXT *tdb);
return a error string for the last tdb error
----------------------------------------------------------------------
int tdb_close(TDB_CONTEXT *tdb);
close a database
----------------------------------------------------------------------
int tdb_update(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf);
update an entry in place - this only works if the new data size
is <= the old data size and the key exists.
on failure return -1
----------------------------------------------------------------------
TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key);
fetch an entry in the database given a key
if the return value has a null dptr then a error occurred
caller must free the resulting data
----------------------------------------------------------------------
int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key);
check if an entry in the database exists
note that 1 is returned if the key is found and 0 is returned if not found
this doesn't match the conventions in the rest of this module, but is
compatible with gdbm
----------------------------------------------------------------------
int tdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb,
TDB_DATA key, TDB_DATA dbuf, void *state), void *state);
traverse the entire database - calling fn(tdb, key, data, state) on each
element.
return -1 on error or the record count traversed
if fn is NULL then it is not called
a non-zero return value from fn() indicates that the traversal should stop
----------------------------------------------------------------------
TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb);
find the first entry in the database and return its key
the caller must free the returned data
----------------------------------------------------------------------
TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key);
find the next entry in the database, returning its key
the caller must free the returned data
----------------------------------------------------------------------
int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key);
delete an entry in the database given a key
----------------------------------------------------------------------
int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
store an element in the database, replacing any existing element
with the same key
If flag==TDB_INSERT then don't overwrite an existing entry
If flag==TDB_MODIFY then don't create a new entry
return 0 on success, -1 on failure
----------------------------------------------------------------------
int tdb_writelock(TDB_CONTEXT *tdb);
lock the database. If we already have it locked then don't do anything
----------------------------------------------------------------------
int tdb_writeunlock(TDB_CONTEXT *tdb);
unlock the database
----------------------------------------------------------------------
int tdb_lockchain(TDB_CONTEXT *tdb, TDB_DATA key);
lock one hash chain. This is meant to be used to reduce locking
contention - it cannot guarantee how many records will be locked
----------------------------------------------------------------------
int tdb_unlockchain(TDB_CONTEXT *tdb, TDB_DATA key);
unlock one hash chain

430
source/lib/tdb/spinlock.c Normal file
View File

@@ -0,0 +1,430 @@
/*
Unix SMB/CIFS implementation.
Samba database functions
Copyright (C) Anton Blanchard 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.
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#if STANDALONE
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <time.h>
#include <signal.h>
#include "tdb.h"
#include "spinlock.h"
#define DEBUG
#else
#include "includes.h"
#endif
#ifdef USE_SPINLOCKS
/*
* ARCH SPECIFIC
*/
#if defined(SPARC_SPINLOCKS)
static inline int __spin_trylock(spinlock_t *lock)
{
unsigned int result;
asm volatile("ldstub [%1], %0"
: "=r" (result)
: "r" (lock)
: "memory");
return (result == 0) ? 0 : EBUSY;
}
static inline void __spin_unlock(spinlock_t *lock)
{
asm volatile("":::"memory");
*lock = 0;
}
static inline void __spin_lock_init(spinlock_t *lock)
{
*lock = 0;
}
static inline int __spin_is_locked(spinlock_t *lock)
{
return (*lock != 0);
}
#elif defined(POWERPC_SPINLOCKS)
static inline int __spin_trylock(spinlock_t *lock)
{
unsigned int result;
__asm__ __volatile__(
"1: lwarx %0,0,%1\n\
cmpwi 0,%0,0\n\
li %0,0\n\
bne- 2f\n\
li %0,1\n\
stwcx. %0,0,%1\n\
bne- 1b\n\
isync\n\
2:" : "=&r"(result)
: "r"(lock)
: "cr0", "memory");
return (result == 1) ? 0 : EBUSY;
}
static inline void __spin_unlock(spinlock_t *lock)
{
asm volatile("eieio":::"memory");
*lock = 0;
}
static inline void __spin_lock_init(spinlock_t *lock)
{
*lock = 0;
}
static inline int __spin_is_locked(spinlock_t *lock)
{
return (*lock != 0);
}
#elif defined(INTEL_SPINLOCKS)
static inline int __spin_trylock(spinlock_t *lock)
{
int oldval;
asm volatile("xchgl %0,%1"
: "=r" (oldval), "=m" (*lock)
: "0" (0)
: "memory");
return oldval > 0 ? 0 : EBUSY;
}
static inline void __spin_unlock(spinlock_t *lock)
{
asm volatile("":::"memory");
*lock = 1;
}
static inline void __spin_lock_init(spinlock_t *lock)
{
*lock = 1;
}
static inline int __spin_is_locked(spinlock_t *lock)
{
return (*lock != 1);
}
#elif defined(MIPS_SPINLOCKS)
static inline unsigned int load_linked(unsigned long addr)
{
unsigned int res;
__asm__ __volatile__("ll\t%0,(%1)"
: "=r" (res)
: "r" (addr));
return res;
}
static inline unsigned int store_conditional(unsigned long addr, unsigned int value)
{
unsigned int res;
__asm__ __volatile__("sc\t%0,(%2)"
: "=r" (res)
: "0" (value), "r" (addr));
return res;
}
static inline int __spin_trylock(spinlock_t *lock)
{
unsigned int mw;
do {
mw = load_linked(lock);
if (mw)
return EBUSY;
} while (!store_conditional(lock, 1));
asm volatile("":::"memory");
return 0;
}
static inline void __spin_unlock(spinlock_t *lock)
{
asm volatile("":::"memory");
*lock = 0;
}
static inline void __spin_lock_init(spinlock_t *lock)
{
*lock = 0;
}
static inline int __spin_is_locked(spinlock_t *lock)
{
return (*lock != 0);
}
#else
#error Need to implement spinlock code in spinlock.c
#endif
/*
* OS SPECIFIC
*/
static void yield_cpu(void)
{
struct timespec tm;
#ifdef USE_SCHED_YIELD
sched_yield();
#else
/* Linux will busy loop for delays < 2ms on real time tasks */
tm.tv_sec = 0;
tm.tv_nsec = 2000000L + 1;
nanosleep(&tm, NULL);
#endif
}
static int this_is_smp(void)
{
return 0;
}
/*
* GENERIC
*/
static int smp_machine = 0;
static inline void __spin_lock(spinlock_t *lock)
{
int ntries = 0;
while(__spin_trylock(lock)) {
while(__spin_is_locked(lock)) {
if (smp_machine && ntries++ < MAX_BUSY_LOOPS)
continue;
yield_cpu();
}
}
}
static void __read_lock(tdb_rwlock_t *rwlock)
{
int ntries = 0;
while(1) {
__spin_lock(&rwlock->lock);
if (!(rwlock->count & RWLOCK_BIAS)) {
rwlock->count++;
__spin_unlock(&rwlock->lock);
return;
}
__spin_unlock(&rwlock->lock);
while(rwlock->count & RWLOCK_BIAS) {
if (smp_machine && ntries++ < MAX_BUSY_LOOPS)
continue;
yield_cpu();
}
}
}
static void __write_lock(tdb_rwlock_t *rwlock)
{
int ntries = 0;
while(1) {
__spin_lock(&rwlock->lock);
if (rwlock->count == 0) {
rwlock->count |= RWLOCK_BIAS;
__spin_unlock(&rwlock->lock);
return;
}
__spin_unlock(&rwlock->lock);
while(rwlock->count != 0) {
if (smp_machine && ntries++ < MAX_BUSY_LOOPS)
continue;
yield_cpu();
}
}
}
static void __write_unlock(tdb_rwlock_t *rwlock)
{
__spin_lock(&rwlock->lock);
#ifdef DEBUG
if (!(rwlock->count & RWLOCK_BIAS))
fprintf(stderr, "bug: write_unlock\n");
#endif
rwlock->count &= ~RWLOCK_BIAS;
__spin_unlock(&rwlock->lock);
}
static void __read_unlock(tdb_rwlock_t *rwlock)
{
__spin_lock(&rwlock->lock);
#ifdef DEBUG
if (!rwlock->count)
fprintf(stderr, "bug: read_unlock\n");
if (rwlock->count & RWLOCK_BIAS)
fprintf(stderr, "bug: read_unlock\n");
#endif
rwlock->count--;
__spin_unlock(&rwlock->lock);
}
/* TDB SPECIFIC */
/* lock a list in the database. list -1 is the alloc list */
int tdb_spinlock(TDB_CONTEXT *tdb, int list, int rw_type)
{
tdb_rwlock_t *rwlocks;
if (!tdb->map_ptr) return -1;
rwlocks = (tdb_rwlock_t *)((char *)tdb->map_ptr + tdb->header.rwlocks);
switch(rw_type) {
case F_RDLCK:
__read_lock(&rwlocks[list+1]);
break;
case F_WRLCK:
__write_lock(&rwlocks[list+1]);
break;
default:
return TDB_ERRCODE(TDB_ERR_LOCK, -1);
}
return 0;
}
/* unlock the database. */
int tdb_spinunlock(TDB_CONTEXT *tdb, int list, int rw_type)
{
tdb_rwlock_t *rwlocks;
if (!tdb->map_ptr) return -1;
rwlocks = (tdb_rwlock_t *)((char *)tdb->map_ptr + tdb->header.rwlocks);
switch(rw_type) {
case F_RDLCK:
__read_unlock(&rwlocks[list+1]);
break;
case F_WRLCK:
__write_unlock(&rwlocks[list+1]);
break;
default:
return TDB_ERRCODE(TDB_ERR_LOCK, -1);
}
return 0;
}
int tdb_create_rwlocks(int fd, unsigned int hash_size)
{
unsigned size, i;
tdb_rwlock_t *rwlocks;
size = (hash_size + 1) * sizeof(tdb_rwlock_t);
rwlocks = malloc(size);
if (!rwlocks)
return -1;
for(i = 0; i < hash_size+1; i++) {
__spin_lock_init(&rwlocks[i].lock);
rwlocks[i].count = 0;
}
/* Write it out (appending to end) */
if (write(fd, rwlocks, size) != size) {
free(rwlocks);
return -1;
}
smp_machine = this_is_smp();
free(rwlocks);
return 0;
}
int tdb_clear_spinlocks(TDB_CONTEXT *tdb)
{
tdb_rwlock_t *rwlocks;
unsigned i;
if (tdb->header.rwlocks == 0) return 0;
if (!tdb->map_ptr) return -1;
/* We're mmapped here */
rwlocks = (tdb_rwlock_t *)((char *)tdb->map_ptr + tdb->header.rwlocks);
for(i = 0; i < tdb->header.hash_size+1; i++) {
__spin_lock_init(&rwlocks[i].lock);
rwlocks[i].count = 0;
}
return 0;
}
#else
int tdb_create_rwlocks(int fd, unsigned int hash_size) { return 0; }
int tdb_spinlock(TDB_CONTEXT *tdb, int list, int rw_type) { return -1; }
int tdb_spinunlock(TDB_CONTEXT *tdb, int list, int rw_type) { return -1; }
/* Non-spinlock version: remove spinlock pointer */
int tdb_clear_spinlocks(TDB_CONTEXT *tdb)
{
tdb_off off = (tdb_off)((char *)&tdb->header.rwlocks
- (char *)&tdb->header);
tdb->header.rwlocks = 0;
if (lseek(tdb->fd, off, SEEK_SET) != off
|| write(tdb->fd, (void *)&tdb->header.rwlocks,
sizeof(tdb->header.rwlocks))
!= sizeof(tdb->header.rwlocks))
return -1;
return 0;
}
#endif

55
source/lib/tdb/spinlock.h Normal file
View File

@@ -0,0 +1,55 @@
#ifndef __SPINLOCK_H__
#define __SPINLOCK_H__
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "tdb.h"
#ifdef USE_SPINLOCKS
#define RWLOCK_BIAS 0x1000UL
/* OS SPECIFIC */
#define MAX_BUSY_LOOPS 1000
#undef USE_SCHED_YIELD
/* ARCH SPECIFIC */
/* We should make sure these are padded to a cache line */
#if defined(SPARC_SPINLOCKS)
typedef volatile char spinlock_t;
#elif defined(POWERPC_SPINLOCKS)
typedef volatile unsigned long spinlock_t;
#elif defined(INTEL_SPINLOCKS)
typedef volatile int spinlock_t;
#elif defined(MIPS_SPINLOCKS)
typedef volatile unsigned long spinlock_t;
#else
#error Need to implement spinlock code in spinlock.h
#endif
typedef struct {
spinlock_t lock;
volatile int count;
} tdb_rwlock_t;
int tdb_spinlock(TDB_CONTEXT *tdb, int list, int rw_type);
int tdb_spinunlock(TDB_CONTEXT *tdb, int list, int rw_type);
int tdb_create_rwlocks(int fd, unsigned int hash_size);
int tdb_clear_spinlocks(TDB_CONTEXT *tdb);
#else /* !USE_SPINLOCKS */
#if 0
#define tdb_create_rwlocks(fd, hash_size) 0
#define tdb_spinlock(tdb, list, rw_type) (-1)
#define tdb_spinunlock(tdb, list, rw_type) (-1)
#else
int tdb_spinlock(TDB_CONTEXT *tdb, int list, int rw_type);
int tdb_spinunlock(TDB_CONTEXT *tdb, int list, int rw_type);
int tdb_create_rwlocks(int fd, unsigned int hash_size);
#endif
int tdb_clear_spinlocks(TDB_CONTEXT *tdb);
#endif
#endif

2020
source/lib/tdb/tdb.c Normal file

File diff suppressed because it is too large Load Diff

144
source/lib/tdb/tdb.h Normal file
View File

@@ -0,0 +1,144 @@
#ifndef __TDB_H__
#define __TDB_H__
/*
Unix SMB/CIFS implementation.
Samba database functions
Copyright (C) Andrew Tridgell 1999
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef __cplusplus
extern "C" {
#endif
/* flags to tdb_store() */
#define TDB_REPLACE 1
#define TDB_INSERT 2
#define TDB_MODIFY 3
/* flags for tdb_open() */
#define TDB_DEFAULT 0 /* just a readability place holder */
#define TDB_CLEAR_IF_FIRST 1
#define TDB_INTERNAL 2 /* don't store on disk */
#define TDB_NOLOCK 4 /* don't do any locking */
#define TDB_NOMMAP 8 /* don't use mmap */
#define TDB_CONVERT 16 /* convert endian (internal use) */
#define TDB_BIGENDIAN 32 /* header is big-endian (internal use) */
#define TDB_ERRCODE(code, ret) ((tdb->ecode = (code)), ret)
/* error codes */
enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK,
TDB_ERR_OOM, TDB_ERR_EXISTS, TDB_ERR_NOEXIST, TDB_ERR_NOLOCK, TDB_ERR_LOCK_TIMEOUT };
#ifndef u32
#define u32 unsigned
#endif
typedef struct {
char *dptr;
size_t dsize;
} TDB_DATA;
typedef u32 tdb_len;
typedef u32 tdb_off;
/* this is stored at the front of every database */
struct tdb_header {
char magic_food[32]; /* for /etc/magic */
u32 version; /* version of the code */
u32 hash_size; /* number of hash entries */
tdb_off rwlocks;
tdb_off reserved[31];
};
struct tdb_lock_type {
u32 count;
u32 ltype;
};
struct tdb_traverse_lock {
struct tdb_traverse_lock *next;
u32 off;
u32 hash;
};
/* this is the context structure that is returned from a db open */
typedef struct tdb_context {
char *name; /* the name of the database */
void *map_ptr; /* where it is currently mapped */
int fd; /* open file descriptor for the database */
tdb_len map_size; /* how much space has been mapped */
int read_only; /* opened read-only */
struct tdb_lock_type *locked; /* array of chain locks */
enum TDB_ERROR ecode; /* error code for last tdb error */
struct tdb_header header; /* a cached copy of the header */
u32 flags; /* the flags passed to tdb_open */
u32 *lockedkeys; /* array of locked keys: first is #keys */
struct tdb_traverse_lock travlocks; /* current traversal locks */
struct tdb_context *next; /* all tdbs to avoid multiple opens */
dev_t device; /* uniquely identifies this tdb */
ino_t inode; /* uniquely identifies this tdb */
void (*log_fn)(struct tdb_context *tdb, int level, const char *, ...); /* logging function */
int open_flags; /* flags used in the open - needed by reopen */
} TDB_CONTEXT;
typedef int (*tdb_traverse_func)(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *);
typedef void (*tdb_log_func)(TDB_CONTEXT *, int , const char *, ...);
TDB_CONTEXT *tdb_open(const char *name, int hash_size, int tdb_flags,
int open_flags, mode_t mode);
TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
int open_flags, mode_t mode,
tdb_log_func log_fn);
int tdb_reopen(TDB_CONTEXT *tdb);
int tdb_reopen_all(void);
void tdb_logging_function(TDB_CONTEXT *tdb, tdb_log_func);
enum TDB_ERROR tdb_error(TDB_CONTEXT *tdb);
const char *tdb_errorstr(TDB_CONTEXT *tdb);
TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key);
int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key);
int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
int tdb_append(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA new_dbuf);
int tdb_close(TDB_CONTEXT *tdb);
TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb);
TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key);
int tdb_traverse(TDB_CONTEXT *tdb, tdb_traverse_func fn, void *state);
int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key);
int tdb_lockkeys(TDB_CONTEXT *tdb, u32 number, TDB_DATA keys[]);
void tdb_unlockkeys(TDB_CONTEXT *tdb);
int tdb_lockall(TDB_CONTEXT *tdb);
void tdb_unlockall(TDB_CONTEXT *tdb);
/* Low level locking functions: use with care */
void tdb_set_lock_alarm(sig_atomic_t *palarm);
int tdb_chainlock(TDB_CONTEXT *tdb, TDB_DATA key);
int tdb_chainunlock(TDB_CONTEXT *tdb, TDB_DATA key);
/* Debug functions. Not used in production. */
void tdb_dump_all(TDB_CONTEXT *tdb);
int tdb_printfreelist(TDB_CONTEXT *tdb);
extern TDB_DATA tdb_null;
#ifdef __cplusplus
}
#endif
#endif /* tdb.h */

10
source/lib/tdb/tdb.magic Normal file
View File

@@ -0,0 +1,10 @@
# Magic file(1) information about tdb files.
#
# Install this into /etc/magic or the corresponding location for your
# system, or pass as a -m argument to file(1).
# You may use and redistribute this file without restriction.
0 string TDB\ file TDB database
>32 lelong =0x2601196D version 6, little-endian
>>36 lelong x hash size %d bytes

687
source/lib/tdb/tdbutil.c Normal file
View File

@@ -0,0 +1,687 @@
/*
Unix SMB/CIFS implementation.
tdb utility functions
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 <fnmatch.h>
/* these are little tdb utility functions that are meant to make
dealing with a tdb database a little less cumbersome in Samba */
static SIG_ATOMIC_T gotalarm;
/***************************************************************
Signal function to tell us we timed out.
****************************************************************/
static void gotalarm_sig(void)
{
gotalarm = 1;
}
/***************************************************************
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 = dptr;
ret.dsize = dsize;
return ret;
}
/****************************************************************************
Lock a chain with timeout (in seconds).
****************************************************************************/
static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout, int rw_type)
{
/* Allow tdb_chainlock to be interrupted by an alarm. */
int ret;
gotalarm = 0;
tdb_set_lock_alarm(&gotalarm);
if (timeout) {
CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
alarm(timeout);
}
if (rw_type == F_RDLCK)
ret = tdb_chainlock_read(tdb, key);
else
ret = tdb_chainlock(tdb, key);
if (timeout) {
alarm(0);
CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
if (gotalarm) {
DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
timeout, key.dptr, tdb->name ));
/* TODO: If we time out waiting for a lock, it might
* be nice to use F_GETLK to get the pid of the
* process currently holding the lock and print that
* as part of the debugging message. -- mbp */
return -1;
}
}
return ret;
}
/****************************************************************************
Write lock a chain. Return -1 if timeout or lock failed.
****************************************************************************/
int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout)
{
return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
}
/****************************************************************************
Lock a chain by string. Return -1 if timeout or lock failed.
****************************************************************************/
int tdb_lock_bystring(TDB_CONTEXT *tdb, const char *keyval, unsigned int timeout)
{
TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
}
/****************************************************************************
Unlock a chain by string.
****************************************************************************/
void tdb_unlock_bystring(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 timeout or lock failed.
****************************************************************************/
int tdb_read_lock_bystring(TDB_CONTEXT *tdb, const char *keyval, unsigned int timeout)
{
TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK);
}
/****************************************************************************
Read unlock a chain by string.
****************************************************************************/
void tdb_read_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
{
TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
tdb_chainunlock_read(tdb, key);
}
/****************************************************************************
Fetch a int32 value by a arbitrary blob key, return -1 if not found.
Output is int32 in native byte order.
****************************************************************************/
int32 tdb_fetch_int32_byblob(TDB_CONTEXT *tdb, const char *keyval, size_t len)
{
TDB_DATA key = make_tdb_data(keyval, len);
TDB_DATA data;
int32 ret;
data = tdb_fetch(tdb, key);
if (!data.dptr || data.dsize != sizeof(int32)) {
SAFE_FREE(data.dptr);
return -1;
}
ret = IVAL(data.dptr,0);
SAFE_FREE(data.dptr);
return ret;
}
/****************************************************************************
Fetch a int32 value by string key, return -1 if not found.
Output is int32 in native byte order.
****************************************************************************/
int32 tdb_fetch_int32(TDB_CONTEXT *tdb, const char *keystr)
{
return tdb_fetch_int32_byblob(tdb, keystr, strlen(keystr) + 1);
}
/****************************************************************************
Store a int32 value by an arbitary blob key, return 0 on success, -1 on failure.
Input is int32 in native byte order. Output in tdb is in little-endian.
****************************************************************************/
int tdb_store_int32_byblob(TDB_CONTEXT *tdb, const char *keystr, size_t len, int32 v)
{
TDB_DATA key = make_tdb_data(keystr, len);
TDB_DATA data;
int32 v_store;
SIVAL(&v_store,0,v);
data.dptr = (void *)&v_store;
data.dsize = sizeof(int32);
return tdb_store(tdb, key, data, TDB_REPLACE);
}
/****************************************************************************
Store a int32 value by string key, return 0 on success, -1 on failure.
Input is int32 in native byte order. Output in tdb is in little-endian.
****************************************************************************/
int tdb_store_int32(TDB_CONTEXT *tdb, const char *keystr, int32 v)
{
return tdb_store_int32_byblob(tdb, keystr, strlen(keystr) + 1, v);
}
/****************************************************************************
Fetch a uint32 value by a arbitrary blob key, return -1 if not found.
Output is uint32 in native byte order.
****************************************************************************/
BOOL tdb_fetch_uint32_byblob(TDB_CONTEXT *tdb, const char *keyval, size_t len, uint32 *value)
{
TDB_DATA key = make_tdb_data(keyval, len);
TDB_DATA data;
data = tdb_fetch(tdb, key);
if (!data.dptr || data.dsize != sizeof(uint32)) {
SAFE_FREE(data.dptr);
return False;
}
*value = IVAL(data.dptr,0);
SAFE_FREE(data.dptr);
return True;
}
/****************************************************************************
Fetch a uint32 value by string key, return -1 if not found.
Output is uint32 in native byte order.
****************************************************************************/
BOOL tdb_fetch_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32 *value)
{
return tdb_fetch_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
}
/****************************************************************************
Store a uint32 value by an arbitary blob key, return 0 on success, -1 on failure.
Input is uint32 in native byte order. Output in tdb is in little-endian.
****************************************************************************/
BOOL tdb_store_uint32_byblob(TDB_CONTEXT *tdb, const char *keystr, size_t len, uint32 value)
{
TDB_DATA key = make_tdb_data(keystr, len);
TDB_DATA data;
uint32 v_store;
BOOL ret = True;
SIVAL(&v_store, 0, value);
data.dptr = (void *)&v_store;
data.dsize = sizeof(uint32);
if (tdb_store(tdb, key, data, TDB_REPLACE) == -1)
ret = False;
return ret;
}
/****************************************************************************
Store a uint32 value by string key, return 0 on success, -1 on failure.
Input is uint32 in native byte order. Output in tdb is in little-endian.
****************************************************************************/
BOOL tdb_store_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32 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_by_string(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_by_string(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_by_string(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 tdb_change_int32_atomic(TDB_CONTEXT *tdb, const char *keystr, int32 *oldval, int32 change_val)
{
int32 val;
int32 ret = -1;
if (tdb_lock_bystring(tdb, keystr,0) == -1)
return -1;
if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
/* The lookup failed */
if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
/* but not becouse 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(TDB_CONTEXT *tdb, const char *keystr, uint32 *oldval, uint32 change_val)
{
uint32 val;
BOOL ret = False;
if (tdb_lock_bystring(tdb, keystr,0) == -1)
return False;
if (!tdb_fetch_uint32(tdb, keystr, &val)) {
/* It failed */
if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
/* and not becouse 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;
}
/****************************************************************************
Useful pair of routines for packing/unpacking data consisting of
integers and strings.
****************************************************************************/
size_t tdb_pack(char *buf, int bufsize, const char *fmt, ...)
{
va_list ap;
uint16 w;
uint32 d;
int i;
void *p;
int len;
char *s;
char c;
char *buf0 = buf;
const char *fmt0 = fmt;
int bufsize0 = bufsize;
va_start(ap, fmt);
while (*fmt) {
switch ((c = *fmt++)) {
case 'w':
len = 2;
w = (uint16)va_arg(ap, int);
if (bufsize >= len)
SSVAL(buf, 0, w);
break;
case 'd':
len = 4;
d = va_arg(ap, uint32);
if (bufsize >= len)
SIVAL(buf, 0, d);
break;
case 'p':
len = 4;
p = va_arg(ap, void *);
d = p?1:0;
if (bufsize >= len)
SIVAL(buf, 0, d);
break;
case 'P':
s = va_arg(ap,char *);
w = strlen(s);
len = w + 1;
if (bufsize >= len)
memcpy(buf, s, len);
break;
case 'f':
s = va_arg(ap,char *);
w = strlen(s);
len = w + 1;
if (bufsize >= len)
memcpy(buf, s, len);
break;
case 'B':
i = va_arg(ap, int);
s = va_arg(ap, char *);
len = 4+i;
if (bufsize >= len) {
SIVAL(buf, 0, i);
memcpy(buf+4, s, i);
}
break;
default:
DEBUG(0,("Unknown tdb_pack format %c in %s\n",
c, fmt));
len = 0;
break;
}
buf += len;
bufsize -= len;
}
va_end(ap);
DEBUG(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(char *buf, int bufsize, const char *fmt, ...)
{
va_list ap;
uint16 *w;
uint32 *d;
int len;
int *i;
void **p;
char *s, **b;
char c;
char *buf0 = buf;
const char *fmt0 = fmt;
int bufsize0 = bufsize;
va_start(ap, fmt);
while (*fmt) {
switch ((c=*fmt++)) {
case 'w':
len = 2;
w = va_arg(ap, uint16 *);
if (bufsize < len)
goto no_space;
*w = SVAL(buf, 0);
break;
case 'd':
len = 4;
d = va_arg(ap, uint32 *);
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:
DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
c, fmt));
len = 0;
break;
}
buf += len;
bufsize -= len;
}
va_end(ap);
DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
return PTR_DIFF(buf, buf0);
no_space:
return -1;
}
/****************************************************************************
Log tdb messages via DEBUG().
****************************************************************************/
static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
{
va_list ap;
char *ptr = NULL;
va_start(ap, format);
vasprintf(&ptr, format, ap);
va_end(ap);
if (!ptr || !*ptr)
return;
DEBUG(level, ("tdb(%s): %s", tdb->name ? tdb->name : "unnamed", ptr));
SAFE_FREE(ptr);
}
/****************************************************************************
Like tdb_open() but also setup a logging function that redirects to
the samba DEBUG() system.
****************************************************************************/
TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
int open_flags, mode_t mode)
{
TDB_CONTEXT *tdb;
if (!lp_use_mmap())
tdb_flags |= TDB_NOMMAP;
tdb = tdb_open_ex(name, hash_size, tdb_flags,
open_flags, mode, tdb_log);
if (!tdb)
return NULL;
return tdb;
}
/****************************************************************************
Allow tdb_delete to be used as a tdb_traversal_fn.
****************************************************************************/
int tdb_traverse_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
void *state)
{
return tdb_delete(the_tdb, key);
}
/**
* Search across the whole tdb for keys that match the given pattern
* return the result as a list of keys
*
* @param tdb pointer to opened tdb file context
* @param pattern searching pattern used by fnmatch(3) functions
*
* @return list of keys found by looking up with given pattern
**/
TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern)
{
TDB_DATA key, next;
TDB_LIST_NODE *list = NULL;
TDB_LIST_NODE *rec = NULL;
TDB_LIST_NODE *tmp = NULL;
for (key = tdb_firstkey(tdb); key.dptr; key = next) {
/* duplicate key string to ensure null-termination */
char *key_str = (char*) strndup(key.dptr, key.dsize);
if (!key_str) {
DEBUG(0, ("tdb_search_keys: strndup() failed!\n"));
smb_panic("strndup failed!\n");
}
DEBUG(18, ("checking %s for match to pattern %s\n", key_str, pattern));
next = tdb_nextkey(tdb, key);
/* do the pattern checking */
if (fnmatch(pattern, key_str, 0) == 0) {
rec = (TDB_LIST_NODE*) malloc(sizeof(*rec));
ZERO_STRUCTP(rec);
rec->node_key = key;
DLIST_ADD_END(list, rec, tmp);
DEBUG(18, ("checking %s matched pattern %s\n", key_str, pattern));
} else {
free(key.dptr);
}
/* free duplicated key string */
free(key_str);
}
return list;
};
/**
* Free the list returned by tdb_search_keys
*
* @param node list of results found by tdb_search_keys
**/
void tdb_search_list_free(TDB_LIST_NODE* node)
{
TDB_LIST_NODE *next_node;
while (node) {
next_node = node->next;
SAFE_FREE(node);
node = next_node;
};
};

37
source/lib/tdb/tdbutil.h Normal file
View File

@@ -0,0 +1,37 @@
/*
Unix SMB/CIFS implementation.
tdb utility functions
Copyright (C) Andrew Tridgell 1999
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __TDBUTIL_H__
#define __TDBUTIL_H__
/* single node of a list returned by tdb_search_keys */
typedef struct keys_node
{
struct keys_node *prev, *next;
TDB_DATA node_key;
} TDB_LIST_NODE;
TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT*, const char*);
void tdb_search_list_free(TDB_LIST_NODE*);
#endif /* __TDBUTIL_H__ */

754
source/lib/time.c Normal file
View File

@@ -0,0 +1,754 @@
/*
Unix SMB/CIFS implementation.
time handling functions
Copyright (C) Andrew Tridgell 1992-1998
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"
/*
This stuff was largely rewritten by Paul Eggert <eggert@twinsun.com>
in May 1996
*/
int extra_time_offset = 0;
#ifndef CHAR_BIT
#define CHAR_BIT 8
#endif
#ifndef TIME_T_MIN
#define TIME_T_MIN ((time_t)0 < (time_t) -1 ? (time_t) 0 \
: ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
#endif
#ifndef TIME_T_MAX
#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
#endif
void get_nttime_max(NTTIME *t)
{
/* FIXME: This is incorrect */
unix_to_nt_time(t, get_time_t_max());
}
/*******************************************************************
External access to time_t_min and time_t_max.
********************************************************************/
time_t get_time_t_max(void)
{
return TIME_T_MAX;
}
/*******************************************************************
a gettimeofday wrapper
********************************************************************/
void GetTimeOfDay(struct timeval *tval)
{
#ifdef HAVE_GETTIMEOFDAY_TZ
gettimeofday(tval,NULL);
#else
gettimeofday(tval);
#endif
}
#define TM_YEAR_BASE 1900
/*******************************************************************
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 + (TM_YEAR_BASE - 1);
int by = b->tm_year + (TM_YEAR_BASE - 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
******************************************************************/
static int TimeZone(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);
}
static BOOL done_serverzone_init;
/* Return the smb serverzone value */
static int get_serverzone(void)
{
static int serverzone;
if (!done_serverzone_init) {
serverzone = TimeZone(time(NULL));
if ((serverzone % 60) != 0) {
DEBUG(1,("WARNING: Your timezone is not a multiple of 1 minute.\n"));
}
DEBUG(4,("Serverzone is %d\n",serverzone));
done_serverzone_init = True;
}
return serverzone;
}
/* Re-read the smb serverzone value */
static struct timeval start_time_hires;
void TimeInit(void)
{
done_serverzone_init = False;
get_serverzone();
/* Save the start time of this process. */
if (start_time_hires.tv_sec == 0 && start_time_hires.tv_usec == 0)
GetTimeOfDay(&start_time_hires);
}
/**********************************************************************
Return a timeval struct of the uptime of this process. As TimeInit is
done before a daemon fork then this is the start time from the parent
daemon start. JRA.
***********************************************************************/
void get_process_uptime(struct timeval *ret_time)
{
struct timeval time_now_hires;
GetTimeOfDay(&time_now_hires);
ret_time->tv_sec = time_now_hires.tv_sec - start_time_hires.tv_sec;
ret_time->tv_usec = time_now_hires.tv_usec - start_time_hires.tv_usec;
if (time_now_hires.tv_usec < start_time_hires.tv_usec) {
ret_time->tv_sec -= 1;
ret_time->tv_usec = 1000000 + (time_now_hires.tv_usec - start_time_hires.tv_usec);
} else
ret_time->tv_usec = time_now_hires.tv_usec - start_time_hires.tv_usec;
}
/*******************************************************************
return the same value as TimeZone, but it should be more efficient.
We keep a table of DST offsets to prevent calling localtime() on each
call of this function. This saves a LOT of time on many unixes.
Updated by Paul Eggert <eggert@twinsun.com>
********************************************************************/
static int TimeZoneFaster(time_t t)
{
static struct dst_table {time_t start,end; int zone;} *tdt, *dst_table = NULL;
static int table_size = 0;
int i;
int zone = 0;
if (t == 0) t = time(NULL);
/* Tunis has a 8 day DST region, we need to be careful ... */
#define MAX_DST_WIDTH (365*24*60*60)
#define MAX_DST_SKIP (7*24*60*60)
for (i=0;i<table_size;i++)
if (t >= dst_table[i].start && t <= dst_table[i].end) break;
if (i<table_size) {
zone = dst_table[i].zone;
} else {
time_t low,high;
zone = TimeZone(t);
tdt = (struct dst_table *)Realloc(dst_table,
sizeof(dst_table[0])*(i+1));
if (!tdt) {
DEBUG(0,("TimeZoneFaster: out of memory!\n"));
SAFE_FREE(dst_table);
table_size = 0;
} else {
dst_table = tdt;
table_size++;
dst_table[i].zone = zone;
dst_table[i].start = dst_table[i].end = t;
/* no entry will cover more than 6 months */
low = t - MAX_DST_WIDTH/2;
if (t < low)
low = TIME_T_MIN;
high = t + MAX_DST_WIDTH/2;
if (high < t)
high = TIME_T_MAX;
/* widen the new entry using two bisection searches */
while (low+60*60 < dst_table[i].start) {
if (dst_table[i].start - low > MAX_DST_SKIP*2)
t = dst_table[i].start - MAX_DST_SKIP;
else
t = low + (dst_table[i].start-low)/2;
if (TimeZone(t) == zone)
dst_table[i].start = t;
else
low = t;
}
while (high-60*60 > dst_table[i].end) {
if (high - dst_table[i].end > MAX_DST_SKIP*2)
t = dst_table[i].end + MAX_DST_SKIP;
else
t = high - (high-dst_table[i].end)/2;
if (TimeZone(t) == zone)
dst_table[i].end = t;
else
high = t;
}
#if 0
DEBUG(1,("Added DST entry from %s ",
asctime(localtime(&dst_table[i].start))));
DEBUG(1,("to %s (%d)\n",asctime(localtime(&dst_table[i].end)),
dst_table[i].zone));
#endif
}
}
return zone;
}
/****************************************************************************
return the UTC offset in seconds west of UTC, adjusted for extra time offset
**************************************************************************/
int TimeDiff(time_t t)
{
return TimeZoneFaster(t) + 60 * lp_time_offset();
}
/****************************************************************************
return the UTC offset in seconds west of UTC, adjusted for extra time
offset, for a local time value. If ut = lt + LocTimeDiff(lt), then
lt = ut - TimeDiff(ut), but the converse does not necessarily hold near
daylight savings transitions because some local times are ambiguous.
LocTimeDiff(t) equals TimeDiff(t) except near daylight savings transitions.
+**************************************************************************/
static int LocTimeDiff(time_t lte)
{
time_t lt = lte - 60 * lp_time_offset();
int d = TimeZoneFaster(lt);
time_t t = lt + d;
/* if overflow occurred, ignore all the adjustments so far */
if (((lte < lt) ^ (lp_time_offset() < 0)) | ((t < lt) ^ (d < 0)))
t = lte;
/* now t should be close enough to the true UTC to yield the right answer */
return TimeDiff(t);
}
/****************************************************************************
try to optimise the localtime call, it can be quite expensive on some machines
****************************************************************************/
struct tm *LocalTime(time_t *t)
{
time_t t2 = *t;
t2 -= TimeDiff(t2);
return(gmtime(&t2));
}
#define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
/****************************************************************************
interpret an 8 byte "filetime" structure to a time_t
It's originally in "100ns units since jan 1st 1601"
It appears to be kludge-GMT (at least for file listings). This means
its the GMT you get by taking a localtime and adding the
serverzone. This is NOT the same as GMT in some cases. This routine
converts this to real GMT.
****************************************************************************/
time_t nt_time_to_unix(const NTTIME *nt)
{
double d;
time_t ret;
/* The next two lines are a fix needed for the
broken SCO compiler. JRA. */
time_t l_time_min = TIME_T_MIN;
time_t l_time_max = TIME_T_MAX;
if (nt->high == 0) return(0);
d = ((double)nt->high)*4.0*(double)(1<<30);
d += (nt->low&0xFFF00000);
d *= 1.0e-7;
/* now adjust by 369 years to make the secs since 1970 */
d -= TIME_FIXUP_CONSTANT;
if (!(l_time_min <= d && d <= l_time_max))
return(0);
ret = (time_t)(d+0.5);
/* this takes us from kludge-GMT to real GMT */
ret -= get_serverzone();
ret += LocTimeDiff(ret);
return(ret);
}
/****************************************************************************
Convert a NTTIME structure to a time_t.
It's originally in "100ns units".
This is an absolute version of the one above.
By absolute I mean, it doesn't adjust from 1/1/1601 to 1/1/1970
if the NTTIME was 5 seconds, the time_t is 5 seconds. JFM
****************************************************************************/
time_t nt_time_to_unix_abs(NTTIME *nt)
{
double d;
time_t ret;
/* The next two lines are a fix needed for the
broken SCO compiler. JRA. */
time_t l_time_min = TIME_T_MIN;
time_t l_time_max = TIME_T_MAX;
if (nt->high == 0)
return(0);
if (nt->high==0x80000000 && nt->low==0)
return -1;
/* reverse the time */
/* it's a negative value, turn it to positive */
nt->high=~nt->high;
nt->low=~nt->low;
d = ((double)nt->high)*4.0*(double)(1<<30);
d += (nt->low&0xFFF00000);
d *= 1.0e-7;
if (!(l_time_min <= d && d <= l_time_max))
return(0);
ret = (time_t)(d+0.5);
return(ret);
}
/****************************************************************************
put a 8 byte filetime from a time_t
This takes real GMT as input and converts to kludge-GMT
****************************************************************************/
void unix_to_nt_time(NTTIME *nt, time_t t)
{
double d;
if (t==0) {
nt->low = 0;
nt->high = 0;
return;
}
if (t == TIME_T_MAX) {
nt->low = 0xffffffff;
nt->high = 0x7fffffff;
return;
}
if (t == -1) {
nt->low = 0xffffffff;
nt->high = 0xffffffff;
return;
}
/* this converts GMT to kludge-GMT */
t -= TimeDiff(t) - get_serverzone();
d = (double)(t);
d += TIME_FIXUP_CONSTANT;
d *= 1.0e7;
nt->high = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
nt->low = (uint32)(d - ((double)nt->high)*4.0*(double)(1<<30));
}
/****************************************************************************
Convert a time_t to a NTTIME structure
This is an absolute version of the one above.
By absolute I mean, it doesn't adjust from 1/1/1970 to 1/1/1601
If the nttime_t was 5 seconds, the NTTIME is 5 seconds. JFM
****************************************************************************/
void unix_to_nt_time_abs(NTTIME *nt, time_t t)
{
double d;
if (t==0) {
nt->low = 0;
nt->high = 0;
return;
}
if (t == TIME_T_MAX) {
nt->low = 0xffffffff;
nt->high = 0x7fffffff;
return;
}
if (t == -1) {
/* that's what NT uses for infinite */
nt->low = 0x0;
nt->high = 0x80000000;
return;
}
d = (double)(t);
d *= 1.0e7;
nt->high = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
nt->low = (uint32)(d - ((double)nt->high)*4.0*(double)(1<<30));
/* convert to a negative value */
nt->high=~nt->high;
nt->low=~nt->low;
}
/****************************************************************************
take an NTTIME structure, containing high / low time. convert to unix time.
lkclXXXX this may need 2 SIVALs not a memcpy. we'll see...
****************************************************************************/
void put_long_date(char *p,time_t t)
{
NTTIME nt;
unix_to_nt_time(&nt, t);
SIVAL(p, 0, nt.low);
SIVAL(p, 4, nt.high);
}
/****************************************************************************
check if it's a null mtime
****************************************************************************/
BOOL null_mtime(time_t mtime)
{
if (mtime == 0 || mtime == (time_t)0xFFFFFFFF || mtime == (time_t)-1)
return True;
return False;
}
/*******************************************************************
create a 16 bit dos packed date
********************************************************************/
static uint16 make_dos_date1(struct tm *t)
{
uint16 ret=0;
ret = (((unsigned)(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 make_dos_time1(struct tm *t)
{
uint16 ret=0;
ret = ((((unsigned)t->tm_min >> 3)&0x7) | (((unsigned)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 make_dos_date(time_t unixdate)
{
struct tm *t;
uint32 ret=0;
if (unixdate == 0) {
return 0;
}
t = LocalTime(&unixdate);
if (!t) {
return 0xFFFFFFFF;
}
ret = make_dos_date1(t);
ret = ((ret&0xFFFF)<<16) | make_dos_time1(t);
return ret;
}
/*******************************************************************
put a dos date into a buffer (time/date format)
This takes GMT time and puts local time in the buffer
********************************************************************/
void put_dos_date(char *buf,int offset,time_t unixdate)
{
uint32 x = make_dos_date(unixdate);
SIVAL(buf,offset,x);
}
/*******************************************************************
put a dos date into a buffer (date/time format)
This takes GMT time and puts local time in the buffer
********************************************************************/
void put_dos_date2(char *buf,int offset,time_t unixdate)
{
uint32 x;
x = make_dos_date(unixdate);
x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
SIVAL(buf,offset,x);
}
/*******************************************************************
put a dos 32 bit "unix like" date into a buffer. This routine takes
GMT and converts it to LOCAL time before putting it (most SMBs assume
localtime for this sort of date)
********************************************************************/
void put_dos_date3(char *buf,int offset,time_t unixdate)
{
if (!null_mtime(unixdate))
unixdate -= TimeDiff(unixdate);
SIVAL(buf,offset,unixdate);
}
/*******************************************************************
interpret a 32 bit dos packed date/time to some parameters
********************************************************************/
static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second)
{
uint32 p0,p1,p2,p3;
p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF;
p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF;
*second = 2*(p0 & 0x1F);
*minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3);
*hour = (p1>>3)&0xFF;
*day = (p2&0x1F);
*month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1;
*year = ((p3>>1)&0xFF) + 80;
}
/*******************************************************************
create a unix date (int GMT) from a dos date (which is actually in
localtime)
********************************************************************/
time_t make_unix_date(void *date_ptr)
{
uint32 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;
/* mktime() also does the local to GMT time conversion for us */
ret = mktime(&t);
return(ret);
}
/*******************************************************************
like make_unix_date() but the words are reversed
********************************************************************/
time_t make_unix_date2(void *date_ptr)
{
uint32 x,x2;
x = IVAL(date_ptr,0);
x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
SIVAL(&x,0,x2);
return make_unix_date((void *)&x);
}
/*******************************************************************
create a unix GMT date from a dos date in 32 bit "unix like" format
these generally arrive as localtimes, with corresponding DST
******************************************************************/
time_t make_unix_date3(void *date_ptr)
{
time_t t = (time_t)IVAL(date_ptr,0);
if (!null_mtime(t))
t += LocTimeDiff(t);
return t;
}
/***************************************************************************
return a HTTP/1.0 time string
***************************************************************************/
char *http_timestring(TALLOC_CTX *mem_ctx, time_t t)
{
char *buf;
fstring tempTime;
struct tm *tm = LocalTime(&t);
if (!tm)
buf = talloc_asprintf(mem_ctx,"%ld seconds since the Epoch",(long)t);
else
#ifndef HAVE_STRFTIME
buf = talloc_strdup(mem_ctx, asctime(tm));
if(buf[strlen(buf)-1] == '\n')
buf[strlen(buf)-1] = 0;
#else /* !HAVE_STRFTIME */
strftime(tempTime, sizeof(tempTime)-1, "%a, %d %b %Y %H:%M:%S %Z", tm);
buf = talloc_strdup(mem_ctx, tempTime);
#endif /* !HAVE_STRFTIME */
return buf;
}
/****************************************************************************
Return the date and time as a string
****************************************************************************/
char *timestring(TALLOC_CTX *mem_ctx, BOOL hires)
{
char *TimeBuf;
fstring tempTime;
struct timeval tp;
time_t t;
struct tm *tm;
if (hires) {
GetTimeOfDay(&tp);
t = (time_t)tp.tv_sec;
} else {
t = time(NULL);
}
tm = LocalTime(&t);
if (!tm) {
if (hires) {
TimeBuf = talloc_asprintf(mem_ctx,
"%ld.%06ld seconds since the Epoch",
(long)tp.tv_sec,
(long)tp.tv_usec);
} else {
TimeBuf = talloc_asprintf(mem_ctx,
"%ld seconds since the Epoch",
(long)t);
}
} else {
#ifdef HAVE_STRFTIME
if (hires) {
strftime(tempTime,sizeof(tempTime)-1,"%Y/%m/%d %H:%M:%S",tm);
TimeBuf = talloc_asprintf(mem_ctx, "%s.%06ld",
tempTime, (long)tp.tv_usec);
} else {
strftime(tempTime,100,"%Y/%m/%d %H:%M:%S",tm);
TimeBuf = talloc_strdup(mem_ctx, tempTime);
}
#else
if (hires) {
TimeBuf = talloc_asprintf(mem_ctx,
"%s.%06ld",
asctime(tm),
(long)tp.tv_usec);
} else {
TimeBuf = talloc_strdup(mem_ctx, asctime(tm));
}
#endif
}
return(TimeBuf);
}
/****************************************************************************
return the best approximation to a 'create time' under UNIX from a stat
structure.
****************************************************************************/
time_t get_create_time(SMB_STRUCT_STAT *st,BOOL fake_dirs)
{
time_t ret, ret1;
if(S_ISDIR(st->st_mode) && fake_dirs)
return (time_t)315493200L; /* 1/1/1980 */
ret = MIN(st->st_ctime, st->st_mtime);
ret1 = MIN(ret, st->st_atime);
if(ret1 != (time_t)0)
return ret1;
/*
* One of ctime, mtime or atime was zero (probably atime).
* Just return MIN(ctime, mtime).
*/
return ret;
}
/****************************************************************************
initialise an NTTIME to -1, which means "unknown" or "don't expire"
****************************************************************************/
void init_nt_time(NTTIME *nt)
{
nt->high = 0x7FFFFFFF;
nt->low = 0xFFFFFFFF;
}
/****************************************************************************
check if NTTIME is 0
****************************************************************************/
BOOL nt_time_is_zero(NTTIME *nt)
{
if(nt->high==0)
return True;
return False;
}
/*
return a talloced string representing a NTTIME for human consumption
*/
const char *nt_time_string(TALLOC_CTX *mem_ctx, const NTTIME *nt)
{
time_t t = nt_time_to_unix(nt);
return talloc_strdup(mem_ctx, http_timestring(mem_ctx, t));
}

537
source/lib/username.c Normal file
View File

@@ -0,0 +1,537 @@
/*
Unix SMB/CIFS implementation.
Username handling
Copyright (C) Andrew Tridgell 1992-1998
Copyright (C) Jeremy Allison 1997-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"
/* internal functions */
static struct passwd *uname_string_combinations(char *s, struct passwd * (*fn) (const char *), int N);
static struct passwd *uname_string_combinations2(char *s, int offset, struct passwd * (*fn) (const char *), int N);
/*****************************************************************
Check if a user or group name is local (this is a *local* name for
*local* people, there's nothing for you here...).
*****************************************************************/
static BOOL name_is_local(const char *name)
{
return !(strchr_m(name, *lp_winbind_separator()));
}
/*****************************************************************
Splits passed user or group name to domain and user/group name parts
Returns True if name was splitted and False otherwise.
*****************************************************************/
BOOL split_domain_and_name(const char *name, char *domain, char* username)
{
char *p = strchr(name,*lp_winbind_separator());
/* Parse a string of the form DOMAIN/user into a domain and a user */
DEBUG(10,("split_domain_and_name: checking whether name |%s| local or not\n", name));
if (p) {
fstrcpy(username, p+1);
fstrcpy(domain, name);
domain[PTR_DIFF(p, name)] = 0;
} else if (lp_winbind_use_default_domain()) {
fstrcpy(username, name);
fstrcpy(domain, lp_workgroup());
} else {
return False;
}
DEBUG(10,("split_domain_and_name: all is fine, domain is |%s| and name is |%s|\n", domain, username));
return True;
}
/****************************************************************************
Get a users home directory.
****************************************************************************/
char *get_user_home_dir(const char *user)
{
struct passwd *pass;
/* Ensure the user exists. */
pass = Get_Pwnam(user);
if (!pass)
return(NULL);
/* Return home directory from struct passwd. */
return(pass->pw_dir);
}
/****************************************************************************
* A wrapper for sys_getpwnam(). The following variations are tried:
* - as transmitted
* - in all lower case if this differs from transmitted
* - in all upper case if this differs from transmitted
* - using lp_usernamelevel() for permutations.
****************************************************************************/
static struct passwd *Get_Pwnam_ret = NULL;
static struct passwd *Get_Pwnam_internals(const char *user, char *user2)
{
struct passwd *ret = NULL;
if (!user2 || !(*user2))
return(NULL);
if (!user || !(*user))
return(NULL);
/* Try in all lower case first as this is the most
common case on UNIX systems */
strlower(user2);
DEBUG(5,("Trying _Get_Pwnam(), username as lowercase is %s\n",user2));
ret = getpwnam_alloc(user2);
if(ret)
goto done;
/* Try as given, if username wasn't originally lowercase */
if(strcmp(user, user2) != 0) {
DEBUG(5,("Trying _Get_Pwnam(), username as given is %s\n", user));
ret = getpwnam_alloc(user);
if(ret)
goto done;
}
/* Try as uppercase, if username wasn't originally uppercase */
strupper(user2);
if(strcmp(user, user2) != 0) {
DEBUG(5,("Trying _Get_Pwnam(), username as uppercase is %s\n", user2));
ret = getpwnam_alloc(user2);
if(ret)
goto done;
}
/* Try all combinations up to usernamelevel */
strlower(user2);
DEBUG(5,("Checking combinations of %d uppercase letters in %s\n", lp_usernamelevel(), user2));
ret = uname_string_combinations(user2, getpwnam_alloc, lp_usernamelevel());
done:
DEBUG(5,("Get_Pwnam_internals %s find user [%s]!\n",ret ? "did":"didn't", user));
/* This call used to just return the 'passwd' static buffer.
This could then have accidental reuse implications, so
we now malloc a copy, and free it in the next use.
This should cause the (ab)user to segfault if it
uses an old struct.
This is better than useing the wrong data in security
critical operations.
The real fix is to make the callers free the returned
malloc'ed data.
*/
if (Get_Pwnam_ret) {
passwd_free(&Get_Pwnam_ret);
}
Get_Pwnam_ret = ret;
return ret;
}
/****************************************************************************
Get_Pwnam wrapper without modification.
NOTE: This with NOT modify 'user'!
****************************************************************************/
struct passwd *Get_Pwnam(const char *user)
{
fstring user2;
struct passwd *ret;
fstrcpy(user2, user);
DEBUG(5,("Finding user %s\n", user));
ret = Get_Pwnam_internals(user, user2);
return ret;
}
/****************************************************************************
Check if a user is in a netgroup user list.
****************************************************************************/
static BOOL user_in_netgroup_list(const char *user, const char *ngname)
{
#ifdef HAVE_NETGROUP
//static char *mydomain = NULL;
/* REWRITE: make thread safe if caching */
char *mydomain = NULL;
//if (mydomain == NULL)
yp_get_default_domain(&mydomain);
if(mydomain == NULL) {
DEBUG(5,("Unable to get default yp domain\n"));
return False;
}
DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
user, mydomain, ngname));
DEBUG(5,("innetgr is %s\n", innetgr(ngname, NULL, user, mydomain)
? "TRUE" : "FALSE"));
if (innetgr(ngname, NULL, user, mydomain))
return (True);
#endif /* HAVE_NETGROUP */
return False;
}
/****************************************************************************
Check if a user is in a winbind group.
****************************************************************************/
static BOOL user_in_winbind_group_list(const char *user, const char *gname, BOOL *winbind_answered)
{
int num_groups;
int i;
gid_t *groups = NULL;
gid_t gid, gid_low, gid_high;
BOOL ret = False;
*winbind_answered = False;
if ((gid = nametogid(gname)) == (gid_t)-1) {
DEBUG(0,("user_in_winbind_group_list: nametogid for group %s failed.\n",
gname ));
goto err;
}
if (!lp_winbind_gid(&gid_low, &gid_high)) {
DEBUG(4, ("winbind gid range not configured, therefore %s cannot be a winbind group\n", gname));
goto err;
}
if (gid < gid_low || gid > gid_high) {
DEBUG(4, ("group %s is not a winbind group\n", gname));
goto err;
}
/*
* Get the gid's that this user belongs to.
*/
if ((num_groups = winbind_getgroups(user, 0, NULL)) == -1)
return False;
if (num_groups == 0) {
*winbind_answered = True;
return False;
}
if ((groups = (gid_t *)malloc(sizeof(gid_t) * num_groups )) == NULL) {
DEBUG(0,("user_in_winbind_group_list: malloc fail.\n"));
goto err;
}
if ((num_groups = winbind_getgroups(user, num_groups, groups)) == -1) {
DEBUG(0,("user_in_winbind_group_list: second winbind_getgroups call \
failed with error %s\n", strerror(errno) ));
goto err;
}
/*
* Now we have the gid list for this user - convert the gname
* to a gid_t via either winbind or the local UNIX lookup and do the comparison.
*/
for (i = 0; i < num_groups; i++) {
if (gid == groups[i]) {
ret = True;
break;
}
}
*winbind_answered = True;
SAFE_FREE(groups);
return ret;
err:
*winbind_answered = False;
SAFE_FREE(groups);
return False;
}
/****************************************************************************
Check if a user is in a UNIX group.
****************************************************************************/
static BOOL user_in_unix_group_list(const char *user,const char *gname)
{
struct passwd *pass = Get_Pwnam(user);
struct sys_userlist *user_list;
struct sys_userlist *member;
TALLOC_CTX *mem_ctx;
DEBUG(10,("user_in_unix_group_list: checking user %s in group %s\n", user, gname));
/*
* We need to check the users primary group as this
* group is implicit and often not listed in the group database.
*/
mem_ctx = talloc_init("smbgroupedit talloc");
if (!mem_ctx) return -1;
if (pass) {
if (strequal(gname,gidtoname(mem_ctx, pass->pw_gid))) {
DEBUG(10,("user_in_unix_group_list: group %s is primary group.\n", gname ));
goto exit;
}
}
user_list = get_users_in_group(gname);
if (user_list == NULL) {
DEBUG(10,("user_in_unix_group_list: no such group %s\n", gname ));
return False;
}
for (member = user_list; member; member = member->next) {
DEBUG(10,("user_in_unix_group_list: checking user %s against member %s\n",
user, member->unix_name ));
if (strequal(member->unix_name,user)) {
free_userlist(user_list);
goto exit;
}
}
free_userlist(user_list);
talloc_destroy(mem_ctx);
return False;
exit:
talloc_destroy(mem_ctx);
return True;
}
/****************************************************************************
Check if a user is in a group list. Ask winbind first, then use UNIX.
****************************************************************************/
static BOOL user_in_group_list(const char *user, const char *gname, gid_t *groups, size_t n_groups)
{
BOOL winbind_answered = False;
BOOL ret;
gid_t gid;
unsigned i;
gid = nametogid(gname);
if (gid == (gid_t)-1)
return False;
if (groups && n_groups > 0) {
for (i=0; i < n_groups; i++) {
if (groups[i] == gid) {
return True;
}
}
return False;
}
/* fallback if we don't yet have the group list */
ret = user_in_winbind_group_list(user, gname, &winbind_answered);
if (!winbind_answered)
ret = user_in_unix_group_list(user, gname);
if (ret)
DEBUG(10,("user_in_group_list: user |%s| is in group |%s|\n", user, gname));
return ret;
}
/****************************************************************************
Check if a user is in a user list - can check combinations of UNIX
and netgroup lists.
****************************************************************************/
BOOL user_in_list(const char *user,const char **list, gid_t *groups, size_t n_groups)
{
if (!list || !*list)
return False;
DEBUG(10,("user_in_list: checking user %s in list\n", user));
while (*list) {
DEBUG(10,("user_in_list: checking user |%s| against |%s|\n", user, *list));
/*
* Check raw username.
*/
if (strequal(user, *list))
return(True);
/*
* Now check to see if any combination
* of UNIX and netgroups has been specified.
*/
if(**list == '@') {
/*
* Old behaviour. Check netgroup list
* followed by UNIX list.
*/
if(user_in_netgroup_list(user, *list +1))
return True;
if(user_in_group_list(user, *list +1, groups, n_groups))
return True;
} else if (**list == '+') {
if((*(*list +1)) == '&') {
/*
* Search UNIX list followed by netgroup.
*/
if(user_in_group_list(user, *list +2, groups, n_groups))
return True;
if(user_in_netgroup_list(user, *list +2))
return True;
} else {
/*
* Just search UNIX list.
*/
if(user_in_group_list(user, *list +1, groups, n_groups))
return True;
}
} else if (**list == '&') {
if(*(*list +1) == '+') {
/*
* Search netgroup list followed by UNIX list.
*/
if(user_in_netgroup_list(user, *list +2))
return True;
if(user_in_group_list(user, *list +2, groups, n_groups))
return True;
} else {
/*
* Just search netgroup list.
*/
if(user_in_netgroup_list(user, *list +1))
return True;
}
} else if (!name_is_local(*list)) {
/*
* If user name did not match and token is not
* a unix group and the token has a winbind separator in the
* name then see if it is a Windows group.
*/
DOM_SID g_sid;
enum SID_NAME_USE name_type;
BOOL winbind_answered = False;
BOOL ret;
fstring groupname, domain;
/* Parse a string of the form DOMAIN/user into a domain and a user */
char *p = strchr(*list,*lp_winbind_separator());
DEBUG(10,("user_in_list: checking if user |%s| is in winbind group |%s|\n", user, *list));
if (p) {
fstrcpy(groupname, p+1);
fstrcpy(domain, *list);
domain[PTR_DIFF(p, *list)] = 0;
/* Check to see if name is a Windows group */
if (winbind_lookup_name(domain, groupname, &g_sid, &name_type) && name_type == SID_NAME_DOM_GRP) {
/* Check if user name is in the Windows group */
ret = user_in_winbind_group_list(user, *list, &winbind_answered);
if (winbind_answered && ret == True) {
DEBUG(10,("user_in_list: user |%s| is in winbind group |%s|\n", user, *list));
return ret;
}
}
}
}
list++;
}
return(False);
}
/* The functions below have been taken from password.c and slightly modified */
/****************************************************************************
Apply a function to upper/lower case combinations
of a string and return true if one of them returns true.
Try all combinations with N uppercase letters.
offset is the first char to try and change (start with 0)
it assumes the string starts lowercased
****************************************************************************/
static struct passwd *uname_string_combinations2(char *s,int offset,struct passwd *(*fn)(const char *),int N)
{
ssize_t len = (ssize_t)strlen(s);
int i;
struct passwd *ret;
if (N <= 0 || offset >= len)
return(fn(s));
for (i=offset;i<(len-(N-1));i++) {
char c = s[i];
if (!islower((int)c))
continue;
s[i] = toupper(c);
ret = uname_string_combinations2(s,i+1,fn,N-1);
if(ret)
return(ret);
s[i] = c;
}
return(NULL);
}
/****************************************************************************
Apply a function to upper/lower case combinations
of a string and return true if one of them returns true.
Try all combinations with up to N uppercase letters.
offset is the first char to try and change (start with 0)
it assumes the string starts lowercased
****************************************************************************/
static struct passwd * uname_string_combinations(char *s,struct passwd * (*fn)(const char *),int N)
{
int n;
struct passwd *ret;
for (n=1;n<=N;n++) {
ret = uname_string_combinations2(s,0,fn,n);
if(ret)
return(ret);
}
return(NULL);
}

1000
source/lib/util.c Normal file

File diff suppressed because it is too large Load Diff

531
source/lib/util_file.c Normal file
View File

@@ -0,0 +1,531 @@
/*
* Unix SMB/CIFS implementation.
* SMB parameters and setup
* Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
*
* 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 int gotalarm;
/***************************************************************
Signal function to tell us we timed out.
****************************************************************/
static void gotalarm_sig(void)
{
gotalarm = 1;
}
/***************************************************************
Lock or unlock a fd for a known lock type. Abandon after waitsecs
seconds.
****************************************************************/
BOOL do_file_lock(int fd, int waitsecs, int type)
{
SMB_STRUCT_FLOCK lock;
int ret;
void (*oldsig_handler)(int);
gotalarm = 0;
oldsig_handler = CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
lock.l_type = type;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 1;
lock.l_pid = 0;
alarm(waitsecs);
/* Note we must *NOT* use sys_fcntl here ! JRA */
ret = fcntl(fd, SMB_F_SETLKW, &lock);
alarm(0);
CatchSignal(SIGALRM, SIGNAL_CAST oldsig_handler);
if (gotalarm) {
DEBUG(0, ("do_file_lock: failed to %s file.\n",
type == F_UNLCK ? "unlock" : "lock"));
return False;
}
return (ret == 0);
}
/***************************************************************
Lock an fd. Abandon after waitsecs seconds.
****************************************************************/
BOOL file_lock(int fd, int type, int secs, int *plock_depth)
{
if (fd < 0)
return False;
(*plock_depth)++;
if ((*plock_depth) == 0)
{
if (!do_file_lock(fd, secs, type)) {
DEBUG(10,("file_lock: locking file failed, error = %s.\n",
strerror(errno)));
return False;
}
}
return True;
}
/***************************************************************
Unlock an fd. Abandon after waitsecs seconds.
****************************************************************/
BOOL file_unlock(int fd, int *plock_depth)
{
BOOL ret=True;
if(*plock_depth == 1)
ret = do_file_lock(fd, 5, F_UNLCK);
(*plock_depth)--;
if(!ret)
DEBUG(10,("file_unlock: unlocking file failed, error = %s.\n",
strerror(errno)));
return ret;
}
/*************************************************************************
gets a line out of a file.
line is of format "xxxx:xxxxxx:xxxxx:".
lines with "#" at the front are ignored.
*************************************************************************/
int getfileline(void *vp, char *linebuf, int linebuf_size)
{
/* Static buffers we will return. */
FILE *fp = (FILE *)vp;
unsigned char c;
unsigned char *p;
size_t linebuf_len;
if (fp == NULL)
{
DEBUG(0,("getfileline: Bad file pointer.\n"));
return -1;
}
/*
* Scan the file, a line at a time.
*/
while (!feof(fp))
{
linebuf[0] = '\0';
fgets(linebuf, linebuf_size, fp);
if (ferror(fp))
{
return -1;
}
/*
* Check if the string is terminated with a newline - if not
* then we must keep reading and discard until we get one.
*/
linebuf_len = strlen(linebuf);
if (linebuf_len == 0)
{
linebuf[0] = '\0';
return 0;
}
if (linebuf[linebuf_len - 1] != '\n')
{
c = '\0';
while (!ferror(fp) && !feof(fp))
{
c = fgetc(fp);
if (c == '\n')
{
break;
}
}
}
else
{
linebuf[linebuf_len - 1] = '\0';
}
#ifdef DEBUG_PASSWORD
DEBUG(100, ("getfileline: got line |%s|\n", linebuf));
#endif
if ((linebuf[0] == 0) && feof(fp))
{
DEBUG(4, ("getfileline: end of file reached\n"));
return 0;
}
if (linebuf[0] == '#' || linebuf[0] == '\0')
{
DEBUG(6, ("getfileline: skipping comment or blank line\n"));
continue;
}
p = (unsigned char *) strchr_m(linebuf, ':');
if (p == NULL)
{
DEBUG(0, ("getfileline: malformed line entry (no :)\n"));
continue;
}
return linebuf_len;
}
return -1;
}
/****************************************************************************
read a line from a file with possible \ continuation chars.
Blanks at the start or end of a line are stripped.
The string will be allocated if s2 is NULL
****************************************************************************/
char *fgets_slash(char *s2,int maxlen,XFILE *f)
{
char *s=s2;
int len = 0;
int c;
BOOL start_of_line = True;
if (x_feof(f))
return(NULL);
if (maxlen <2) return(NULL);
if (!s2)
{
maxlen = MIN(maxlen,8);
s = (char *)malloc(maxlen);
}
if (!s) return(NULL);
*s = 0;
while (len < maxlen-1)
{
c = x_getc(f);
switch (c)
{
case '\r':
break;
case '\n':
while (len > 0 && s[len-1] == ' ')
{
s[--len] = 0;
}
if (len > 0 && s[len-1] == '\\')
{
s[--len] = 0;
start_of_line = True;
break;
}
return(s);
case EOF:
if (len <= 0 && !s2)
SAFE_FREE(s);
return(len>0?s:NULL);
case ' ':
if (start_of_line)
break;
default:
start_of_line = False;
s[len++] = c;
s[len] = 0;
}
if (!s2 && len > maxlen-3)
{
char *t;
maxlen *= 2;
t = (char *)Realloc(s,maxlen);
if (!t) {
DEBUG(0,("fgets_slash: failed to expand buffer!\n"));
SAFE_FREE(s);
return(NULL);
} else s = t;
}
}
return(s);
}
/****************************************************************************
load from a pipe into memory
****************************************************************************/
char *file_pload(char *syscmd, size_t *size)
{
int fd, n;
char *p, *tp;
pstring buf;
size_t total;
fd = sys_popen(syscmd);
if (fd == -1) return NULL;
p = NULL;
total = 0;
while ((n = read(fd, buf, sizeof(buf))) > 0) {
tp = Realloc(p, total + n + 1);
if (!tp) {
DEBUG(0,("file_pload: failed to expand buffer!\n"));
close(fd);
SAFE_FREE(p);
return NULL;
} else p = tp;
memcpy(p+total, buf, n);
total += n;
}
if (p) p[total] = 0;
/* FIXME: Perhaps ought to check that the command completed
* successfully (returned 0); if not the data may be
* truncated. */
sys_pclose(fd);
if (size) *size = total;
return p;
}
/****************************************************************************
load a file into memory from a fd.
****************************************************************************/
char *fd_load(int fd, size_t *size)
{
SMB_STRUCT_STAT sbuf;
char *p;
if (sys_fstat(fd, &sbuf) != 0) return NULL;
p = (char *)malloc(sbuf.st_size+1);
if (!p) return NULL;
if (read(fd, p, sbuf.st_size) != sbuf.st_size) {
SAFE_FREE(p);
return NULL;
}
p[sbuf.st_size] = 0;
if (size) *size = sbuf.st_size;
return p;
}
/****************************************************************************
load a file into memory
****************************************************************************/
char *file_load(const char *fname, size_t *size)
{
int fd;
char *p;
if (!fname || !*fname) return NULL;
fd = open(fname,O_RDONLY);
if (fd == -1) return NULL;
p = fd_load(fd, size);
close(fd);
return p;
}
/*******************************************************************
mmap (if possible) or read a file
********************************************************************/
void *map_file(char *fname, size_t size)
{
size_t s2 = 0;
void *p = NULL;
#ifdef HAVE_MMAP
if (lp_use_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);
if (!p) return NULL;
if (s2 != size) {
DEBUG(1,("incorrect size for %s - got %d expected %d\n",
fname, s2, size));
if (p) free(p);
return NULL;
}
}
return p;
}
/****************************************************************************
parse a buffer into lines
****************************************************************************/
static char **file_lines_parse(char *p, size_t size, int *numlines)
{
int i;
char *s, **ret;
if (!p) return NULL;
for (s = p, i=0; s < p+size; s++) {
if (s[0] == '\n') i++;
}
ret = (char **)malloc(sizeof(ret[0])*(i+2));
if (!ret) {
SAFE_FREE(p);
return NULL;
}
memset(ret, 0, sizeof(ret[0])*(i+2));
if (numlines) *numlines = i;
ret[0] = p;
for (s = p, i=0; s < p+size; s++) {
if (s[0] == '\n') {
s[0] = 0;
i++;
ret[i] = s+1;
}
if (s[0] == '\r') s[0] = 0;
}
return ret;
}
/****************************************************************************
load a file into memory and return an array of pointers to lines in the file
must be freed with file_lines_free().
****************************************************************************/
char **file_lines_load(const char *fname, int *numlines)
{
char *p;
size_t size;
p = file_load(fname, &size);
if (!p) return NULL;
return file_lines_parse(p, size, numlines);
}
/****************************************************************************
load a fd into memory and return an array of pointers to lines in the file
must be freed with file_lines_free(). If convert is true calls unix_to_dos on
the list.
****************************************************************************/
char **fd_lines_load(int fd, int *numlines)
{
char *p;
size_t size;
p = fd_load(fd, &size);
if (!p) return NULL;
return file_lines_parse(p, size, numlines);
}
/****************************************************************************
load a pipe into memory and return an array of pointers to lines in the data
must be freed with file_lines_free().
****************************************************************************/
char **file_lines_pload(char *syscmd, int *numlines)
{
char *p;
size_t size;
p = file_pload(syscmd, &size);
if (!p) return NULL;
return file_lines_parse(p, size, numlines);
}
/****************************************************************************
free lines loaded with file_lines_load
****************************************************************************/
void file_lines_free(char **lines)
{
if (!lines) return;
SAFE_FREE(lines[0]);
SAFE_FREE(lines);
}
/****************************************************************************
take a lislist of lines and modify them to produce a list where \ continues
a line
****************************************************************************/
void file_lines_slashcont(char **lines)
{
int i, j;
for (i=0; lines[i];) {
int len = strlen(lines[i]);
if (lines[i][len-1] == '\\') {
lines[i][len-1] = ' ';
if (lines[i+1]) {
char *p = &lines[i][len];
while (p < lines[i+1]) *p++ = ' ';
for (j = i+1; lines[j]; j++) lines[j] = lines[j+1];
}
} else {
i++;
}
}
}
/*
save a lump of data into a file. Mostly used for debugging
*/
BOOL file_save(const char *fname, 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;
}

306
source/lib/util_getent.c Normal file
View File

@@ -0,0 +1,306 @@
/*
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 = (struct sys_grent *) malloc(sizeof(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 = (char **) malloc((num+1) * sizeof(char *))) == 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 = (struct sys_grent *) malloc(sizeof(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 = (struct sys_pwent *) malloc(sizeof(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 = (struct sys_pwent *) malloc(sizeof(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 = (struct sys_userlist *)malloc(sizeof(*entry));
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;
fstring domain;
fstring groupname;
DOM_SID sid;
enum SID_NAME_USE name_type;
/* No point using winbind if we can't split it in the
first place */
if (split_domain_and_name(gname, domain, groupname)) {
/*
* If we're doing this via winbindd, don't do the
* entire group list enumeration as we know this is
* pointless (and slow).
*/
if (winbind_lookup_name(domain, groupname, &sid, &name_type)
&& name_type == SID_NAME_DOM_GRP) {
if ((gptr = (struct group *)getgrnam(gname)) == NULL)
return NULL;
return add_members_to_userlist(list_head, 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
source/lib/util_pw.c Normal file
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(sizeof(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);
}

486
source/lib/util_seaccess.c Normal file
View File

@@ -0,0 +1,486 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Luke Kenneth Casson Leighton 1996-2000.
Copyright (C) Tim Potter 2000.
Copyright (C) Re-written by Jeremy Allison 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"
extern DOM_SID global_sid_Builtin;
/**********************************************************************************
Check if this ACE has a SID in common with the token.
**********************************************************************************/
static BOOL token_sid_in_ace(const NT_USER_TOKEN *token, const SEC_ACE *ace)
{
size_t i;
for (i = 0; i < token->num_sids; i++) {
if (sid_equal(&ace->trustee, &token->user_sids[i]))
return True;
}
return False;
}
/*********************************************************************************
Check an ACE against a SID. We return the remaining needed permission
bits not yet granted. Zero means permission allowed (no more needed bits).
**********************************************************************************/
static uint32 check_ace(SEC_ACE *ace, const NT_USER_TOKEN *token, uint32 acc_desired,
NTSTATUS *status)
{
uint32 mask = ace->info.mask;
/*
* Inherit only is ignored.
*/
if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
return acc_desired;
}
/*
* If this ACE has no SID in common with the token,
* ignore it as it cannot be used to make an access
* determination.
*/
if (!token_sid_in_ace( token, ace))
return acc_desired;
switch (ace->type) {
case SEC_ACE_TYPE_ACCESS_ALLOWED:
/*
* This is explicitly allowed.
* Remove the bits from the remaining
* access required. Return the remaining
* bits needed.
*/
acc_desired &= ~mask;
break;
case SEC_ACE_TYPE_ACCESS_DENIED:
/*
* This is explicitly denied.
* If any bits match terminate here,
* we are denied.
*/
if (acc_desired & mask) {
*status = NT_STATUS_ACCESS_DENIED;
return 0xFFFFFFFF;
}
break;
case SEC_ACE_TYPE_SYSTEM_ALARM:
case SEC_ACE_TYPE_SYSTEM_AUDIT:
*status = NT_STATUS_NOT_IMPLEMENTED;
return 0xFFFFFFFF;
default:
*status = NT_STATUS_INVALID_PARAMETER;
return 0xFFFFFFFF;
}
return acc_desired;
}
/*********************************************************************************
Maximum access was requested. Calculate the max possible. Fail if it doesn't
include other bits requested.
**********************************************************************************/
static BOOL get_max_access( SEC_ACL *the_acl, const NT_USER_TOKEN *token, uint32 *granted,
uint32 desired,
NTSTATUS *status)
{
uint32 acc_denied = 0;
uint32 acc_granted = 0;
size_t i;
for ( i = 0 ; i < the_acl->num_aces; i++) {
SEC_ACE *ace = &the_acl->ace[i];
uint32 mask = ace->info.mask;
if (!token_sid_in_ace( token, ace))
continue;
switch (ace->type) {
case SEC_ACE_TYPE_ACCESS_ALLOWED:
acc_granted |= (mask & ~acc_denied);
break;
case SEC_ACE_TYPE_ACCESS_DENIED:
acc_denied |= (mask & ~acc_granted);
break;
case SEC_ACE_TYPE_SYSTEM_ALARM:
case SEC_ACE_TYPE_SYSTEM_AUDIT:
*status = NT_STATUS_NOT_IMPLEMENTED;
*granted = 0;
return False;
default:
*status = NT_STATUS_INVALID_PARAMETER;
*granted = 0;
return False;
}
}
/*
* If we were granted no access, or we desired bits that we
* didn't get, then deny.
*/
if ((acc_granted == 0) || ((acc_granted & desired) != desired)) {
*status = NT_STATUS_ACCESS_DENIED;
*granted = 0;
return False;
}
/*
* Return the access we did get.
*/
*granted = acc_granted;
*status = NT_STATUS_OK;
return True;
}
/* Map generic access rights to object specific rights. This technique is
used to give meaning to assigning read, write, execute and all access to
objects. Each type of object has its own mapping of generic to object
specific access rights. */
void se_map_generic(uint32 *access_mask, struct generic_mapping *mapping)
{
uint32 old_mask = *access_mask;
if (*access_mask & GENERIC_READ_ACCESS) {
*access_mask &= ~GENERIC_READ_ACCESS;
*access_mask |= mapping->generic_read;
}
if (*access_mask & GENERIC_WRITE_ACCESS) {
*access_mask &= ~GENERIC_WRITE_ACCESS;
*access_mask |= mapping->generic_write;
}
if (*access_mask & GENERIC_EXECUTE_ACCESS) {
*access_mask &= ~GENERIC_EXECUTE_ACCESS;
*access_mask |= mapping->generic_execute;
}
if (*access_mask & GENERIC_ALL_ACCESS) {
*access_mask &= ~GENERIC_ALL_ACCESS;
*access_mask |= mapping->generic_all;
}
if (old_mask != *access_mask) {
DEBUG(10, ("se_map_generic(): mapped mask 0x%08x to 0x%08x\n",
old_mask, *access_mask));
}
}
/* Map standard access rights to object specific rights. This technique is
used to give meaning to assigning read, write, execute and all access to
objects. Each type of object has its own mapping of standard to object
specific access rights. */
void se_map_standard(uint32 *access_mask, struct standard_mapping *mapping)
{
uint32 old_mask = *access_mask;
if (*access_mask & READ_CONTROL_ACCESS) {
*access_mask &= ~READ_CONTROL_ACCESS;
*access_mask |= mapping->std_read;
}
if (*access_mask & (DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|SYNCHRONIZE_ACCESS)) {
*access_mask &= ~(DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|SYNCHRONIZE_ACCESS);
*access_mask |= mapping->std_all;
}
if (old_mask != *access_mask) {
DEBUG(10, ("se_map_standard(): mapped mask 0x%08x to 0x%08x\n",
old_mask, *access_mask));
}
}
/*****************************************************************************
Check access rights of a user against a security descriptor. Look at
each ACE in the security descriptor until an access denied ACE denies
any of the desired rights to the user or any of the users groups, or one
or more ACEs explicitly grant all requested access rights. See
"Access-Checking" document in MSDN.
*****************************************************************************/
BOOL se_access_check(const SEC_DESC *sd, const NT_USER_TOKEN *token,
uint32 acc_desired, uint32 *acc_granted,
NTSTATUS *status)
{
extern NT_USER_TOKEN anonymous_token;
size_t i;
SEC_ACL *the_acl;
fstring sid_str;
uint32 tmp_acc_desired = acc_desired;
if (!status || !acc_granted)
return False;
if (!token)
token = &anonymous_token;
*status = NT_STATUS_OK;
*acc_granted = 0;
DEBUG(10,("se_access_check: requested access 0x%08x, for NT token with %u entries and first sid %s.\n",
(unsigned int)acc_desired, (unsigned int)token->num_sids,
sid_to_string(sid_str, &token->user_sids[0])));
/*
* No security descriptor or security descriptor with no DACL
* present allows all access.
*/
/* ACL must have something in it */
if (!sd || (sd && (!(sd->type & SEC_DESC_DACL_PRESENT) || sd->dacl == NULL))) {
*status = NT_STATUS_OK;
*acc_granted = acc_desired;
DEBUG(5, ("se_access_check: no sd or blank DACL, access allowed\n"));
return True;
}
/* The user sid is the first in the token */
if (DEBUGLVL(3)) {
DEBUG(3, ("se_access_check: user sid is %s\n", sid_to_string(sid_str, &token->user_sids[PRIMARY_USER_SID_INDEX]) ));
for (i = 1; i < token->num_sids; i++) {
DEBUGADD(3, ("se_access_check: also %s\n",
sid_to_string(sid_str, &token->user_sids[i])));
}
}
/* Is the token the owner of the SID ? */
if (sd->owner_sid) {
for (i = 0; i < token->num_sids; i++) {
if (sid_equal(&token->user_sids[i], sd->owner_sid)) {
/*
* The owner always has SEC_RIGHTS_WRITE_DAC & READ_CONTROL.
*/
if (tmp_acc_desired & WRITE_DAC_ACCESS)
tmp_acc_desired &= ~WRITE_DAC_ACCESS;
if (tmp_acc_desired & READ_CONTROL_ACCESS)
tmp_acc_desired &= ~READ_CONTROL_ACCESS;
}
}
}
the_acl = sd->dacl;
if (tmp_acc_desired & MAXIMUM_ALLOWED_ACCESS) {
tmp_acc_desired &= ~MAXIMUM_ALLOWED_ACCESS;
return get_max_access( the_acl, token, acc_granted, tmp_acc_desired,
status);
}
for ( i = 0 ; i < the_acl->num_aces && tmp_acc_desired != 0; i++) {
SEC_ACE *ace = &the_acl->ace[i];
DEBUGADD(10,("se_access_check: ACE %u: type %d, flags = 0x%02x, SID = %s mask = %x, current desired = %x\n",
(unsigned int)i, ace->type, ace->flags,
sid_to_string(sid_str, &ace->trustee),
(unsigned int) ace->info.mask,
(unsigned int)tmp_acc_desired ));
tmp_acc_desired = check_ace( ace, token, tmp_acc_desired, status);
if (NT_STATUS_V(*status)) {
*acc_granted = 0;
DEBUG(5,("se_access_check: ACE %u denied with status %s.\n", (unsigned int)i, nt_errstr(*status)));
return False;
}
}
/*
* If there are no more desired permissions left then
* access was allowed.
*/
if (tmp_acc_desired == 0) {
*acc_granted = acc_desired;
*status = NT_STATUS_OK;
DEBUG(5,("se_access_check: access (%x) granted.\n", (unsigned int)acc_desired ));
return True;
}
*acc_granted = 0;
*status = NT_STATUS_ACCESS_DENIED;
DEBUG(5,("se_access_check: access (%x) denied.\n", (unsigned int)acc_desired ));
return False;
}
/* Create a child security descriptor using another security descriptor as
the parent container. This child object can either be a container or
non-container object. */
SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr,
BOOL child_container)
{
SEC_DESC_BUF *sdb;
SEC_DESC *sd;
SEC_ACL *new_dacl, *the_acl;
SEC_ACE *new_ace_list = NULL;
unsigned int new_ace_list_ndx = 0, i;
size_t size;
/* Currently we only process the dacl when creating the child. The
sacl should also be processed but this is left out as sacls are
not implemented in Samba at the moment.*/
the_acl = parent_ctr->dacl;
if (!(new_ace_list = talloc(ctx, sizeof(SEC_ACE) * the_acl->num_aces)))
return NULL;
for (i = 0; the_acl && i < the_acl->num_aces; i++) {
SEC_ACE *ace = &the_acl->ace[i];
SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
uint8 new_flags = 0;
BOOL inherit = False;
fstring sid_str;
/* The OBJECT_INHERIT_ACE flag causes the ACE to be
inherited by non-container children objects. Container
children objects will inherit it as an INHERIT_ONLY
ACE. */
if (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
if (!child_container) {
new_flags |= SEC_ACE_FLAG_OBJECT_INHERIT;
} else {
new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
}
inherit = True;
}
/* The CONAINER_INHERIT_ACE flag means all child container
objects will inherit and use the ACE. */
if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
if (!child_container) {
inherit = False;
} else {
new_flags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
}
}
/* The INHERIT_ONLY_ACE is not used by the se_access_check()
function for the parent container, but is inherited by
all child objects as a normal ACE. */
if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
/* Move along, nothing to see here */
}
/* The SEC_ACE_FLAG_NO_PROPAGATE_INHERIT flag means the ACE
is inherited by child objects but not grandchildren
objects. We clear the object inherit and container
inherit flags in the inherited ACE. */
if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
new_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT |
SEC_ACE_FLAG_CONTAINER_INHERIT);
}
/* Add ACE to ACE list */
if (!inherit)
continue;
init_sec_access(&new_ace->info, ace->info.mask);
init_sec_ace(new_ace, &ace->trustee, ace->type,
new_ace->info, new_flags);
sid_to_string(sid_str, &ace->trustee);
DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
" inherited as %s:%d/0x%02x/0x%08x\n", sid_str,
ace->type, ace->flags, ace->info.mask,
sid_str, new_ace->type, new_ace->flags,
new_ace->info.mask));
new_ace_list_ndx++;
}
/* Create child security descriptor to return */
new_dacl = make_sec_acl(ctx, ACL_REVISION, new_ace_list_ndx, new_ace_list);
/* Use the existing user and group sids. I don't think this is
correct. Perhaps the user and group should be passed in as
parameters by the caller? */
sd = make_sec_desc(ctx, SEC_DESC_REVISION,
parent_ctr->owner_sid,
parent_ctr->grp_sid,
parent_ctr->sacl,
new_dacl, &size);
sdb = make_sec_desc_buf(ctx, size, sd);
return sdb;
}
/*******************************************************************
samr_make_sam_obj_sd
********************************************************************/
NTSTATUS samr_make_sam_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd_size)
{
extern DOM_SID global_sid_World;
DOM_SID adm_sid;
DOM_SID act_sid;
SEC_ACE ace[3];
SEC_ACCESS mask;
SEC_ACL *psa = NULL;
sid_copy(&adm_sid, &global_sid_Builtin);
sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
sid_copy(&act_sid, &global_sid_Builtin);
sid_append_rid(&act_sid, BUILTIN_ALIAS_RID_ACCOUNT_OPS);
/*basic access for every one*/
init_sec_access(&mask, GENERIC_RIGHTS_SAM_EXECUTE | GENERIC_RIGHTS_SAM_READ);
init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
/*full access for builtin aliases Administrators and Account Operators*/
init_sec_access(&mask, GENERIC_RIGHTS_SAM_ALL_ACCESS);
init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
init_sec_ace(&ace[2], &act_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) == NULL)
return NT_STATUS_NO_MEMORY;
if ((*psd = make_sec_desc(ctx, SEC_DESC_REVISION, NULL, NULL, NULL, psa, sd_size)) == NULL)
return NT_STATUS_NO_MEMORY;
return NT_STATUS_OK;
}

631
source/lib/util_sid.c Normal file
View File

@@ -0,0 +1,631 @@
/*
Unix SMB/CIFS implementation.
Samba utility functions
Copyright (C) Andrew Tridgell 1992-1998
Copyright (C) Luke Kenneth Caseson Leighton 1998-1999
Copyright (C) Jeremy Allison 1999
Copyright (C) Stefan (metze) Metzmacher 2002
Copyright (C) Simo Sorce 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"
/*
* Some useful sids
*/
DOM_SID global_sid_World_Domain; /* Everyone domain */
DOM_SID global_sid_World; /* Everyone */
DOM_SID global_sid_Creator_Owner_Domain; /* Creator Owner domain */
DOM_SID global_sid_NT_Authority; /* NT Authority */
DOM_SID global_sid_System; /* System */
DOM_SID global_sid_NULL; /* NULL sid */
DOM_SID global_sid_Authenticated_Users; /* All authenticated rids */
DOM_SID global_sid_Network; /* Network rids */
DOM_SID global_sid_Creator_Owner; /* Creator Owner */
DOM_SID global_sid_Creator_Group; /* Creator Group */
DOM_SID global_sid_Anonymous; /* Anonymous login */
DOM_SID global_sid_Builtin; /* Local well-known domain */
DOM_SID global_sid_Builtin_Administrators; /* Builtin administrators */
DOM_SID global_sid_Builtin_Users; /* Builtin users */
DOM_SID global_sid_Builtin_Guests; /* Builtin guest users */
DOM_SID global_sid_Builtin_Power_Users; /* Builtin power users */
DOM_SID global_sid_Builtin_Account_Operators; /* Builtin account operators */
DOM_SID global_sid_Builtin_Server_Operators; /* Builtin server operators */
DOM_SID global_sid_Builtin_Print_Operators; /* Builtin print operators */
DOM_SID global_sid_Builtin_Backup_Operators; /* Builtin backup operators */
DOM_SID global_sid_Builtin_Replicator; /* Builtin replicator */
#define SECURITY_NULL_SID_AUTHORITY 0
#define SECURITY_WORLD_SID_AUTHORITY 1
#define SECURITY_LOCAL_SID_AUTHORITY 2
#define SECURITY_CREATOR_SID_AUTHORITY 3
#define SECURITY_NT_AUTHORITY 5
/*
* An NT compatible anonymous token.
*/
static DOM_SID anon_sid_array[3];
NT_USER_TOKEN anonymous_token = {
3,
anon_sid_array
};
static DOM_SID system_sid_array[4];
NT_USER_TOKEN system_token = {
1,
system_sid_array
};
/****************************************************************************
Lookup string names for SID types.
****************************************************************************/
static const struct {
enum SID_NAME_USE sid_type;
const char *string;
} sid_name_type[] = {
{SID_NAME_USER, "User"},
{SID_NAME_DOM_GRP, "Domain Group"},
{SID_NAME_DOMAIN, "Domain"},
{SID_NAME_ALIAS, "Local Group"},
{SID_NAME_WKN_GRP, "Well-known Group"},
{SID_NAME_DELETED, "Deleted Account"},
{SID_NAME_INVALID, "Invalid Account"},
{SID_NAME_UNKNOWN, "UNKNOWN"},
{SID_NAME_USE_NONE, NULL}
};
const char *sid_type_lookup(uint32 sid_type)
{
int i = 0;
/* Look through list */
while(sid_name_type[i].sid_type != 0) {
if (sid_name_type[i].sid_type == sid_type)
return sid_name_type[i].string;
i++;
}
/* Default return */
return "SID *TYPE* is INVALID";
}
/****************************************************************************
Creates some useful well known sids
****************************************************************************/
void generate_wellknown_sids(void)
{
static BOOL initialised = False;
if (initialised)
return;
/* SECURITY_NULL_SID_AUTHORITY */
string_to_sid(&global_sid_NULL, "S-1-0-0");
/* SECURITY_WORLD_SID_AUTHORITY */
string_to_sid(&global_sid_World_Domain, "S-1-1");
string_to_sid(&global_sid_World, "S-1-1-0");
/* SECURITY_CREATOR_SID_AUTHORITY */
string_to_sid(&global_sid_Creator_Owner_Domain, "S-1-3");
string_to_sid(&global_sid_Creator_Owner, "S-1-3-0");
string_to_sid(&global_sid_Creator_Group, "S-1-3-1");
/* SECURITY_NT_AUTHORITY */
string_to_sid(&global_sid_NT_Authority, "S-1-5");
string_to_sid(&global_sid_Network, "S-1-5-2");
string_to_sid(&global_sid_Anonymous, "S-1-5-7");
string_to_sid(&global_sid_Authenticated_Users, "S-1-5-11");
string_to_sid(&global_sid_System, "S-1-5-18");
/* SECURITY_BUILTIN_DOMAIN_RID */
string_to_sid(&global_sid_Builtin, "S-1-5-32");
string_to_sid(&global_sid_Builtin_Administrators, "S-1-5-32-544");
string_to_sid(&global_sid_Builtin_Users, "S-1-5-32-545");
string_to_sid(&global_sid_Builtin_Guests, "S-1-5-32-546");
string_to_sid(&global_sid_Builtin_Power_Users, "S-1-5-32-547");
string_to_sid(&global_sid_Builtin_Account_Operators, "S-1-5-32-548");
string_to_sid(&global_sid_Builtin_Server_Operators, "S-1-5-32-549");
string_to_sid(&global_sid_Builtin_Print_Operators, "S-1-5-32-550");
string_to_sid(&global_sid_Builtin_Backup_Operators, "S-1-5-32-551");
string_to_sid(&global_sid_Builtin_Replicator, "S-1-5-32-552");
/* Create the anon token. */
sid_copy( &anonymous_token.user_sids[0], &global_sid_World);
sid_copy( &anonymous_token.user_sids[1], &global_sid_Network);
sid_copy( &anonymous_token.user_sids[2], &global_sid_Anonymous);
/* Create the system token. */
sid_copy( &system_token.user_sids[0], &global_sid_System);
initialised = True;
}
/**************************************************************************
Create the SYSTEM token.
***************************************************************************/
NT_USER_TOKEN *get_system_token(void)
{
generate_wellknown_sids(); /* The token is initialised here */
return &system_token;
}
/**************************************************************************
Splits a name of format \DOMAIN\name or name into its two components.
Sets the DOMAIN name to lp_netbios_name() if it has not been specified.
***************************************************************************/
void split_domain_name(const char *fullname, char *domain, char *name)
{
pstring full_name;
const char *sep;
char *p;
sep = lp_winbind_separator();
*domain = *name = '\0';
if (fullname[0] == sep[0] || fullname[0] == '\\')
fullname++;
pstrcpy(full_name, fullname);
p = strchr_m(full_name+1, '\\');
if (!p) p = strchr_m(full_name+1, sep[0]);
if (p != NULL) {
*p = 0;
fstrcpy(domain, full_name);
fstrcpy(name, p+1);
} else {
fstrcpy(domain, lp_netbios_name());
fstrcpy(name, full_name);
}
DEBUG(10,("split_domain_name:name '%s' split into domain :'%s' and user :'%s'\n",
fullname, domain, name));
}
/****************************************************************************
Test if a SID is wellknown and resolvable.
****************************************************************************/
BOOL resolvable_wellknown_sid(DOM_SID *sid)
{
uint32 ia = (sid->id_auth[5]) +
(sid->id_auth[4] << 8 ) +
(sid->id_auth[3] << 16) +
(sid->id_auth[2] << 24);
if (sid->sid_rev_num != SEC_DESC_REVISION || sid->num_auths < 1)
return False;
return (ia == SECURITY_WORLD_SID_AUTHORITY ||
ia == SECURITY_CREATOR_SID_AUTHORITY);
}
/*****************************************************************
Convert a SID to an ascii string.
*****************************************************************/
char *sid_to_string(fstring sidstr_out, const DOM_SID *sid)
{
char subauth[16];
int i;
uint32 ia;
if (!sid) {
fstrcpy(sidstr_out, "(NULL SID)");
return sidstr_out;
}
/*
* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32
* in a range of 2^48.
*/
ia = (sid->id_auth[5]) +
(sid->id_auth[4] << 8 ) +
(sid->id_auth[3] << 16) +
(sid->id_auth[2] << 24);
slprintf(sidstr_out, sizeof(fstring) - 1, "S-%u-%lu", (unsigned int)sid->sid_rev_num, (unsigned long)ia);
for (i = 0; i < sid->num_auths; i++) {
slprintf(subauth, sizeof(subauth)-1, "-%lu", (unsigned long)sid->sub_auths[i]);
fstrcat(sidstr_out, subauth);
}
return sidstr_out;
}
/*****************************************************************
Useful function for debug lines.
*****************************************************************/
const char *sid_string_talloc(TALLOC_CTX *mem_ctx, const DOM_SID *sid)
{
fstring tempSid;
sid_to_string(tempSid, sid);
return talloc_strdup(mem_ctx, tempSid);
}
/*****************************************************************
Convert a string to a SID. Returns True on success, False on fail.
*****************************************************************/
BOOL string_to_sid(DOM_SID *sidout, const char *sidstr)
{
pstring tok;
char *q;
const char *p;
/* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
uint32 ia;
if (StrnCaseCmp( sidstr, "S-", 2)) {
DEBUG(0,("string_to_sid: Sid %s does not start with 'S-'.\n", sidstr));
return False;
}
memset((char *)sidout, '\0', sizeof(DOM_SID));
p = q = strdup(sidstr + 2);
if (p == NULL) {
DEBUG(0, ("string_to_sid: out of memory!\n"));
return False;
}
if (!next_token(&p, tok, "-", sizeof(tok))) {
DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr));
SAFE_FREE(q);
return False;
}
/* Get the revision number. */
sidout->sid_rev_num = (uint8)strtoul(tok, NULL, 10);
if (!next_token(&p, tok, "-", sizeof(tok))) {
DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr));
SAFE_FREE(q);
return False;
}
/* identauth in decimal should be < 2^32 */
ia = (uint32)strtoul(tok, NULL, 10);
/* NOTE - the ia value is in big-endian format. */
sidout->id_auth[0] = 0;
sidout->id_auth[1] = 0;
sidout->id_auth[2] = (ia & 0xff000000) >> 24;
sidout->id_auth[3] = (ia & 0x00ff0000) >> 16;
sidout->id_auth[4] = (ia & 0x0000ff00) >> 8;
sidout->id_auth[5] = (ia & 0x000000ff);
sidout->num_auths = 0;
while(next_token(&p, tok, "-", sizeof(tok)) &&
sidout->num_auths < MAXSUBAUTHS) {
/*
* NOTE - the subauths are in native machine-endian format. They
* are converted to little-endian when linearized onto the wire.
*/
sid_append_rid(sidout, (uint32)strtoul(tok, NULL, 10));
}
SAFE_FREE(q);
return True;
}
/*****************************************************************
Add a rid to the end of a sid
*****************************************************************/
BOOL sid_append_rid(DOM_SID *sid, uint32 rid)
{
if (sid->num_auths < MAXSUBAUTHS) {
sid->sub_auths[sid->num_auths++] = rid;
return True;
}
return False;
}
/*****************************************************************
Removes the last rid from the end of a sid
*****************************************************************/
BOOL sid_split_rid(DOM_SID *sid, uint32 *rid)
{
if (sid->num_auths > 0) {
sid->num_auths--;
*rid = sid->sub_auths[sid->num_auths];
return True;
}
return False;
}
/*****************************************************************
Return the last rid from the end of a sid
*****************************************************************/
BOOL sid_peek_rid(const DOM_SID *sid, uint32 *rid)
{
if (!sid || !rid)
return False;
if (sid->num_auths > 0) {
*rid = sid->sub_auths[sid->num_auths - 1];
return True;
}
return False;
}
/*****************************************************************
Return the last rid from the end of a sid
and check the sid against the exp_dom_sid
*****************************************************************/
BOOL sid_peek_check_rid(const DOM_SID *exp_dom_sid, const DOM_SID *sid, uint32 *rid)
{
if (!exp_dom_sid || !sid || !rid)
return False;
if (sid_compare_domain(exp_dom_sid, sid)!=0){
*rid=(-1);
return False;
}
return sid_peek_rid(sid, rid);
}
/*****************************************************************
Copies a sid
*****************************************************************/
void sid_copy(DOM_SID *dst, const DOM_SID *src)
{
int i;
ZERO_STRUCTP(dst);
dst->sid_rev_num = src->sid_rev_num;
dst->num_auths = src->num_auths;
memcpy(&dst->id_auth[0], &src->id_auth[0], sizeof(src->id_auth));
for (i = 0; i < src->num_auths; i++)
dst->sub_auths[i] = src->sub_auths[i];
}
/*****************************************************************
Write a sid out into on-the-wire format.
*****************************************************************/
BOOL sid_linearize(char *outbuf, size_t len, const DOM_SID *sid)
{
size_t i;
if (len < sid_size(sid))
return False;
SCVAL(outbuf,0,sid->sid_rev_num);
SCVAL(outbuf,1,sid->num_auths);
memcpy(&outbuf[2], sid->id_auth, 6);
for(i = 0; i < sid->num_auths; i++)
SIVAL(outbuf, 8 + (i*4), sid->sub_auths[i]);
return True;
}
/*****************************************************************
Parse a on-the-wire SID to a DOM_SID.
*****************************************************************/
BOOL sid_parse(const char *inbuf, size_t len, DOM_SID *sid)
{
int i;
if (len < 8)
return False;
ZERO_STRUCTP(sid);
sid->sid_rev_num = CVAL(inbuf, 0);
sid->num_auths = CVAL(inbuf, 1);
memcpy(sid->id_auth, inbuf+2, 6);
if (len < 8 + sid->num_auths*4)
return False;
for (i=0;i<sid->num_auths;i++)
sid->sub_auths[i] = IVAL(inbuf, 8+i*4);
return True;
}
/*****************************************************************
Compare the auth portion of two sids.
*****************************************************************/
static int sid_compare_auth(const DOM_SID *sid1, const DOM_SID *sid2)
{
int i;
if (sid1 == sid2)
return 0;
if (!sid1)
return -1;
if (!sid2)
return 1;
if (sid1->sid_rev_num != sid2->sid_rev_num)
return sid1->sid_rev_num - sid2->sid_rev_num;
for (i = 0; i < 6; i++)
if (sid1->id_auth[i] != sid2->id_auth[i])
return sid1->id_auth[i] - sid2->id_auth[i];
return 0;
}
/*****************************************************************
Compare two sids.
*****************************************************************/
int sid_compare(const DOM_SID *sid1, const DOM_SID *sid2)
{
int i;
if (sid1 == sid2)
return 0;
if (!sid1)
return -1;
if (!sid2)
return 1;
/* Compare most likely different rids, first: i.e start at end */
if (sid1->num_auths != sid2->num_auths)
return sid1->num_auths - sid2->num_auths;
for (i = sid1->num_auths-1; i >= 0; --i)
if (sid1->sub_auths[i] != sid2->sub_auths[i])
return sid1->sub_auths[i] - sid2->sub_auths[i];
return sid_compare_auth(sid1, sid2);
}
/*****************************************************************
See if 2 SIDs are in the same domain
this just compares the leading sub-auths
*****************************************************************/
int sid_compare_domain(const DOM_SID *sid1, const DOM_SID *sid2)
{
int n, i;
n = MIN(sid1->num_auths, sid2->num_auths);
for (i = n-1; i >= 0; --i)
if (sid1->sub_auths[i] != sid2->sub_auths[i])
return sid1->sub_auths[i] - sid2->sub_auths[i];
return sid_compare_auth(sid1, sid2);
}
/*****************************************************************
Compare two sids.
*****************************************************************/
BOOL sid_equal(const DOM_SID *sid1, const DOM_SID *sid2)
{
return sid_compare(sid1, sid2) == 0;
}
/*****************************************************************
Check if the SID is the builtin SID (S-1-5-32).
*****************************************************************/
BOOL sid_check_is_builtin(const DOM_SID *sid)
{
return sid_equal(sid, &global_sid_Builtin);
}
/*****************************************************************
Check if the SID is one of the builtin SIDs (S-1-5-32-a).
*****************************************************************/
BOOL sid_check_is_in_builtin(const DOM_SID *sid)
{
DOM_SID dom_sid;
uint32 rid;
sid_copy(&dom_sid, sid);
sid_split_rid(&dom_sid, &rid);
return sid_equal(&dom_sid, &global_sid_Builtin);
}
/*****************************************************************
Calculates size of a sid.
*****************************************************************/
size_t sid_size(const DOM_SID *sid)
{
if (sid == NULL)
return 0;
return sid->num_auths * sizeof(uint32) + 8;
}
/*****************************************************************
Returns true if SID is internal (and non-mappable).
*****************************************************************/
BOOL non_mappable_sid(DOM_SID *sid)
{
DOM_SID dom;
uint32 rid;
sid_copy(&dom, sid);
sid_split_rid(&dom, &rid);
if (sid_equal(&dom, &global_sid_Builtin))
return True;
if (sid_equal(&dom, &global_sid_NT_Authority))
return True;
return False;
}
/*****************************************************************
Return the binary string representation of a DOM_SID.
Caller must free.
*****************************************************************/
char *sid_binstring(const DOM_SID *sid)
{
char *buf, *s;
int len = sid_size(sid);
buf = malloc(len);
if (!buf)
return NULL;
sid_linearize(buf, len, sid);
s = binary_string(buf, len);
free(buf);
return s;
}
/*****************************************************************
Print a GUID structure for debugging.
*****************************************************************/
void print_guid(GUID *guid)
{
int i;
d_printf("%08x-%04x-%04x",
IVAL(guid->info, 0), SVAL(guid->info, 4), SVAL(guid->info, 6));
d_printf("-%02x%02x-", guid->info[8], guid->info[9]);
for (i=10;i<GUID_SIZE;i++)
d_printf("%02x", guid->info[i]);
d_printf("\n");
}

65
source/lib/util_smbd.c Normal file
View File

@@ -0,0 +1,65 @@
/*
Unix SMB/CIFS implementation.
Samba utility functions, used in smbd only
Copyright (C) Andrew Tridgell 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"
/*
This function requires sys_getgrouplist - which is only
available in smbd due to it's use of become_root() in a
legacy systems hack.
*/
/*
return a full list of groups for a user
returns the number of groups the user is a member of. The return will include the
users primary group.
remember to free the resulting gid_t array
NOTE! uses become_root() to gain correct priviages on systems
that lack a native getgroups() call (uses initgroups and getgroups)
*/
int getgroups_user(const char *user, gid_t **groups)
{
struct passwd *pwd;
int ngrp, max_grp;
pwd = getpwnam_alloc(user);
if (!pwd) return -1;
max_grp = groups_max();
(*groups) = (gid_t *)malloc(sizeof(gid_t) * max_grp);
if (! *groups) {
passwd_free(&pwd);
errno = ENOMEM;
return -1;
}
ngrp = sys_getgrouplist(user, pwd->pw_gid, *groups, &max_grp);
if (ngrp <= 0) {
passwd_free(&pwd);
free(*groups);
return ngrp;
}
passwd_free(&pwd);
return ngrp;
}

631
source/lib/util_sock.c Normal file
View File

@@ -0,0 +1,631 @@
/*
Unix SMB/CIFS implementation.
Samba utility functions
Copyright (C) Andrew Tridgell 1992-1998
Copyright (C) Tim Potter 2000-2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
/****************************************************************************
Determine if a file descriptor is in fact a socket.
****************************************************************************/
BOOL is_a_socket(int fd)
{
int v,l;
l = sizeof(int);
return getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0;
}
enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
typedef struct smb_socket_option {
const char *name;
int level;
int option;
int value;
int opttype;
} smb_socket_option;
static const smb_socket_option socket_options[] = {
{"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
{"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
{"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
#ifdef TCP_NODELAY
{"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
#endif
#ifdef IPTOS_LOWDELAY
{"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
#endif
#ifdef IPTOS_THROUGHPUT
{"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
#endif
#ifdef SO_REUSEPORT
{"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
#endif
#ifdef SO_SNDBUF
{"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
#endif
#ifdef SO_RCVBUF
{"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
#endif
#ifdef SO_SNDLOWAT
{"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
#endif
#ifdef SO_RCVLOWAT
{"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
#endif
#ifdef SO_SNDTIMEO
{"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
#endif
#ifdef SO_RCVTIMEO
{"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
#endif
{NULL,0,0,0,0}};
/****************************************************************************
Print socket options.
****************************************************************************/
static void print_socket_options(int s)
{
int value, vlen = 4;
const smb_socket_option *p = &socket_options[0];
for (; p->name != NULL; p++) {
if (getsockopt(s, p->level, p->option, (void *)&value, &vlen) == -1) {
DEBUG(5,("Could not test socket option %s.\n", p->name));
} else {
DEBUG(5,("socket option %s = %d\n",p->name,value));
}
}
}
/****************************************************************************
Set user socket options.
****************************************************************************/
void set_socket_options(int fd, const char *options)
{
fstring tok;
while (next_token(&options,tok," \t,", sizeof(tok))) {
int ret=0,i;
int value = 1;
char *p;
BOOL got_value = False;
if ((p = strchr_m(tok,'='))) {
*p = 0;
value = atoi(p+1);
got_value = True;
}
for (i=0;socket_options[i].name;i++)
if (strequal(socket_options[i].name,tok))
break;
if (!socket_options[i].name) {
DEBUG(0,("Unknown socket option %s\n",tok));
continue;
}
switch (socket_options[i].opttype) {
case OPT_BOOL:
case OPT_INT:
ret = setsockopt(fd,socket_options[i].level,
socket_options[i].option,(char *)&value,sizeof(int));
break;
case OPT_ON:
if (got_value)
DEBUG(0,("syntax error - %s does not take a value\n",tok));
{
int on = socket_options[i].value;
ret = setsockopt(fd,socket_options[i].level,
socket_options[i].option,(char *)&on,sizeof(int));
}
break;
}
if (ret != 0)
DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok, strerror(errno) ));
}
print_socket_options(fd);
}
/****************************************************************************
Read from a socket.
****************************************************************************/
ssize_t read_udp_socket(int fd, char *buf, size_t len,
struct in_addr *from_addr, int *from_port)
{
ssize_t ret;
struct sockaddr_in sock;
socklen_t socklen = sizeof(sock);
ret = (ssize_t)sys_recvfrom(fd,buf,len, 0, (struct sockaddr *)&sock, &socklen);
if (ret <= 0) {
DEBUG(2,("read socket failed. ERRNO=%s\n",strerror(errno)));
return 0;
}
if (from_addr) {
*from_addr = sock.sin_addr;
}
if (from_port) {
*from_port = ntohs(sock.sin_port);
}
return ret;
}
/****************************************************************************
read data from the client, reading exactly N bytes.
****************************************************************************/
ssize_t read_data(int fd, char *buffer, size_t N)
{
ssize_t ret;
size_t total=0;
while (total < N) {
ret = sys_read(fd,buffer + total,N - total);
if (ret == 0) {
return 0;
}
if (ret == -1) {
return -1;
}
total += ret;
}
return (ssize_t)total;
}
/****************************************************************************
Write data to a fd.
****************************************************************************/
ssize_t write_data(int fd, const char *buffer, size_t N)
{
size_t total=0;
ssize_t ret;
while (total < N) {
ret = sys_write(fd, buffer + total, N - total);
if (ret == -1) {
return -1;
}
if (ret == 0)
return total;
total += ret;
}
return (ssize_t)total;
}
/****************************************************************************
send a keepalive packet (rfc1002)
****************************************************************************/
BOOL send_nbt_keepalive(int sock_fd)
{
unsigned char buf[4];
buf[0] = SMBkeepalive;
buf[1] = buf[2] = buf[3] = 0;
return write_data(sock_fd,(char *)buf,4) == 4;
}
/****************************************************************************
Open a socket of the specified type, port, and address for incoming data.
****************************************************************************/
int open_socket_in( int type, int port, int dlevel, uint32 socket_addr, BOOL rebind )
{
struct sockaddr_in sock;
int res;
memset( (char *)&sock, '\0', sizeof(sock) );
#ifdef HAVE_SOCK_SIN_LEN
sock.sin_len = sizeof(sock);
#endif
sock.sin_port = htons( port );
sock.sin_family = AF_INET;
sock.sin_addr.s_addr = socket_addr;
res = socket( AF_INET, type, 0 );
if( res == -1 ) {
DEBUG(0,("open_socket_in(): socket() call failed: %s\n", strerror(errno)));
return -1;
}
/* This block sets/clears the SO_REUSEADDR and possibly SO_REUSEPORT. */
{
int val = rebind ? 1 : 0;
setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val));
#ifdef SO_REUSEPORT
setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val));
#endif
}
/* now we've got a socket - we need to bind it */
if( bind( res, (struct sockaddr *)&sock, sizeof(sock) ) == -1 ) {
DEBUG(0,("bind failed on port %d - %s\n", port, strerror(errno)));
close( res );
return( -1 );
}
DEBUG( 10, ( "bind succeeded on port %d\n", port ) );
return( res );
}
/****************************************************************************
create an outgoing socket. timeout is in milliseconds.
**************************************************************************/
int open_socket_out(int type, struct in_addr *addr, int port, int timeout)
{
struct sockaddr_in sock_out;
int res,ret;
int connect_loop = 250; /* 250 milliseconds */
int loops = (timeout) / connect_loop;
/* create a socket to write to */
res = socket(PF_INET, type, 0);
if (res == -1)
{ DEBUG(0,("socket error\n")); return -1; }
if (type != SOCK_STREAM) return(res);
memset((char *)&sock_out,'\0',sizeof(sock_out));
putip((char *)&sock_out.sin_addr,(char *)addr);
sock_out.sin_port = htons( port );
sock_out.sin_family = PF_INET;
/* set it non-blocking */
set_blocking(res,False);
DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port));
/* and connect it to the destination */
connect_again:
ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out));
/* Some systems return EAGAIN when they mean EINPROGRESS */
if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
errno == EAGAIN) && loops--) {
msleep(connect_loop);
goto connect_again;
}
if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
errno == EAGAIN)) {
DEBUG(1,("timeout connecting to %s:%d\n",inet_ntoa(*addr),port));
close(res);
return -1;
}
#ifdef EISCONN
if (ret < 0 && errno == EISCONN) {
errno = 0;
ret = 0;
}
#endif
if (ret < 0) {
DEBUG(2,("error connecting to %s:%d (%s)\n",
inet_ntoa(*addr),port,strerror(errno)));
close(res);
return -1;
}
/* set it blocking again */
set_blocking(res,True);
return res;
}
/*
open a connected UDP socket to host on port
*/
int open_udp_socket(const char *host, int port)
{
int type = SOCK_DGRAM;
struct sockaddr_in sock_out;
int res;
struct in_addr *addr;
TALLOC_CTX *mem_ctx;
mem_ctx = talloc_init("open_udp_socket");
if (!mem_ctx) {
return -1;
}
addr = interpret_addr2(mem_ctx, host);
res = socket(PF_INET, type, 0);
if (res == -1) {
return -1;
}
memset((char *)&sock_out,'\0',sizeof(sock_out));
putip((char *)&sock_out.sin_addr,(char *)addr);
sock_out.sin_port = htons(port);
sock_out.sin_family = PF_INET;
talloc_destroy(mem_ctx);
if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))) {
close(res);
return -1;
}
return res;
}
/*******************************************************************
matchname - determine if host name matches IP address. Used to
confirm a hostname lookup to prevent spoof attacks
******************************************************************/
static BOOL matchname(char *remotehost, struct in_addr addr)
{
struct hostent *hp;
int i;
if ((hp = sys_gethostbyname(remotehost)) == 0) {
DEBUG(0,("sys_gethostbyname(%s): lookup failure.\n", remotehost));
return False;
}
/*
* Make sure that gethostbyname() returns the "correct" host name.
* Unfortunately, gethostbyname("localhost") sometimes yields
* "localhost.domain". Since the latter host name comes from the
* local DNS, we just have to trust it (all bets are off if the local
* DNS is perverted). We always check the address list, though.
*/
if (strcasecmp(remotehost, hp->h_name)
&& strcasecmp(remotehost, "localhost")) {
DEBUG(0,("host name/name mismatch: %s != %s\n",
remotehost, hp->h_name));
return False;
}
/* Look up the host address in the address list we just got. */
for (i = 0; hp->h_addr_list[i]; i++) {
if (memcmp(hp->h_addr_list[i], (char *) & addr, sizeof(addr)) == 0)
return True;
}
/*
* The host name does not map to the original host address. Perhaps
* someone has compromised a name server. More likely someone botched
* it, but that could be dangerous, too.
*/
DEBUG(0,("host name/address mismatch: %s != %s\n",
inet_ntoa(addr), hp->h_name));
return False;
}
/*******************************************************************
return the DNS name of the remote end of a socket
******************************************************************/
char *get_socket_name(TALLOC_CTX *mem_ctx, int fd, BOOL force_lookup)
{
char *name_buf;
char *addr_buf;
struct hostent *hp;
struct in_addr addr;
char *p;
/* reverse lookups can be *very* expensive, and in many
situations won't work because many networks don't link dhcp
with dns. To avoid the delay we avoid the lookup if
possible */
if (!lp_hostname_lookups() && (force_lookup == False)) {
return get_socket_addr(mem_ctx, fd);
}
p = get_socket_addr(mem_ctx, fd);
name_buf = talloc_strdup(mem_ctx, "UNKNOWN");
if (fd == -1) return name_buf;
addr_buf = talloc_strdup(mem_ctx, p);
addr = *interpret_addr2(mem_ctx, p);
/* Look up the remote host name. */
if ((hp = gethostbyaddr((char *)&addr.s_addr, sizeof(addr.s_addr), AF_INET)) == 0) {
DEBUG(1,("Gethostbyaddr failed for %s\n",p));
name_buf = talloc_strdup(mem_ctx, p);
} else {
name_buf = talloc_strdup(mem_ctx, (char *)hp->h_name);
if (!matchname(name_buf, addr)) {
DEBUG(0,("Matchname failed on %s %s\n",name_buf,p));
name_buf = talloc_strdup(mem_ctx, "UNKNOWN");
}
}
alpha_strcpy(name_buf, name_buf, "_-.", sizeof(name_buf));
if (strstr(name_buf,"..")) {
name_buf = talloc_strdup(mem_ctx, "UNKNOWN");
}
return name_buf;
}
/*******************************************************************
return the IP addr of the remote end of a socket as a string
******************************************************************/
char *get_socket_addr(TALLOC_CTX *mem_ctx, int fd)
{
struct sockaddr sa;
struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
int length = sizeof(sa);
char *addr_buf;
addr_buf = talloc_strdup(mem_ctx, "0.0.0.0");
if (fd == -1) {
return addr_buf;
}
if (getpeername(fd, &sa, &length) < 0) {
DEBUG(0,("getpeername failed. Error was %s\n", strerror(errno) ));
return addr_buf;
}
addr_buf = talloc_strdup(mem_ctx, (char *)inet_ntoa(sockin->sin_addr));
return addr_buf;
}
/*******************************************************************
this is like socketpair but uses tcp. It is used by the Samba
regression test code
The function guarantees that nobody else can attach to the socket,
or if they do that this function fails and the socket gets closed
returns 0 on success, -1 on failure
the resulting file descriptors are symmetrical
******************************************************************/
static int socketpair_tcp(int fd[2])
{
int listener;
struct sockaddr_in sock;
struct sockaddr_in sock2;
socklen_t socklen = sizeof(sock);
int connect_done = 0;
fd[0] = fd[1] = listener = -1;
memset(&sock, 0, sizeof(sock));
if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
memset(&sock2, 0, sizeof(sock2));
#ifdef HAVE_SOCK_SIN_LEN
sock2.sin_len = sizeof(sock2);
#endif
sock2.sin_family = PF_INET;
bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
if (listen(listener, 1) != 0) goto failed;
if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
set_blocking(fd[1], 0);
sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
if (errno != EINPROGRESS) goto failed;
} else {
connect_done = 1;
}
if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
close(listener);
if (connect_done == 0) {
if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
&& errno != EISCONN) goto failed;
}
set_blocking(fd[1], 1);
/* all OK! */
return 0;
failed:
if (fd[0] != -1) close(fd[0]);
if (fd[1] != -1) close(fd[1]);
if (listener != -1) close(listener);
return -1;
}
/*******************************************************************
run a program on a local tcp socket, this is used to launch smbd
when regression testing
the return value is a socket which is attached to a subprocess
running "prog". stdin and stdout are attached. stderr is left
attached to the original stderr
******************************************************************/
int sock_exec(const char *prog)
{
int fd[2];
if (socketpair_tcp(fd) != 0) {
DEBUG(0,("socketpair_tcp failed (%s)\n", strerror(errno)));
return -1;
}
if (fork() == 0) {
close(fd[0]);
close(0);
close(1);
dup(fd[1]);
dup(fd[1]);
exit(system(prog));
}
close(fd[1]);
return fd[0];
}
/*
determine if a packet is pending for receive on a socket
*/
BOOL socket_pending(int fd)
{
fd_set fds;
int selrtn;
struct timeval timeout;
FD_ZERO(&fds);
FD_SET(fd,&fds);
/* immediate timeout */
timeout.tv_sec = 0;
timeout.tv_usec = 0;
/* yes, this is supposed to be a normal select not a sys_select() */
selrtn = select(fd+1,&fds,NULL,NULL,&timeout);
if (selrtn == 1) {
/* the fd is readable */
return True;
}
return False;
}

1619
source/lib/util_str.c Normal file

File diff suppressed because it is too large Load Diff

838
source/lib/util_unistr.c Normal file
View File

@@ -0,0 +1,838 @@
/*
Unix SMB/CIFS implementation.
Samba utility functions
Copyright (C) Andrew Tridgell 1992-2001
Copyright (C) Simo Sorce 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#ifndef MAXUNI
#define MAXUNI 1024
#endif
/* these 3 tables define the unicode case handling. They are loaded
at startup either via mmap() or read() from the lib directory */
static smb_ucs2_t *upcase_table;
static smb_ucs2_t *lowcase_table;
static uint8 *valid_table;
/*******************************************************************
load the case handling tables
********************************************************************/
void load_case_tables(void)
{
static int initialised;
int i;
TALLOC_CTX *mem_ctx;
if (initialised) return;
initialised = 1;
mem_ctx = talloc_init("load_case_tables");
if (!mem_ctx) {
smb_panic("No memory for case_tables");
}
upcase_table = map_file(lib_path(mem_ctx, "upcase.dat"), 0x20000);
lowcase_table = map_file(lib_path(mem_ctx, "lowcase.dat"), 0x20000);
talloc_destroy(mem_ctx);
/* we would like Samba to limp along even if these tables are
not available */
if (!upcase_table) {
DEBUG(1,("creating lame upcase table\n"));
upcase_table = malloc(0x20000);
if (!upcase_table) {
smb_panic("No memory for upcase tables");
}
for (i=0;i<0x10000;i++) {
smb_ucs2_t v;
SSVAL(&v, 0, i);
upcase_table[v] = i;
}
for (i=0;i<256;i++) {
smb_ucs2_t v;
SSVAL(&v, 0, UCS2_CHAR(i));
upcase_table[v] = UCS2_CHAR(islower(i)?toupper(i):i);
}
}
if (!lowcase_table) {
DEBUG(1,("creating lame lowcase table\n"));
lowcase_table = malloc(0x20000);
if (!lowcase_table) {
smb_panic("No memory for lowcase tables");
}
for (i=0;i<0x10000;i++) {
smb_ucs2_t v;
SSVAL(&v, 0, i);
lowcase_table[v] = i;
}
for (i=0;i<256;i++) {
smb_ucs2_t v;
SSVAL(&v, 0, UCS2_CHAR(i));
lowcase_table[v] = UCS2_CHAR(isupper(i)?tolower(i):i);
}
}
}
/*
see if a ucs2 character can be mapped correctly to a dos character
and mapped back to the same character in ucs2
*/
static int check_dos_char(smb_ucs2_t c)
{
char buf[10];
smb_ucs2_t c2 = 0;
int len1, len2;
len1 = convert_string(CH_UCS2, CH_DOS, &c, 2, buf, sizeof(buf));
if (len1 == 0) return 0;
len2 = convert_string(CH_DOS, CH_UCS2, buf, len1, &c2, 2);
if (len2 != 2) return 0;
return (c == c2);
}
/**
* Load the valid character map table from <tt>valid.dat</tt> or
* create from the configured codepage.
*
* This function is called whenever the configuration is reloaded.
* However, the valid character table is not changed if it's loaded
* from a file, because we can't unmap files.
**/
void init_valid_table(void)
{
static int mapped_file;
int i;
const char *allowed = ".!#$%&'()_-@^`~";
uint8 *valid_file;
TALLOC_CTX *mem_ctx;
if (mapped_file) {
/* Can't unmap files, so stick with what we have */
return;
}
mem_ctx = talloc_init("init_valid_table");
if (!mem_ctx) {
smb_panic("No memory for valid_table");
}
valid_file = map_file(lib_path(mem_ctx, "valid.dat"), 0x10000);
talloc_destroy(mem_ctx);
if (valid_file) {
valid_table = valid_file;
mapped_file = 1;
return;
}
/* Otherwise, we're using a dynamically created valid_table.
* It might need to be regenerated if the code page changed.
* We know that we're not using a mapped file, so we can
* free() the old one. */
if (valid_table) free(valid_table);
DEBUG(2,("creating default valid table\n"));
valid_table = malloc(0x10000);
if (!valid_table) {
smb_panic("No memory for valid_table");
}
for (i=0;i<128;i++)
valid_table[i] = isalnum(i) || strchr(allowed,i);
for (;i<0x10000;i++) {
smb_ucs2_t c;
SSVAL(&c, 0, i);
valid_table[i] = check_dos_char(c);
}
}
/*******************************************************************
Write a string in (little-endian) unicode format. src is in
the current DOS codepage. len is the length in bytes of the
string pointed to by dst.
if null_terminate is True then null terminate the packet (adds 2 bytes)
the return value is the length in bytes consumed by the string, including the
null termination if applied
********************************************************************/
size_t dos_PutUniCode(char *dst,const char *src, ssize_t len, BOOL null_terminate)
{
return push_ucs2(NULL, dst, src, len,
STR_UNICODE|STR_NOALIGN | (null_terminate?STR_TERMINATE:0));
}
/*******************************************************************
Skip past a unicode string, but not more than len. Always move
past a terminating zero if found.
********************************************************************/
char *skip_unibuf(char *src, size_t len)
{
char *srcend = src + len;
while (src < srcend && SVAL(src,0))
src += 2;
if(!SVAL(src,0))
src += 2;
return src;
}
/* Copy a string from little-endian or big-endian unicode source (depending
* on flags) to internal samba format destination
*/
int rpcstr_pull(char* dest, void *src, int dest_len, int src_len, int flags)
{
if (!src) return 0;
if(dest_len==-1) dest_len=MAXUNI-3;
return pull_ucs2(NULL, dest, src, dest_len, src_len, flags|STR_UNICODE|STR_NOALIGN);
}
/* Copy a string from a unistr2 source to internal samba format
destination. Use this instead of direct calls to rpcstr_pull() to avoid
having to determine whether the source string is null terminated. */
int rpcstr_pull_unistr2_fstring(char *dest, UNISTR2 *src)
{
return pull_ucs2(NULL, dest, src->buffer, sizeof(fstring),
src->uni_str_len * 2, 0);
}
/* Converts a string from internal samba format to unicode
*/
int rpcstr_push(void* dest, const char *src, int dest_len, int flags)
{
return push_ucs2(NULL, dest, src, dest_len, flags|STR_UNICODE|STR_NOALIGN);
}
/*******************************************************************
Convert a (little-endian) UNISTR2 structure to an ASCII string
********************************************************************/
void unistr2_to_ascii(char *dest, const UNISTR2 *str, size_t maxlen)
{
if (str == NULL) {
*dest='\0';
return;
}
pull_ucs2(NULL, dest, str->buffer, maxlen, str->uni_str_len*2, STR_NOALIGN);
}
/*******************************************************************
give a static string for displaying a UNISTR2
********************************************************************/
const char *unistr2_static(TALLOC_CTX *mem_ctx, const UNISTR2 *str)
{
pstring ret;
unistr2_to_ascii(ret, str, sizeof(ret));
return talloc_strdup(mem_ctx, ret);
}
/*******************************************************************
duplicate a UNISTR2 string into a null terminated char*
using a talloc context
********************************************************************/
char *unistr2_tdup(TALLOC_CTX *ctx, const UNISTR2 *str)
{
char *s;
int maxlen = (str->uni_str_len+1)*4;
if (!str->buffer) return NULL;
s = (char *)talloc(ctx, maxlen); /* convervative */
if (!s) return NULL;
pull_ucs2(NULL, s, str->buffer, maxlen, str->uni_str_len*2,
STR_NOALIGN);
return s;
}
/*******************************************************************
Return a number stored in a buffer
********************************************************************/
uint32 buffer2_to_uint32(BUFFER2 *str)
{
if (str->buf_len == 4)
return IVAL(str->buffer, 0);
else
return 0;
}
/*******************************************************************
Convert a wchar to upper case.
********************************************************************/
smb_ucs2_t toupper_w(smb_ucs2_t val)
{
return upcase_table[SVAL(&val,0)];
}
/*******************************************************************
Convert a wchar to lower case.
********************************************************************/
smb_ucs2_t tolower_w( smb_ucs2_t val )
{
return lowcase_table[SVAL(&val,0)];
}
/*******************************************************************
determine if a character is lowercase
********************************************************************/
BOOL islower_w(smb_ucs2_t c)
{
return upcase_table[SVAL(&c,0)] != c;
}
/*******************************************************************
determine if a character is uppercase
********************************************************************/
BOOL isupper_w(smb_ucs2_t c)
{
return lowcase_table[SVAL(&c,0)] != c;
}
/*******************************************************************
determine if a character is valid in a 8.3 name
********************************************************************/
BOOL isvalid83_w(smb_ucs2_t c)
{
return valid_table[SVAL(&c,0)] != 0;
}
/*******************************************************************
Count the number of characters in a smb_ucs2_t string.
********************************************************************/
size_t strlen_w(const smb_ucs2_t *src)
{
size_t len;
for (len = 0; SVAL(src,0); len++, src++) ;
return len;
}
/*******************************************************************
Count up to max number of characters in a smb_ucs2_t string.
********************************************************************/
size_t strnlen_w(const smb_ucs2_t *src, size_t max)
{
size_t len;
for (len = 0; (len < max) && SVAL(src, 0); len++, src++) ;
return len;
}
/*******************************************************************
wide strchr()
********************************************************************/
const smb_ucs2_t *strchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
{
while (*s != 0) {
if (c == *s) return s;
s++;
}
if (c == *s) return s;
return NULL;
}
const smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c)
{
return strchr_w(s, UCS2_CHAR(c));
}
const smb_ucs2_t *strrchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
{
const smb_ucs2_t *p = s;
int len = strlen_w(s);
if (len == 0) return NULL;
p += (len - 1);
do {
if (c == *p) return p;
} while (p-- != s);
return NULL;
}
/*******************************************************************
wide strstr()
********************************************************************/
const smb_ucs2_t *strstr_w(const smb_ucs2_t *s, const smb_ucs2_t *ins)
{
const smb_ucs2_t *r;
size_t slen, inslen;
if (!s || !*s || !ins || !*ins) return NULL;
slen = strlen_w(s);
inslen = strlen_w(ins);
r = s;
while ((r = strchr_w(r, *ins))) {
if (strncmp_w(r, ins, inslen) == 0) return r;
r++;
}
return NULL;
}
/*******************************************************************
Convert a string to lower case.
return True if any char is converted
********************************************************************/
BOOL strlower_w(smb_ucs2_t *s)
{
BOOL ret = False;
while (*s) {
smb_ucs2_t v = tolower_w(*s);
if (v != *s) {
*s = v;
ret = True;
}
s++;
}
return ret;
}
/*******************************************************************
Convert a string to upper case.
return True if any char is converted
********************************************************************/
BOOL strupper_w(smb_ucs2_t *s)
{
BOOL ret = False;
while (*s) {
smb_ucs2_t v = toupper_w(*s);
if (v != *s) {
*s = v;
ret = True;
}
s++;
}
return ret;
}
int strcmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
{
while (*b && *a == *b) { a++; b++; }
return (*a - *b);
/* warning: if *a != *b and both are not 0 we retrun a random
greater or lesser than 0 number not realted to which
string is longer */
}
int strncmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len)
{
size_t n = 0;
while ((n < len) && *b && *a == *b) { a++; b++; n++;}
return (len - n)?(*a - *b):0;
}
/*******************************************************************
case insensitive string comparison
********************************************************************/
int strcasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
{
while (*b && toupper_w(*a) == toupper_w(*b)) { a++; b++; }
return (tolower_w(*a) - tolower_w(*b));
}
/*******************************************************************
case insensitive string comparison, lenght limited
********************************************************************/
int strncasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len)
{
size_t n = 0;
while ((n < len) && *b && (toupper_w(*a) == toupper_w(*b))) { a++; b++; n++; }
return (len - n)?(tolower_w(*a) - tolower_w(*b)):0;
}
/*******************************************************************
compare 2 strings
********************************************************************/
BOOL strequal_w(const smb_ucs2_t *s1, const smb_ucs2_t *s2)
{
if (s1 == s2) return(True);
if (!s1 || !s2) return(False);
return(strcasecmp_w(s1,s2)==0);
}
/*******************************************************************
compare 2 strings up to and including the nth char.
******************************************************************/
BOOL strnequal_w(const smb_ucs2_t *s1,const smb_ucs2_t *s2,size_t n)
{
if (s1 == s2) return(True);
if (!s1 || !s2 || !n) return(False);
return(strncasecmp_w(s1,s2,n)==0);
}
/*******************************************************************
duplicate string
********************************************************************/
smb_ucs2_t *strdup_w(const smb_ucs2_t *src)
{
return strndup_w(src, 0);
}
/* if len == 0 then duplicate the whole string */
smb_ucs2_t *strndup_w(const smb_ucs2_t *src, size_t len)
{
smb_ucs2_t *dest;
if (!len) len = strlen_w(src);
dest = (smb_ucs2_t *)malloc((len + 1) * sizeof(smb_ucs2_t));
if (!dest) {
DEBUG(0,("strdup_w: out of memory!\n"));
return NULL;
}
memcpy(dest, src, len * sizeof(smb_ucs2_t));
dest[len] = 0;
return dest;
}
/*******************************************************************
copy a string with max len
********************************************************************/
smb_ucs2_t *strncpy_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
{
size_t len;
if (!dest || !src) return NULL;
for (len = 0; (src[len] != 0) && (len < max); len++)
dest[len] = src[len];
while (len < max)
dest[len++] = 0;
return dest;
}
/*******************************************************************
append a string of len bytes and add a terminator
********************************************************************/
smb_ucs2_t *strncat_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
{
size_t start;
size_t len;
if (!dest || !src) return NULL;
start = strlen_w(dest);
len = strnlen_w(src, max);
memcpy(&dest[start], src, len*sizeof(smb_ucs2_t));
dest[start+len] = 0;
return dest;
}
smb_ucs2_t *strcat_w(smb_ucs2_t *dest, const smb_ucs2_t *src)
{
size_t start;
size_t len;
if (!dest || !src) return NULL;
start = strlen_w(dest);
len = strlen_w(src);
memcpy(&dest[start], src, len*sizeof(smb_ucs2_t));
dest[start+len] = 0;
return dest;
}
/*******************************************************************
replace any occurence of oldc with newc in unicode string
********************************************************************/
void string_replace_w(smb_ucs2_t *s, smb_ucs2_t oldc, smb_ucs2_t newc)
{
for(;*s;s++) {
if(*s==oldc) *s=newc;
}
}
/*******************************************************************
trim unicode string
********************************************************************/
BOOL trim_string_w(smb_ucs2_t *s, const smb_ucs2_t *front,
const smb_ucs2_t *back)
{
BOOL ret = False;
size_t len, front_len, back_len;
if (!s || !*s) return False;
len = strlen_w(s);
if (front && *front) {
front_len = strlen_w(front);
while (len && strncmp_w(s, front, front_len) == 0) {
memmove(s, (s + front_len), (len - front_len + 1) * sizeof(smb_ucs2_t));
len -= front_len;
ret = True;
}
}
if (back && *back) {
back_len = strlen_w(back);
while (len && strncmp_w((s + (len - back_len)), back, back_len) == 0) {
s[len - back_len] = 0;
len -= back_len;
ret = True;
}
}
return ret;
}
/*
The *_wa() functions take a combination of 7 bit ascii
and wide characters They are used so that you can use string
functions combining C string constants with ucs2 strings
The char* arguments must NOT be multibyte - to be completely sure
of this only pass string constants */
void pstrcpy_wa(smb_ucs2_t *dest, const char *src)
{
int i;
for (i=0;i<PSTRING_LEN;i++) {
dest[i] = UCS2_CHAR(src[i]);
if (src[i] == 0) return;
}
}
int strcmp_wa(const smb_ucs2_t *a, const char *b)
{
while (*b && *a == UCS2_CHAR(*b)) { a++; b++; }
return (*a - UCS2_CHAR(*b));
}
int strncmp_wa(const smb_ucs2_t *a, const char *b, size_t len)
{
size_t n = 0;
while ((n < len) && *b && *a == UCS2_CHAR(*b)) { a++; b++; n++;}
return (len - n)?(*a - UCS2_CHAR(*b)):0;
}
const smb_ucs2_t *strpbrk_wa(const smb_ucs2_t *s, const char *p)
{
while (*s != 0) {
int i;
for (i=0; p[i] && *s != UCS2_CHAR(p[i]); i++)
;
if (p[i]) return s;
s++;
}
return NULL;
}
const smb_ucs2_t *strstr_wa(const smb_ucs2_t *s, const char *ins)
{
const smb_ucs2_t *r;
size_t slen, inslen;
if (!s || !*s || !ins || !*ins) return NULL;
slen = strlen_w(s);
inslen = strlen(ins);
r = s;
while ((r = strchr_w(r, UCS2_CHAR(*ins)))) {
if (strncmp_wa(r, ins, inslen) == 0) return r;
r++;
}
return NULL;
}
/*******************************************************************
copy a string with max len
********************************************************************/
smb_ucs2_t *strncpy_wa(smb_ucs2_t *dest, const char *src, const size_t max)
{
smb_ucs2_t *ucs2_src;
if (!dest || !src) return NULL;
if (!(ucs2_src = acnv_uxu2(src)))
return NULL;
strncpy_w(dest, ucs2_src, max);
SAFE_FREE(ucs2_src);
return dest;
}
/*******************************************************************
convert and duplicate an ascii string
********************************************************************/
smb_ucs2_t *strdup_wa(const char *src)
{
return strndup_wa(src, 0);
}
/* if len == 0 then duplicate the whole string */
smb_ucs2_t *strndup_wa(const char *src, size_t len)
{
smb_ucs2_t *dest, *s;
s = acnv_dosu2(src);
if (!len) len = strlen_w(s);
dest = (smb_ucs2_t *)malloc((len + 1) * sizeof(smb_ucs2_t));
if (!dest) {
DEBUG(0,("strdup_w: out of memory!\n"));
SAFE_FREE(s);
return NULL;
}
memcpy(dest, src, len * sizeof(smb_ucs2_t));
dest[len] = 0;
SAFE_FREE(s);
return dest;
}
/*******************************************************************
append a string of len bytes and add a terminator
********************************************************************/
smb_ucs2_t *strncat_wa(smb_ucs2_t *dest, const char *src, const size_t max)
{
smb_ucs2_t *ucs2_src;
if (!dest || !src) return NULL;
if (!(ucs2_src = acnv_uxu2(src)))
return NULL;
strncat_w(dest, ucs2_src, max);
SAFE_FREE(ucs2_src);
return dest;
}
smb_ucs2_t *strcat_wa(smb_ucs2_t *dest, const char *src)
{
smb_ucs2_t *ucs2_src;
if (!dest || !src) return NULL;
if (!(ucs2_src = acnv_uxu2(src)))
return NULL;
strcat_w(dest, ucs2_src);
SAFE_FREE(ucs2_src);
return dest;
}
BOOL trim_string_wa(smb_ucs2_t *s, const char *front,
const char *back)
{
wpstring f, b;
if (front) push_ucs2(NULL, f, front, sizeof(wpstring) - 1, STR_TERMINATE);
else *f = 0;
if (back) push_ucs2(NULL, b, back, sizeof(wpstring) - 1, STR_TERMINATE);
else *b = 0;
return trim_string_w(s, f, b);
}
/*******************************************************************
returns the length in number of wide characters
******************************************************************/
int unistrlen(uint16 *s)
{
int len;
if (!s)
return -1;
for (len=0; *s; s++,len++);
return len;
}
/*******************************************************************
Strcpy for unicode strings. returns length (in num of wide chars)
********************************************************************/
int unistrcpy(uint16 *dst, uint16 *src)
{
int num_wchars = 0;
while (*src) {
*dst++ = *src++;
num_wchars++;
}
*dst = 0;
return num_wchars;
}
/**
* Samba ucs2 type to UNISTR2 conversion
*
* @param ctx Talloc context to create the dst strcture (if null) and the
* contents of the unicode string.
* @param dst UNISTR2 destination. If equals null, then it's allocated.
* @param src smb_ucs2_t source.
* @param max_len maximum number of unicode characters to copy. If equals
* null, then null-termination of src is taken
*
* @return copied UNISTR2 destination
**/
UNISTR2* ucs2_to_unistr2(TALLOC_CTX *ctx, UNISTR2* dst, smb_ucs2_t* src)
{
size_t len;
if (!src) return NULL;
len = strlen_w(src);
/* allocate UNISTR2 destination if not given */
if (!dst) {
dst = (UNISTR2*) talloc(ctx, sizeof(UNISTR2));
if (!dst) return NULL;
}
if (!dst->buffer) {
dst->buffer = (uint16*) talloc(ctx, sizeof(uint16) * (len + 1));
if (!dst->buffer) return NULL;
}
/* set UNISTR2 parameters */
dst->uni_max_len = len + 1;
dst->undoc = 0;
dst->uni_str_len = len;
/* copy the actual unicode string */
strncpy_w(dst->buffer, src, dst->uni_max_len);
return dst;
};

104
source/lib/util_uuid.c Normal file
View File

@@ -0,0 +1,104 @@
/*
* Unix SMB/CIFS implementation.
* UUID server routines
* Copyright (C) Theodore Ts'o 1996, 1997,
* Copyright (C) Jim McDonough 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"
/*
* Offset between 15-Oct-1582 and 1-Jan-70
*/
#define TIME_OFFSET_HIGH 0x01B21DD2
#define TIME_OFFSET_LOW 0x13814000
struct uuid {
uint32 time_low;
uint16 time_mid;
uint16 time_hi_and_version;
uint8 clock_seq[2];
uint8 node[6];
};
static void uuid_pack(const struct uuid *uu, GUID *ptr)
{
uint8 *out = ptr->info;
SIVAL(out, 0, uu->time_low);
SSVAL(out, 4, uu->time_mid);
SSVAL(out, 6, uu->time_hi_and_version);
memcpy(out+8, uu->clock_seq, 2);
memcpy(out+10, uu->node, 6);
}
static void uuid_unpack(const GUID in, struct uuid *uu)
{
const uint8 *ptr = in.info;
uu->time_low = IVAL(ptr, 0);
uu->time_mid = SVAL(ptr, 4);
uu->time_hi_and_version = SVAL(ptr, 6);
memcpy(uu->clock_seq, ptr+8, 2);
memcpy(uu->node, ptr+10, 6);
}
void uuid_generate_random(GUID *out)
{
GUID tmp;
struct uuid uu;
generate_random_buffer(tmp.info, sizeof(tmp.info), True);
uuid_unpack(tmp, &uu);
uu.clock_seq[0] = (uu.clock_seq[0] & 0x3F) | 0x80;
uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000;
uuid_pack(&uu, out);
}
char *guid_to_string(const GUID in)
{
struct uuid uu;
char *out;
uuid_unpack(in, &uu);
asprintf(&out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
uu.time_low, uu.time_mid, uu.time_hi_and_version,
uu.clock_seq[0], uu.clock_seq[1],
uu.node[0], uu.node[1], uu.node[2],
uu.node[3], uu.node[4], uu.node[5]);
return out;
}
const char *uuid_string(TALLOC_CTX *mem_ctx, const GUID in)
{
struct uuid uu;
char *out;
uuid_unpack(in, &uu);
if (!out) return NULL;
out = talloc_asprintf(mem_ctx,
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
uu.time_low, uu.time_mid, uu.time_hi_and_version,
uu.clock_seq[0], uu.clock_seq[1],
uu.node[0], uu.node[1], uu.node[2],
uu.node[3], uu.node[4], uu.node[5]);
return out;
}

361
source/lib/wins_srv.c Normal file
View File

@@ -0,0 +1,361 @@
/*
Unix SMB/CIFS implementation.
Samba wins server helper functions
Copyright (C) Andrew Tridgell 1992-2002
Copyright (C) Christopher R. Hertel 2000
Copyright (C) Tim Potter 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"
/*
This is pretty much a complete rewrite of the earlier code. The main
aim of the rewrite is to add support for having multiple wins server
lists, so Samba can register with multiple groups of wins servers
and each group has a failover list of wins servers.
Central to the way it all works is the idea of a wins server
'tag'. A wins tag is a label for a group of wins servers. For
example if you use
wins server = fred:192.168.2.10 mary:192.168.3.199 fred:192.168.2.61
then you would have two groups of wins servers, one tagged with the
name 'fred' and the other with the name 'mary'. I would usually
recommend using interface names instead of 'fred' and 'mary' but
they can be any alpha string.
Now, how does it all work. Well, nmbd needs to register each of its
IPs with each of its names once with each group of wins servers. So
it tries registering with the first one mentioned in the list, then
if that fails it marks that WINS server dead and moves onto the next
one.
In the client code things are a bit different. As each of the groups
of wins servers is a separate name space we need to try each of the
groups until we either succeed or we run out of wins servers to
try. If we get a negative response from a wins server then that
means the name doesn't exist in that group, so we give up on that
group and move to the next group. If we don't get a response at all
then maybe the wins server is down, in which case we need to
failover to the next one for that group.
confused yet? (tridge)
*/
/* how long a server is marked dead for */
#define DEATH_TIME 600
/* The list of dead wins servers is stored in gencache.tdb. Each server is
marked dead from the point of view of a given source address. We keep a
separate dead list for each src address to cope with multiple interfaces
that are not routable to each other.
*/
#define WINS_SRV_FMT "WINS_SRV_DEAD/%s,%s" /* wins_ip,src_ip */
static char *wins_srv_keystr(struct in_addr wins_ip, struct in_addr src_ip)
{
char *keystr;
if (asprintf(&keystr, WINS_SRV_FMT, inet_ntoa(wins_ip),
inet_ntoa(src_ip)) == -1) {
DEBUG(0, ("wins_srv_is_dead: malloc error\n"));
return NULL;
}
return keystr;
}
/*
see if an ip is on the dead list
*/
BOOL wins_srv_is_dead(struct in_addr wins_ip, struct in_addr src_ip)
{
char *keystr = wins_srv_keystr(wins_ip, src_ip);
BOOL result;
/* If the key exists then the WINS server has been marked as dead */
result = gencache_get(keystr, NULL, NULL);
SAFE_FREE(keystr);
DEBUG(4, ("wins_srv_is_dead: %s is %s\n", inet_ntoa(wins_ip),
result ? "dead" : "alive"));
return result;
}
/*
mark a wins server as being alive (for the moment)
*/
void wins_srv_alive(struct in_addr wins_ip, struct in_addr src_ip)
{
char *keystr = wins_srv_keystr(wins_ip, src_ip);
gencache_del(keystr);
SAFE_FREE(keystr);
DEBUG(4, ("wins_srv_alive: marking wins server %s alive\n",
inet_ntoa(wins_ip)));
}
/*
mark a wins server as temporarily dead
*/
void wins_srv_died(struct in_addr wins_ip, struct in_addr src_ip)
{
char *keystr;
if (is_zero_ip(wins_ip) || wins_srv_is_dead(wins_ip, src_ip))
return;
keystr = wins_srv_keystr(wins_ip, src_ip);
gencache_set(keystr, "DOWN", time(NULL) + DEATH_TIME);
SAFE_FREE(keystr);
DEBUG(4,("Marking wins server %s dead for %u seconds from source %s\n",
inet_ntoa(wins_ip), DEATH_TIME, inet_ntoa(src_ip)));
}
/*
return the total number of wins servers, dead or not
*/
unsigned wins_srv_count(void)
{
const char **list;
int count = 0;
if (lp_wins_support()) {
/* simple - just talk to ourselves */
return 1;
}
list = lp_wins_server_list();
for (count=0; list && list[count]; count++)
/* nop */ ;
return count;
}
/* an internal convenience structure for an IP with a short string tag
attached */
struct tagged_ip {
fstring tag;
struct in_addr ip;
};
/*
parse an IP string that might be in tagged format
the result is a tagged_ip structure containing the tag
and the ip in in_addr format. If there is no tag then
use the tag '*'
*/
static void parse_ip(TALLOC_CTX *mem_ctx, struct tagged_ip *ip, const char *str)
{
char *s = strchr(str, ':');
if (!s) {
fstrcpy(ip->tag, "*");
ip->ip = *interpret_addr2(mem_ctx, str);
return;
}
ip->ip = *interpret_addr2(mem_ctx, s+1);
fstrcpy(ip->tag, str);
s = strchr(ip->tag, ':');
if (s) *s = 0;
}
/*
return the list of wins server tags. A 'tag' is used to distinguish
wins server as either belonging to the same name space or a separate
name space. Usually you would setup your 'wins server' option to
list one or more wins server per interface and use the interface
name as your tag, but you are free to use any tag you like.
*/
char **wins_srv_tags(void)
{
char **ret = NULL;
int count=0, i, j;
const char **list;
TALLOC_CTX *mem_ctx;
if (lp_wins_support()) {
/* give the caller something to chew on. This makes
the rest of the logic simpler (ie. less special cases) */
ret = (char **)malloc(sizeof(char *)*2);
if (!ret) return NULL;
ret[0] = strdup("*");
ret[1] = NULL;
return ret;
}
list = lp_wins_server_list();
if (!list)
return NULL;
mem_ctx = talloc_init("wins_ssrv_tags");
if (!mem_ctx) {
return NULL;
}
/* yes, this is O(n^2) but n is very small */
for (i=0;list[i];i++) {
struct tagged_ip t_ip;
parse_ip(mem_ctx, &t_ip, list[i]);
/* see if we already have it */
for (j=0;j<count;j++) {
if (strcmp(ret[j], t_ip.tag) == 0) {
break;
}
}
if (j != count) {
/* we already have it. Move along */
continue;
}
/* add it to the list */
ret = (char **)Realloc(ret, (count+2) * sizeof(char *));
ret[count] = strdup(t_ip.tag);
if (!ret[count]) break;
count++;
}
if (count) {
/* make sure we null terminate */
ret[count] = NULL;
}
return ret;
}
/* free a list of wins server tags given by wins_srv_tags */
void wins_srv_tags_free(char **list)
{
int i;
if (!list) return;
for (i=0; list[i]; i++) {
free(list[i]);
}
free(list);
}
/*
return the IP of the currently active wins server for the given tag,
or the zero IP otherwise
*/
struct in_addr wins_srv_ip_tag(const char *tag, struct in_addr src_ip)
{
const char **list;
int i;
struct tagged_ip t_ip;
TALLOC_CTX *mem_ctx;
/* if we are a wins server then we always just talk to ourselves */
if (lp_wins_support()) {
extern struct in_addr loopback_ip;
return loopback_ip;
}
list = lp_wins_server_list();
if (!list || !list[0]) {
struct in_addr ip;
zero_ip(&ip);
return ip;
}
mem_ctx = talloc_init("wins_srv_ip_tag");
/* find the first live one for this tag */
for (i=0; list[i]; i++) {
parse_ip(mem_ctx, &t_ip, list[i]);
if (strcmp(tag, t_ip.tag) != 0) {
/* not for the right tag. Move along */
continue;
}
if (!wins_srv_is_dead(t_ip.ip, src_ip)) {
char *src_name;
src_name = talloc_strdup(mem_ctx, inet_ntoa(src_ip));
DEBUG(6,("Current wins server for tag '%s' with source %s is %s\n",
tag,
src_name,
inet_ntoa(t_ip.ip)));
goto exit;
}
}
/* they're all dead - try the first one until they revive */
for (i=0; list[i]; i++) {
parse_ip(mem_ctx, &t_ip, list[i]);
if (strcmp(tag, t_ip.tag) != 0) {
continue;
}
goto exit;
}
/* this can't happen?? */
zero_ip(&t_ip.ip);
exit:
talloc_destroy(mem_ctx);
return t_ip.ip;
}
/*
return a count of the number of IPs for a particular tag, including
dead ones
*/
unsigned wins_srv_count_tag(const char *tag)
{
const char **list;
int i, count=0;
TALLOC_CTX *mem_ctx;
/* if we are a wins server then we always just talk to ourselves */
if (lp_wins_support()) {
return 1;
}
list = lp_wins_server_list();
if (!list || !list[0]) {
return 0;
}
/* find the first live one for this tag */
mem_ctx = talloc_init("wins_srv_count_tag");
if (!mem_ctx) {
return 0;
}
for (i=0; list[i]; i++) {
struct tagged_ip t_ip;
parse_ip(mem_ctx, &t_ip, list[i]);
if (strcmp(tag, t_ip.tag) == 0) {
count++;
}
}
talloc_destroy(mem_ctx);
return count;
}

378
source/lib/xfile.c Normal file
View File

@@ -0,0 +1,378 @@
/*
Unix SMB/CIFS implementation.
stdio replacement
Copyright (C) Andrew Tridgell 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
stdio is very convenient, but on some systems the file descriptor
in FILE* is 8 bits, so it fails when more than 255 files are open.
XFILE replaces stdio. It is less efficient, but at least it works
when you have lots of files open
The main restriction on XFILE is that it doesn't support seeking,
and doesn't support O_RDWR. That keeps the code simple.
*/
#include "includes.h"
#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 = (XFILE *)malloc(sizeof(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 = sys_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);
}
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 = *(unsigned char *)(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 (off_t)sys_lseek(f->fd, offset, whence);
}