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:
3
source/lib/.cvsignore
Normal file
3
source/lib/.cvsignore
Normal file
@@ -0,0 +1,3 @@
|
||||
*.po
|
||||
*.po32
|
||||
|
||||
169
source/lib/account_pol.c
Normal file
169
source/lib/account_pol.c
Normal 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
464
source/lib/adt_tree.c
Normal 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
163
source/lib/bitmap.c
Normal 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
925
source/lib/charcnv.c
Normal 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;
|
||||
}
|
||||
327
source/lib/cmdline/popt_common.c
Normal file
327
source/lib/cmdline/popt_common.c
Normal 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/cmdline/readline.c
Normal file
159
source/lib/cmdline/readline.c
Normal 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
71
source/lib/crc32.c
Normal 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
71
source/lib/crypto/crc32.c
Normal 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
134
source/lib/crypto/hmacmd5.c
Normal 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
175
source/lib/crypto/md4.c
Normal 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
247
source/lib/crypto/md5.c
Normal 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
141
source/lib/data_blob.c
Normal 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
157
source/lib/debug.c
Normal 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
72
source/lib/dmallocmsg.c
Normal 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
113
source/lib/dprintf.c
Normal 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
372
source/lib/events.c
Normal 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
107
source/lib/fault.c
Normal 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
148
source/lib/fsusage.c
Normal 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
372
source/lib/gencache.c
Normal 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
786
source/lib/genparser.c
Normal 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));
|
||||
}
|
||||
200
source/lib/genparser_samba.c
Normal file
200
source/lib/genparser_samba.c
Normal 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
267
source/lib/genrand.c
Normal 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
156
source/lib/getsmbpass.c
Normal 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
134
source/lib/hmacmd5.c
Normal 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
526
source/lib/iconv.c
Normal 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
333
source/lib/interface.c
Normal 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
407
source/lib/interfaces.c
Normal 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
90
source/lib/ldap_escape.c
Normal 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
175
source/lib/md4.c
Normal 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
247
source/lib/md5.c
Normal 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
566
source/lib/messages.c
Normal 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
128
source/lib/module.c
Normal 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
226
source/lib/ms_fnmatch.c
Normal 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
142
source/lib/mutex.c
Normal 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
126
source/lib/pam_errors.c
Normal 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
109
source/lib/pidfile.c
Normal 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
43
source/lib/popt/CHANGES
Normal 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
22
source/lib/popt/COPYING
Normal 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
18
source/lib/popt/README
Normal 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
0
source/lib/popt/dummy.in
Normal file
46
source/lib/popt/findme.c
Normal file
46
source/lib/popt/findme.c
Normal 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
10
source/lib/popt/findme.h
Normal 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
782
source/lib/popt/popt.c
Normal 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
130
source/lib/popt/popt.h
Normal 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
|
||||
142
source/lib/popt/poptconfig.c
Normal file
142
source/lib/popt/poptconfig.c
Normal 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
301
source/lib/popt/popthelp.c
Normal 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
71
source/lib/popt/poptint.h
Normal 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
102
source/lib/popt/poptparse.c
Normal 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
53
source/lib/popt/system.h
Normal 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
327
source/lib/popt_common.c
Normal 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
159
source/lib/readline.c
Normal 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
467
source/lib/replace.c
Normal 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
159
source/lib/select.c
Normal 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
382
source/lib/sendfile.c
Normal 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
58
source/lib/server_mutex.c
Normal 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
139
source/lib/signal.c
Normal 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
200
source/lib/smbpasswd.c
Normal 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
171
source/lib/smbrun.c
Normal 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
978
source/lib/snprintf.c
Normal 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
188
source/lib/substitute.c
Normal 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
3198
source/lib/sysacls.c
Normal file
File diff suppressed because it is too large
Load Diff
1114
source/lib/system.c
Normal file
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
119
source/lib/system_smbd.c
Normal 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
515
source/lib/talloc.c
Normal 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
58
source/lib/tallocmsg.c
Normal 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
65
source/lib/talloctort.c
Normal 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
167
source/lib/tdb/README
Normal 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
430
source/lib/tdb/spinlock.c
Normal 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
55
source/lib/tdb/spinlock.h
Normal 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
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
144
source/lib/tdb/tdb.h
Normal 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
10
source/lib/tdb/tdb.magic
Normal 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
687
source/lib/tdb/tdbutil.c
Normal 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
37
source/lib/tdb/tdbutil.h
Normal 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
754
source/lib/time.c
Normal 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
537
source/lib/username.c
Normal 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
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
531
source/lib/util_file.c
Normal 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
306
source/lib/util_getent.c
Normal 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
89
source/lib/util_pw.c
Normal 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
486
source/lib/util_seaccess.c
Normal 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
631
source/lib/util_sid.c
Normal 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
65
source/lib/util_smbd.c
Normal 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
631
source/lib/util_sock.c
Normal 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
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
838
source/lib/util_unistr.c
Normal 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
104
source/lib/util_uuid.c
Normal 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
361
source/lib/wins_srv.c
Normal 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
378
source/lib/xfile.c
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user