summaryrefslogtreecommitdiffstats
path: root/source/lib
diff options
context:
space:
mode:
authorCVS Import User <samba-bugs@samba.org>2004-04-04 11:51:10 +0000
committerCVS Import User <samba-bugs@samba.org>2004-04-04 11:51:10 +0000
commite3d2dbdff6711b0bc768fb6b08f41240f21d5fba (patch)
tree159ef54b59b18e9b950f5c6af105915214244912 /source/lib
parent139b1658ca30692835c1a7203c7cd003e587ac12 (diff)
downloadsamba-e3d2dbdff6711b0bc768fb6b08f41240f21d5fba.tar.gz
samba-e3d2dbdff6711b0bc768fb6b08f41240f21d5fba.tar.xz
samba-e3d2dbdff6711b0bc768fb6b08f41240f21d5fba.zip
r6: merge in the samba4 HEAD branch from cvs
to checkout try: svn co svn+ssh://svn.samba.org/home/svn/samba/branches/SAMBA_4_0 metze
Diffstat (limited to 'source/lib')
-rw-r--r--source/lib/access.c333
-rw-r--r--source/lib/account_pol.c25
-rw-r--r--source/lib/adt_tree.c6
-rw-r--r--source/lib/afs.c486
-rw-r--r--source/lib/basic.m426
-rw-r--r--source/lib/bitmap.c14
-rw-r--r--source/lib/charcnv.c989
-rw-r--r--source/lib/clobber.c60
-rw-r--r--source/lib/cmdline/config.m479
-rw-r--r--source/lib/cmdline/popt_common.c (renamed from source/lib/popt_common.c)108
-rw-r--r--source/lib/cmdline/readline.c (renamed from source/lib/readline.c)10
-rw-r--r--source/lib/crypto/crc32.c (renamed from source/lib/crc32.c)0
-rw-r--r--source/lib/crypto/hmacmd5.c (renamed from source/lib/hmacmd5.c)2
-rw-r--r--source/lib/crypto/md4.c (renamed from source/lib/md4.c)102
-rw-r--r--source/lib/crypto/md5.c (renamed from source/lib/md5.c)0
-rw-r--r--source/lib/data_blob.c57
-rw-r--r--source/lib/debug.c1023
-rw-r--r--source/lib/dprintf.c2
-rw-r--r--source/lib/dummysmbd.c29
-rw-r--r--source/lib/events.c394
-rw-r--r--source/lib/fault.c48
-rw-r--r--source/lib/gencache.c15
-rw-r--r--source/lib/genparser.c30
-rw-r--r--source/lib/genparser_samba.c32
-rw-r--r--source/lib/genrand.c2
-rw-r--r--source/lib/getsmbpass.c149
-rw-r--r--source/lib/hash.c316
-rw-r--r--source/lib/iconv.c215
-rw-r--r--source/lib/iconv.m466
-rw-r--r--source/lib/interface.c45
-rw-r--r--source/lib/ldb/Makefile.ldb56
-rw-r--r--source/lib/ldb/common/ldb.c129
-rw-r--r--source/lib/ldb/common/ldb_ldif.c623
-rw-r--r--source/lib/ldb/common/ldb_parse.c460
-rw-r--r--source/lib/ldb/common/util.c102
-rw-r--r--source/lib/ldb/docs/design.txt41
-rw-r--r--source/lib/ldb/include/includes.h22
-rw-r--r--source/lib/ldb/include/ldb.h219
-rw-r--r--source/lib/ldb/include/ldb_parse.h53
-rw-r--r--source/lib/ldb/include/proto.h126
-rw-r--r--source/lib/ldb/ldb_ldap/ldb_ldap.c520
-rw-r--r--source/lib/ldb/ldb_ldap/ldb_ldap.h8
-rw-r--r--source/lib/ldb/ldb_tdb/.cvsignore7
-rw-r--r--source/lib/ldb/ldb_tdb/ldb_index.c725
-rw-r--r--source/lib/ldb/ldb_tdb/ldb_match.c182
-rw-r--r--source/lib/ldb/ldb_tdb/ldb_pack.c218
-rw-r--r--source/lib/ldb/ldb_tdb/ldb_search.c508
-rw-r--r--source/lib/ldb/ldb_tdb/ldb_tdb.c542
-rw-r--r--source/lib/ldb/ldb_tdb/ldb_tdb.h11
-rw-r--r--source/lib/ldb/tests/init.ldif15
-rw-r--r--source/lib/ldb/tests/init_slapd.sh11
-rw-r--r--source/lib/ldb/tests/ldapi_url.sh11
-rw-r--r--source/lib/ldb/tests/slapd.conf25
-rw-r--r--source/lib/ldb/tests/start_slapd.sh8
-rw-r--r--source/lib/ldb/tests/test-generic.sh8
-rw-r--r--source/lib/ldb/tests/test-index.ldif4
-rw-r--r--source/lib/ldb/tests/test-ldap.sh8
-rw-r--r--source/lib/ldb/tests/test-modify.ldif14
-rw-r--r--source/lib/ldb/tests/test-tdb.sh8
-rw-r--r--source/lib/ldb/tests/test.ldif416
-rw-r--r--source/lib/ldb/tests/testdata.txt8
-rw-r--r--source/lib/ldb/tests/testsearch.txt5
-rw-r--r--source/lib/ldb/tools/ldbadd.c81
-rw-r--r--source/lib/ldb/tools/ldbdel.c69
-rw-r--r--source/lib/ldb/tools/ldbmodify.c85
-rw-r--r--source/lib/ldb/tools/ldbsearch.c127
-rw-r--r--source/lib/messages.c56
-rw-r--r--source/lib/module.c244
-rw-r--r--source/lib/ms_fnmatch.c81
-rw-r--r--source/lib/mutex.c142
-rw-r--r--source/lib/pidfile.c2
-rw-r--r--source/lib/popt/CHANGES43
-rw-r--r--source/lib/popt/COPYING22
-rw-r--r--source/lib/popt/README18
-rw-r--r--source/lib/popt/config.m440
-rw-r--r--source/lib/popt/findme.c47
-rw-r--r--source/lib/popt/findme.h10
-rw-r--r--source/lib/popt/popt.c798
-rw-r--r--source/lib/popt/popt.h130
-rw-r--r--source/lib/popt/poptconfig.c144
-rw-r--r--source/lib/popt/popthelp.c312
-rw-r--r--source/lib/popt/poptint.h71
-rw-r--r--source/lib/popt/poptparse.c102
-rw-r--r--source/lib/popt/system.h53
-rw-r--r--source/lib/privileges.c442
-rw-r--r--source/lib/replace.c29
-rw-r--r--source/lib/replace1.c42
-rw-r--r--source/lib/secace.c285
-rw-r--r--source/lib/secacl.c118
-rw-r--r--source/lib/secdesc.c522
-rw-r--r--source/lib/select.c4
-rw-r--r--source/lib/sendfile.c2
-rw-r--r--source/lib/server_mutex.c6
-rw-r--r--source/lib/smbldap.c1234
-rw-r--r--source/lib/smbldap_util.c203
-rw-r--r--source/lib/smbpasswd.c200
-rw-r--r--source/lib/smbrun.c22
-rw-r--r--source/lib/snprintf.c136
-rw-r--r--source/lib/sock_exec.c115
-rw-r--r--source/lib/substitute.c730
-rw-r--r--source/lib/sysacls.c8
-rw-r--r--source/lib/sysquotas.c505
-rw-r--r--source/lib/sysquotas_4A.c339
-rw-r--r--source/lib/sysquotas_linux.c560
-rw-r--r--source/lib/sysquotas_xfs.c333
-rw-r--r--source/lib/system.c647
-rw-r--r--source/lib/system_smbd.c137
-rw-r--r--source/lib/talloc.c208
-rw-r--r--source/lib/talloctort.c8
-rw-r--r--source/lib/tdb/README167
-rw-r--r--source/lib/tdb/spinlock.c481
-rw-r--r--source/lib/tdb/spinlock.h59
-rw-r--r--source/lib/tdb/tdb.c2090
-rw-r--r--source/lib/tdb/tdb.h151
-rw-r--r--source/lib/tdb/tdb.magic10
-rw-r--r--source/lib/tdb/tdbutil.c764
-rw-r--r--source/lib/tdb/tdbutil.h (renamed from source/lib/dummyroot.c)30
-rw-r--r--source/lib/time.c192
-rw-r--r--source/lib/ufc.c771
-rw-r--r--source/lib/username.c275
-rw-r--r--source/lib/util.c1833
-rw-r--r--source/lib/util_file.c79
-rw-r--r--source/lib/util_getent.c6
-rw-r--r--source/lib/util_seaccess.c135
-rw-r--r--source/lib/util_sec.c467
-rw-r--r--source/lib/util_sid.c40
-rw-r--r--source/lib/util_smbd.c65
-rw-r--r--source/lib/util_sock.c852
-rw-r--r--source/lib/util_str.c900
-rw-r--r--source/lib/util_unistr.c566
-rw-r--r--source/lib/util_uuid.c168
-rw-r--r--source/lib/wins_srv.c57
132 files changed, 14051 insertions, 15375 deletions
diff --git a/source/lib/access.c b/source/lib/access.c
deleted file mode 100644
index f03f5daf333..00000000000
--- a/source/lib/access.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- This module is an adaption of code from the tcpd-1.4 package written
- by Wietse Venema, Eindhoven University of Technology, The Netherlands.
-
- The code is used here with permission.
-
- The code has been considerably changed from the original. Bug reports
- should be sent to samba@samba.org
-*/
-
-#include "includes.h"
-
-#define FAIL (-1)
-
-#define ALLONES ((uint32)0xFFFFFFFF)
-
-/* masked_match - match address against netnumber/netmask */
-static BOOL masked_match(const char *tok, const char *slash, const char *s)
-{
- uint32 net;
- uint32 mask;
- uint32 addr;
- fstring tok_cpy;
-
- if ((addr = interpret_addr(s)) == INADDR_NONE)
- return (False);
-
- fstrcpy(tok_cpy, tok);
- tok_cpy[PTR_DIFF(slash,tok)] = '\0';
- net = interpret_addr(tok_cpy);
- tok_cpy[PTR_DIFF(slash,tok)] = '/';
-
- if (strlen(slash + 1) > 2) {
- mask = interpret_addr(slash + 1);
- } else {
- mask = (uint32)((ALLONES >> atoi(slash + 1)) ^ ALLONES);
- /* convert to network byte order */
- mask = htonl(mask);
- }
-
- if (net == INADDR_NONE || mask == INADDR_NONE) {
- DEBUG(0,("access: bad net/mask access control: %s\n", tok));
- return (False);
- }
-
- return ((addr & mask) == (net & mask));
-}
-
-/* string_match - match string against token */
-static BOOL string_match(const char *tok,const char *s, char *invalid_char)
-{
- size_t tok_len;
- size_t str_len;
- const char *cut;
-
- *invalid_char = '\0';
-
- /* Return True if a token has the magic value "ALL". Return
- * FAIL if the token is "FAIL". If the token starts with a "."
- * (domain name), return True if it matches the last fields of
- * the string. If the token has the magic value "LOCAL",
- * return True if the string does not contain a "."
- * character. If the token ends on a "." (network number),
- * return True if it matches the first fields of the
- * string. If the token begins with a "@" (netgroup name),
- * return True if the string is a (host) member of the
- * netgroup. Return True if the token fully matches the
- * string. If the token is a netnumber/netmask pair, return
- * True if the address is a member of the specified subnet.
- */
-
- if (tok[0] == '.') { /* domain: match last fields */
- if ((str_len = strlen(s)) > (tok_len = strlen(tok))
- && strequal(tok, s + str_len - tok_len))
- return (True);
- } else if (tok[0] == '@') { /* netgroup: look it up */
-#ifdef HAVE_NETGROUP
- static char *mydomain = NULL;
- char *hostname = NULL;
- BOOL netgroup_ok = False;
-
- if (!mydomain)
- yp_get_default_domain(&mydomain);
-
- if (!mydomain) {
- DEBUG(0,("Unable to get default yp domain.\n"));
- return False;
- }
- if (!(hostname = strdup(s))) {
- DEBUG(1,("out of memory for strdup!\n"));
- return False;
- }
-
- netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain);
-
- DEBUG(5,("looking for %s of domain %s in netgroup %s gave %s\n",
- hostname,
- mydomain,
- tok+1,
- BOOLSTR(netgroup_ok)));
-
- SAFE_FREE(hostname);
-
- if (netgroup_ok)
- return(True);
-#else
- DEBUG(0,("access: netgroup support is not configured\n"));
- return (False);
-#endif
- } else if (strequal(tok, "ALL")) { /* all: match any */
- return (True);
- } else if (strequal(tok, "FAIL")) { /* fail: match any */
- return (FAIL);
- } else if (strequal(tok, "LOCAL")) { /* local: no dots */
- if (strchr_m(s, '.') == 0 && !strequal(s, "unknown"))
- return (True);
- } else if (strequal(tok, s)) { /* match host name or address */
- return (True);
- } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { /* network */
- if (strncmp(tok, s, tok_len) == 0)
- return (True);
- } else if ((cut = strchr_m(tok, '/')) != 0) { /* netnumber/netmask */
- if (isdigit((int)s[0]) && masked_match(tok, cut, s))
- return (True);
- } else if (strchr_m(tok, '*') != 0) {
- *invalid_char = '*';
- } else if (strchr_m(tok, '?') != 0) {
- *invalid_char = '?';
- }
- return (False);
-}
-
-/* client_match - match host name and address against token */
-static BOOL client_match(const char *tok, const char *item)
-{
- const char **client = (const char **)item;
- BOOL match;
- char invalid_char = '\0';
-
- /*
- * Try to match the address first. If that fails, try to match the host
- * name if available.
- */
-
- if ((match = string_match(tok, client[1], &invalid_char)) == 0) {
- if(invalid_char)
- DEBUG(0,("client_match: address match failing due to invalid character '%c' found in \
-token '%s' in an allow/deny hosts line.\n", invalid_char, tok ));
-
- if (client[0][0] != 0)
- match = string_match(tok, client[0], &invalid_char);
-
- if(invalid_char)
- DEBUG(0,("client_match: address match failing due to invalid character '%c' found in \
-token '%s' in an allow/deny hosts line.\n", invalid_char, tok ));
- }
-
- return (match);
-}
-
-/* list_match - match an item against a list of tokens with exceptions */
-static BOOL list_match(const char **list,const char *item,
- BOOL (*match_fn)(const char *, const char *))
-{
- BOOL match = False;
-
- if (!list)
- return False;
-
- /*
- * Process tokens one at a time. We have exhausted all possible matches
- * when we reach an "EXCEPT" token or the end of the list. If we do find
- * a match, look for an "EXCEPT" list and recurse to determine whether
- * the match is affected by any exceptions.
- */
-
- for (; *list ; list++) {
- if (strequal(*list, "EXCEPT")) /* EXCEPT: give up */
- break;
- if ((match = (*match_fn) (*list, item))) /* True or FAIL */
- break;
- }
- /* Process exceptions to True or FAIL matches. */
-
- if (match != False) {
- while (*list && !strequal(*list, "EXCEPT"))
- list++;
-
- for (; *list; list++) {
- if ((*match_fn) (*list, item)) /* Exception Found */
- return False;
- }
- }
-
- return (match);
-}
-
-/* return true if access should be allowed */
-static BOOL allow_access_internal(const char **deny_list,const char **allow_list,
- const char *cname, const char *caddr)
-{
- const char *client[2];
-
- client[0] = cname;
- client[1] = caddr;
-
- /* if it is loopback then always allow unless specifically denied */
- if (strcmp(caddr, "127.0.0.1") == 0) {
- /*
- * If 127.0.0.1 matches both allow and deny then allow.
- * Patch from Steve Langasek vorlon@netexpress.net.
- */
- if (deny_list &&
- list_match(deny_list,(const char *)client,client_match) &&
- (!allow_list ||
- !list_match(allow_list,(const char *)client, client_match))) {
- return False;
- }
- return True;
- }
-
- /* if theres no deny list and no allow list then allow access */
- if ((!deny_list || *deny_list == 0) &&
- (!allow_list || *allow_list == 0)) {
- return(True);
- }
-
- /* if there is an allow list but no deny list then allow only hosts
- on the allow list */
- if (!deny_list || *deny_list == 0)
- return(list_match(allow_list,(const char *)client,client_match));
-
- /* if theres a deny list but no allow list then allow
- all hosts not on the deny list */
- if (!allow_list || *allow_list == 0)
- return(!list_match(deny_list,(const char *)client,client_match));
-
- /* if there are both types of list then allow all hosts on the
- allow list */
- if (list_match(allow_list,(const char *)client,client_match))
- return (True);
-
- /* if there are both types of list and it's not on the allow then
- allow it if its not on the deny */
- if (list_match(deny_list,(const char *)client,client_match))
- return (False);
-
- return (True);
-}
-
-/* return true if access should be allowed */
-BOOL allow_access(const char **deny_list, const char **allow_list,
- const char *cname, const char *caddr)
-{
- BOOL ret;
- char *nc_cname = smb_xstrdup(cname);
- char *nc_caddr = smb_xstrdup(caddr);
-
- ret = allow_access_internal(deny_list, allow_list, nc_cname, nc_caddr);
-
- SAFE_FREE(nc_cname);
- SAFE_FREE(nc_caddr);
- return ret;
-}
-
-/* return true if the char* contains ip addrs only. Used to avoid
-gethostbyaddr() calls */
-
-static BOOL only_ipaddrs_in_list(const char** list)
-{
- BOOL only_ip = True;
-
- if (!list)
- return True;
-
- for (; *list ; list++) {
- /* factor out the special strings */
- if (strequal(*list, "ALL") || strequal(*list, "FAIL") ||
- strequal(*list, "EXCEPT")) {
- continue;
- }
-
- if (!is_ipaddress(*list)) {
- /*
- * if we failed, make sure that it was not because the token
- * was a network/netmask pair. Only network/netmask pairs
- * have a '/' in them
- */
- if ((strchr_m(*list, '/')) == NULL) {
- only_ip = False;
- DEBUG(3,("only_ipaddrs_in_list: list has non-ip address (%s)\n", *list));
- break;
- }
- }
- }
-
- return only_ip;
-}
-
-/* return true if access should be allowed to a service for a socket */
-BOOL check_access(int sock, const char **allow_list, const char **deny_list)
-{
- BOOL ret = False;
- BOOL only_ip = False;
-
- if ((!deny_list || *deny_list==0) && (!allow_list || *allow_list==0))
- ret = True;
-
- if (!ret) {
- /* bypass gethostbyaddr() calls if the lists only contain IP addrs */
- if (only_ipaddrs_in_list(allow_list) && only_ipaddrs_in_list(deny_list)) {
- only_ip = True;
- DEBUG (3, ("check_access: no hostnames in host allow/deny list.\n"));
- ret = allow_access(deny_list,allow_list, "", get_peer_addr(sock));
- } else {
- DEBUG (3, ("check_access: hostnames in host allow/deny list.\n"));
- ret = allow_access(deny_list,allow_list, get_peer_name(sock,True),
- get_peer_addr(sock));
- }
-
- if (ret) {
- DEBUG(2,("Allowed connection from %s (%s)\n",
- only_ip ? "" : get_peer_name(sock,True),
- get_peer_addr(sock)));
- } else {
- DEBUG(0,("Denied connection from %s (%s)\n",
- only_ip ? "" : get_peer_name(sock,True),
- get_peer_addr(sock)));
- }
- }
-
- return(ret);
-}
diff --git a/source/lib/account_pol.c b/source/lib/account_pol.c
index c2c63493a6f..df1479da3a2 100644
--- a/source/lib/account_pol.c
+++ b/source/lib/account_pol.c
@@ -1,7 +1,7 @@
/*
* Unix SMB/CIFS implementation.
* account policy storage
- * Copyright (C) Jean François Micouleau 1998-2001.
+ * Copyright (C) Jean Fran�ois Micouleau 1998-2001.
* Copyright (C) Andrew Bartlett 2002
*
* This program is free software; you can redistribute it and/or modify
@@ -33,16 +33,23 @@ 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 == sys_getpid())
+ if (tdb && local_pid == getpid())
return True;
- tdb = tdb_open_log(lock_path("account_policy.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ 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 = sys_getpid();
+ local_pid = getpid();
/* handle a Samba upgrade */
tdb_lock_bystring(tdb, vstring,0);
@@ -53,10 +60,10 @@ BOOL init_account_policy(void)
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, (uint32)-1); /* don't expire */
+ 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, 30); /* lockout for 30 minutes */
- account_policy_set(AP_RESET_COUNT_TIME, 30); /* reset after 30 minutes */
+ 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 */
}
@@ -118,7 +125,7 @@ BOOL account_policy_get(int field, uint32 *value)
{
fstring name;
- if(!init_account_policy())return False;
+ init_account_policy();
*value = 0;
@@ -142,7 +149,7 @@ BOOL account_policy_set(int field, uint32 value)
{
fstring name;
- if(!init_account_policy())return False;
+ init_account_policy();
fstrcpy(name, decode_account_policy_name(field));
if (!*name) {
diff --git a/source/lib/adt_tree.c b/source/lib/adt_tree.c
index bd857e205ac..0bc224ec232 100644
--- a/source/lib/adt_tree.c
+++ b/source/lib/adt_tree.c
@@ -65,7 +65,7 @@ SORTED_TREE* sorted_tree_init( void *data_p,
ZERO_STRUCTP( tree );
tree->compare = cmp_fn;
- tree->free_func = free_fn;
+ tree->free = free_fn;
if ( !(tree->root = (TREE_NODE*)malloc( sizeof(TREE_NODE) )) ) {
SAFE_FREE( tree );
@@ -110,8 +110,8 @@ void sorted_tree_destroy( SORTED_TREE *tree )
if ( tree->root )
sorted_tree_destroy_children( tree->root );
- if ( tree->free_func )
- tree->free_func( tree->root );
+ if ( tree->free )
+ tree->free( tree->root );
SAFE_FREE( tree );
}
diff --git a/source/lib/afs.c b/source/lib/afs.c
deleted file mode 100644
index ce972ec27b7..00000000000
--- a/source/lib/afs.c
+++ /dev/null
@@ -1,486 +0,0 @@
-/*
- * Unix SMB/CIFS implementation.
- * Generate AFS tickets
- * Copyright (C) Volker Lendecke 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"
-
-#ifdef WITH_FAKE_KASERVER
-
-#include <afs/stds.h>
-#include <afs/afs.h>
-#include <afs/auth.h>
-#include <afs/venus.h>
-#include <asm/unistd.h>
-#include <openssl/des.h>
-
-_syscall5(int, afs_syscall, int, subcall,
- char *, path,
- int, cmd,
- char *, cmarg,
- int, follow);
-
-struct ClearToken {
- uint32 AuthHandle;
- char HandShakeKey[8];
- uint32 ViceId;
- uint32 BeginTimestamp;
- uint32 EndTimestamp;
-};
-
-static char *afs_encode_token(const char *cell, const DATA_BLOB ticket,
- const struct ClearToken *ct)
-{
- char *base64_ticket;
- char *result;
-
- DATA_BLOB key = data_blob(ct->HandShakeKey, 8);
- char *base64_key;
-
- base64_ticket = base64_encode_data_blob(ticket);
- if (base64_ticket == NULL)
- return NULL;
-
- base64_key = base64_encode_data_blob(key);
- if (base64_key == NULL) {
- free(base64_ticket);
- return NULL;
- }
-
- asprintf(&result, "%s\n%u\n%s\n%u\n%u\n%u\n%s\n", cell,
- ct->AuthHandle, base64_key, ct->ViceId, ct->BeginTimestamp,
- ct->EndTimestamp, base64_ticket);
-
- DEBUG(10, ("Got ticket string:\n%s\n", result));
-
- free(base64_ticket);
- free(base64_key);
-
- return result;
-}
-
-static BOOL afs_decode_token(const char *string, char **cell,
- DATA_BLOB *ticket, struct ClearToken *ct)
-{
- DATA_BLOB blob;
- struct ClearToken result_ct;
-
- char *s = strdup(string);
-
- char *t;
-
- if ((t = strtok(s, "\n")) == NULL) {
- DEBUG(10, ("strtok failed\n"));
- return False;
- }
-
- *cell = strdup(t);
-
- if ((t = strtok(NULL, "\n")) == NULL) {
- DEBUG(10, ("strtok failed\n"));
- return False;
- }
-
- if (sscanf(t, "%u", &result_ct.AuthHandle) != 1) {
- DEBUG(10, ("sscanf AuthHandle failed\n"));
- return False;
- }
-
- if ((t = strtok(NULL, "\n")) == NULL) {
- DEBUG(10, ("strtok failed\n"));
- return False;
- }
-
- blob = base64_decode_data_blob(t);
-
- if ( (blob.data == NULL) ||
- (blob.length != sizeof(result_ct.HandShakeKey) )) {
- DEBUG(10, ("invalid key: %x/%d\n", (uint32)blob.data,
- blob.length));
- return False;
- }
-
- memcpy(result_ct.HandShakeKey, blob.data, blob.length);
-
- data_blob_free(&blob);
-
- if ((t = strtok(NULL, "\n")) == NULL) {
- DEBUG(10, ("strtok failed\n"));
- return False;
- }
-
- if (sscanf(t, "%u", &result_ct.ViceId) != 1) {
- DEBUG(10, ("sscanf ViceId failed\n"));
- return False;
- }
-
- if ((t = strtok(NULL, "\n")) == NULL) {
- DEBUG(10, ("strtok failed\n"));
- return False;
- }
-
- if (sscanf(t, "%u", &result_ct.BeginTimestamp) != 1) {
- DEBUG(10, ("sscanf BeginTimestamp failed\n"));
- return False;
- }
-
- if ((t = strtok(NULL, "\n")) == NULL) {
- DEBUG(10, ("strtok failed\n"));
- return False;
- }
-
- if (sscanf(t, "%u", &result_ct.EndTimestamp) != 1) {
- DEBUG(10, ("sscanf EndTimestamp failed\n"));
- return False;
- }
-
- if ((t = strtok(NULL, "\n")) == NULL) {
- DEBUG(10, ("strtok failed\n"));
- return False;
- }
-
- blob = base64_decode_data_blob(t);
-
- if (blob.data == NULL) {
- DEBUG(10, ("Could not get ticket\n"));
- return False;
- }
-
- *ticket = blob;
- *ct = result_ct;
-
- return True;
-}
-
-/*
- Put an AFS token into the Kernel so that it can authenticate against
- the AFS server. This assumes correct local uid settings.
-
- This is currently highly Linux and OpenAFS-specific. The correct API
- call for this would be ktc_SetToken. But to do that we would have to
- import a REALLY big bunch of libraries which I would currently like
- to avoid.
-*/
-
-static BOOL afs_settoken(const char *cell,
- const struct ClearToken *ctok,
- DATA_BLOB ticket)
-{
- int ret;
- struct {
- char *in, *out;
- uint16 in_size, out_size;
- } iob;
-
- char buf[1024];
- char *p = buf;
- int tmp;
-
- memcpy(p, &ticket.length, sizeof(uint32));
- p += sizeof(uint32);
- memcpy(p, ticket.data, ticket.length);
- p += ticket.length;
-
- tmp = sizeof(struct ClearToken);
- memcpy(p, &tmp, sizeof(uint32));
- p += sizeof(uint32);
- memcpy(p, ctok, tmp);
- p += tmp;
-
- tmp = 0;
-
- memcpy(p, &tmp, sizeof(uint32));
- p += sizeof(uint32);
-
- tmp = strlen(cell);
- if (tmp >= MAXKTCREALMLEN) {
- DEBUG(1, ("Realm too long\n"));
- return False;
- }
-
- strncpy(p, cell, tmp);
- p += tmp;
- *p = 0;
- p +=1;
-
- iob.in = buf;
- iob.in_size = PTR_DIFF(p,buf);
- iob.out = buf;
- iob.out_size = sizeof(buf);
-
-#if 0
- file_save("/tmp/ioctlbuf", iob.in, iob.in_size);
-#endif
-
- ret = afs_syscall(AFSCALL_PIOCTL, 0, VIOCSETTOK, (char *)&iob, 0);
-
- DEBUG(10, ("afs VIOCSETTOK returned %d\n", ret));
- return (ret == 0);
-}
-
-BOOL afs_settoken_str(const char *token_string)
-{
- DATA_BLOB ticket;
- struct ClearToken ct;
- BOOL result;
- char *cell;
-
- if (!afs_decode_token(token_string, &cell, &ticket, &ct))
- return False;
-
- if (geteuid() != 0)
- ct.ViceId = getuid();
-
- result = afs_settoken(cell, &ct, ticket);
-
- SAFE_FREE(cell);
- data_blob_free(&ticket);
-
- return result;
- }
-
-/* Create a ClearToken and an encrypted ticket. ClearToken has not yet the
- * ViceId set, this should be set by the caller. */
-
-static BOOL afs_createtoken(const char *username, const char *cell,
- DATA_BLOB *ticket, struct ClearToken *ct)
-{
- fstring clear_ticket;
- char *p = clear_ticket;
- uint32 len;
- uint32 now;
-
- struct afs_key key;
- des_key_schedule key_schedule;
-
- if (!secrets_init())
- return False;
-
- if (!secrets_fetch_afs_key(cell, &key)) {
- DEBUG(1, ("Could not fetch AFS service key\n"));
- return False;
- }
-
- ct->AuthHandle = key.kvno;
-
- /* Build the ticket. This is going to be encrypted, so in our
- way we fill in ct while we still have the unencrypted
- form. */
-
- p = clear_ticket;
-
- /* The byte-order */
- *p = 1;
- p += 1;
-
- /* "Alice", the client username */
- strncpy(p, username, sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
- p += strlen(p)+1;
- strncpy(p, "", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
- p += strlen(p)+1;
- strncpy(p, cell, sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
- p += strlen(p)+1;
-
- /* Alice's network layer address. At least Openafs-1.2.10
- ignores this, so we fill in a dummy value here. */
- SIVAL(p, 0, 0);
- p += 4;
-
- /* We need to create a session key */
- generate_random_buffer(p, 8, False);
-
- /* Our client code needs the the key in the clear, it does not
- know the server-key ... */
- memcpy(ct->HandShakeKey, p, 8);
-
- p += 8;
-
- /* Ticket lifetime. We fake everything here, so go as long as
- possible. This is in 5-minute intervals, so 255 is 21 hours
- and 15 minutes.*/
- *p = 255;
- p += 1;
-
- /* Ticket creation time */
- now = time(NULL);
- SIVAL(p, 0, now);
- ct->BeginTimestamp = now;
-
- ct->EndTimestamp = now + (255*60*5);
- if (((ct->EndTimestamp - ct->BeginTimestamp) & 1) == 1) {
- ct->BeginTimestamp += 1; /* Lifetime must be even */
- }
- p += 4;
-
- /* And here comes Bob's name and instance, in this case the
- AFS server. */
- strncpy(p, "afs", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
- p += strlen(p)+1;
- strncpy(p, "", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
- p += strlen(p)+1;
-
- /* And zero-pad to a multiple of 8 bytes */
- len = PTR_DIFF(p, clear_ticket);
- if (len & 7) {
- uint32 extra_space = 8-(len & 7);
- memset(p, 0, extra_space);
- p+=extra_space;
- }
- len = PTR_DIFF(p, clear_ticket);
-
- des_key_sched((const_des_cblock *)key.key, key_schedule);
- des_pcbc_encrypt(clear_ticket, clear_ticket,
- len, key_schedule, (C_Block *)key.key, 1);
-
- ZERO_STRUCT(key);
-
- *ticket = data_blob(clear_ticket, len);
-
- return True;
-}
-
-char *afs_createtoken_str(const char *username, const char *cell)
-{
- DATA_BLOB ticket;
- struct ClearToken ct;
- char *result;
-
- if (!afs_createtoken(username, cell, &ticket, &ct))
- return NULL;
-
- result = afs_encode_token(cell, ticket, &ct);
-
- data_blob_free(&ticket);
-
- return result;
-}
-
-/*
- This routine takes a radical approach completely bypassing the
- Kerberos idea of security and using AFS simply as an intelligent
- file backend. Samba has persuaded itself somehow that the user is
- actually correctly identified and then we create a ticket that the
- AFS server hopefully accepts using its KeyFile that the admin has
- kindly stored to our secrets.tdb.
-
- Thanks to the book "Network Security -- PRIVATE Communication in a
- PUBLIC World" by Charlie Kaufman, Radia Perlman and Mike Speciner
- Kerberos 4 tickets are not really hard to construct.
-
- For the comments "Alice" is the User to be auth'ed, and "Bob" is the
- AFS server. */
-
-BOOL afs_login(connection_struct *conn)
-{
- DATA_BLOB ticket;
- pstring afs_username;
- char *cell;
- BOOL result;
-
- struct ClearToken ct;
-
- pstrcpy(afs_username, lp_afs_username_map());
- standard_sub_conn(conn, afs_username, sizeof(afs_username));
-
- /* The pts command always generates completely lower-case user
- * names. */
- strlower_m(afs_username);
-
- cell = strchr(afs_username, '@');
-
- if (cell == NULL) {
- DEBUG(1, ("AFS username doesn't contain a @, "
- "could not find cell\n"));
- return False;
- }
-
- *cell = '\0';
- cell += 1;
-
- DEBUG(10, ("Trying to log into AFS for user %s@%s\n",
- afs_username, cell));
-
- if (!afs_createtoken(afs_username, cell, &ticket, &ct))
- return False;
-
- /* For which Unix-UID do we want to set the token? */
- ct.ViceId = getuid();
-
- {
- char *str, *new_cell;
- DATA_BLOB test_ticket;
- struct ClearToken test_ct;
-
- hex_encode(ct.HandShakeKey, sizeof(ct.HandShakeKey), &str);
- DEBUG(10, ("Key: %s\n", str));
- free(str);
-
- str = afs_encode_token(cell, ticket, &ct);
-
- if (!afs_decode_token(str, &new_cell, &test_ticket,
- &test_ct)) {
- DEBUG(0, ("Could not decode token"));
- goto decode_failed;
- }
-
- if (strcmp(cell, new_cell) != 0) {
- DEBUG(0, ("cell changed\n"));
- }
-
- if ((ticket.length != test_ticket.length) ||
- (memcmp(ticket.data, test_ticket.data,
- ticket.length) != 0)) {
- DEBUG(0, ("Ticket changed\n"));
- }
-
- if (memcmp(&ct, &test_ct, sizeof(ct)) != 0) {
- DEBUG(0, ("ClearToken changed\n"));
- }
-
- data_blob_free(&test_ticket);
-
- decode_failed:
- SAFE_FREE(str);
- SAFE_FREE(new_cell);
- }
-
- result = afs_settoken(cell, &ct, ticket);
-
- data_blob_free(&ticket);
-
- return result;
-}
-
-#else
-
-BOOL afs_login(connection_struct *conn)
-{
- return True;
-}
-
-BOOL afs_settoken_str(const char *token_string)
-{
- return False;
-}
-
-char *afs_createtoken_str(const char *username, const char *cell)
-{
- return False;
-}
-
-#endif /* WITH_FAKE_KASERVER */
diff --git a/source/lib/basic.m4 b/source/lib/basic.m4
new file mode 100644
index 00000000000..712a4826b72
--- /dev/null
+++ b/source/lib/basic.m4
@@ -0,0 +1,26 @@
+dnl # LIB BASIC subsystem
+
+SMB_SUBSYSTEM(LIBBASIC,[lib/version.o],
+ [lib/debug.o lib/fault.o \
+ lib/getsmbpass.o lib/interface.o \
+ lib/interfaces.o lib/pidfile.o lib/replace.o \
+ lib/signal.o lib/system.o lib/sendfile.o lib/time.o \
+ lib/genrand.o lib/username.o \
+ lib/util_getent.o lib/util_pw.o lib/smbrun.o \
+ lib/bitmap.o lib/snprintf.o lib/dprintf.o \
+ lib/xfile.o lib/wins_srv.o \
+ lib/util_str.o lib/util_sid.o lib/util_uuid.o \
+ lib/util_unistr.o lib/util_file.o lib/data_blob.o \
+ lib/util.o lib/util_sock.o \
+ lib/talloc.o lib/substitute.o lib/fsusage.o \
+ lib/ms_fnmatch.o lib/select.o lib/messages.o \
+ lib/tallocmsg.o lib/dmallocmsg.o \
+ lib/smbpasswd.o \
+ nsswitch/wb_client.o nsswitch/wb_common.o \
+ lib/pam_errors.o intl/lang_tdb.o lib/account_pol.o \
+ lib/gencache.o lib/module.o lib/mutex.o \
+ lib/ldap_escape.o lib/events.o \
+ lib/crypto/crc32.o lib/crypto/md5.o \
+ lib/crypto/hmacmd5.o lib/crypto/md4.o \
+ lib/tdb/tdb.o lib/tdb/spinlock.o lib/tdb/tdbutil.o \$(CHARSET_OBJS)],
+ lib/libbasic_public_proto.h)
diff --git a/source/lib/bitmap.c b/source/lib/bitmap.c
index 3fa20cdd112..1023dd6541d 100644
--- a/source/lib/bitmap.c
+++ b/source/lib/bitmap.c
@@ -84,20 +84,6 @@ struct bitmap *bitmap_talloc(TALLOC_CTX *mem_ctx, int n)
}
/****************************************************************************
-copy as much of the source bitmap as will fit in the destination bitmap.
-****************************************************************************/
-
-int bitmap_copy(struct bitmap * const dst, const struct bitmap * const src)
-{
- int count = MIN(dst->n, src->n);
-
- SMB_ASSERT(dst->b != src->b);
- memcpy(dst->b, src->b, sizeof(dst->b[0])*(count+31)/32);
-
- return count;
-}
-
-/****************************************************************************
set a bit in a bitmap
****************************************************************************/
BOOL bitmap_set(struct bitmap *bm, unsigned i)
diff --git a/source/lib/charcnv.c b/source/lib/charcnv.c
index b9791931a35..11b0e64dce9 100644
--- a/source/lib/charcnv.c
+++ b/source/lib/charcnv.c
@@ -4,7 +4,6 @@
Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
Copyright (C) Andrew Tridgell 2001
Copyright (C) Simo Sorce 2001
- Copyright (C) Martin Pool 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
@@ -38,9 +37,8 @@
* @sa lib/iconv.c
*/
-
static smb_iconv_t conv_handles[NUM_CHARSETS][NUM_CHARSETS];
-static BOOL conv_silent; /* Should we do a debug if the conversion fails ? */
+
/**
* Return the name of a charset to give to iconv().
@@ -54,36 +52,13 @@ static const char *charset_name(charset_t ch)
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 defined(HAVE_NL_LANGINFO) && defined(CODESET)
- if (ret && !strcmp(ret, "LOCALE")) {
- const char *ln = NULL;
-
-#ifdef HAVE_SETLOCALE
- setlocale(LC_ALL, "");
-#endif
- ln = nl_langinfo(CODESET);
- if (ln) {
- /* Check whether the charset name is supported
- by iconv */
- smb_iconv_t handle = smb_iconv_open(ln,"UCS-2LE");
- if (handle == (smb_iconv_t) -1) {
- DEBUG(5,("Locale charset '%s' unsupported, using ASCII instead\n", ln));
- ln = NULL;
- } else {
- DEBUG(5,("Substituting charset '%s' for LOCALE\n", ln));
- smb_iconv_close(handle);
- }
- }
- ret = ln;
- }
-#endif
+ else if (ch == CH_UCS2BE) ret = "UCS-2BE";
if (!ret || !*ret) ret = "ASCII";
return ret;
}
-void lazy_initialize_conv(void)
+static void lazy_initialize_conv(void)
{
static int initialized = False;
@@ -91,16 +66,14 @@ void lazy_initialize_conv(void)
initialized = True;
load_case_tables();
init_iconv();
+ init_valid_table();
}
}
/**
- * Initialize iconv conversion descriptors.
- *
- * This is called the first time it is needed, and also called again
- * every time the configuration is reloaded, because the charset or
- * codepage might have changed.
- **/
+ Initialize iconv conversion descriptors.
+**/
+
void init_iconv(void)
{
int c1, c2;
@@ -130,54 +103,30 @@ void init_iconv(void)
conv_handles[c1][c2] = smb_iconv_open(n2,n1);
if (conv_handles[c1][c2] == (smb_iconv_t)-1) {
- DEBUG(0,("init_iconv: Conversion from %s to %s not supported\n",
+ DEBUG(0,("Conversion from %s to %s not supported\n",
charset_name((charset_t)c1), charset_name((charset_t)c2)));
- if (c1 != CH_UCS2) {
- n1 = "ASCII";
- }
- if (c2 != CH_UCS2) {
- n2 = "ASCII";
- }
- DEBUG(0,("init_iconv: Attempting to replace with conversion from %s to %s\n",
- n1, n2 ));
- conv_handles[c1][c2] = smb_iconv_open(n2,n1);
- if (!conv_handles[c1][c2]) {
- DEBUG(0,("init_iconv: Conversion from %s to %s failed", n1, n2));
- smb_panic("init_iconv: conv_handle initialization failed.");
- }
+ conv_handles[c1][c2] = NULL;
}
}
}
if (did_reload) {
- /* XXX: Does this really get called every time the dos
- * codepage changes? */
- /* XXX: Is the did_reload test too strict? */
- conv_silent = True;
- init_doschar_table();
init_valid_table();
- conv_silent = False;
}
}
/**
* Convert string from one encoding to another, making error checking etc
- * Slow path version - uses (slow) iconv.
*
* @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
- * @param allow_bad_conv determines if a "best effort" conversion is acceptable (never returns errors)
* @returns the number of bytes occupied in the destination
- *
- * Ensure the srclen contains the terminating zero.
- *
**/
-
-static size_t convert_string_internal(charset_t from, charset_t to,
+ssize_t convert_string(charset_t from, charset_t to,
void const *src, size_t srclen,
- void *dest, size_t destlen, BOOL allow_bad_conv)
+ void *dest, size_t destlen)
{
size_t i_len, o_len;
size_t retval;
@@ -185,466 +134,127 @@ static size_t convert_string_internal(charset_t from, charset_t to,
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 (srclen == (size_t)-1) {
- if (from == CH_UCS2) {
- srclen = (strlen_w((const smb_ucs2_t *)src)+1) * 2;
- } else {
- srclen = strlen((const char *)src)+1;
- }
- }
-
-
if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
- if (!conv_silent)
- DEBUG(0,("convert_string_internal: Conversion not supported.\n"));
- return (size_t)-1;
+ /* conversion not supported, use as is */
+ size_t len = MIN(srclen,destlen);
+ memcpy(dest,src,len);
+ return len;
}
i_len=srclen;
o_len=destlen;
-
- again:
-
- retval = smb_iconv(descriptor, (char **)&inbuf, &i_len, &outbuf, &o_len);
+ retval = smb_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len);
if(retval==(size_t)-1) {
- const char *reason="unknown error";
+ const char *reason;
switch(errno) {
case EINVAL:
reason="Incomplete multibyte sequence";
- if (!conv_silent)
- DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
- if (allow_bad_conv)
- goto use_as_is;
break;
case E2BIG:
reason="No more room";
- if (!conv_silent)
- DEBUG(3, ("convert_string_internal: Required %lu, available %lu\n",
- (unsigned long)srclen, (unsigned long)destlen));
+ 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";
- if (!conv_silent)
- DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
- if (allow_bad_conv)
- goto use_as_is;
- break;
- default:
- if (!conv_silent)
- DEBUG(0,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
- break;
+ reason="Illegal multibyte sequence";
+ break;
}
/* smb_panic(reason); */
}
return destlen-o_len;
-
- use_as_is:
-
- /*
- * Conversion not supported. This is actually an error, but there are so
- * many misconfigured iconv systems and smb.conf's out there we can't just
- * fail. Do a very bad conversion instead.... JRA.
- */
-
- {
- if (o_len == 0 || i_len == 0)
- return destlen - o_len;
-
- if (from == CH_UCS2 && to != CH_UCS2) {
- /* Can't convert from ucs2 to multibyte. Just truncate this char to ascii. */
- if (i_len < 2)
- return destlen - o_len;
- if (i_len >= 2) {
- *outbuf = inbuf[0];
-
- outbuf++;
- o_len--;
-
- inbuf += 2;
- i_len -= 2;
- }
-
- if (o_len == 0 || i_len == 0)
- return destlen - o_len;
-
- /* Keep trying with the next char... */
- goto again;
-
- } else if (from != CH_UCS2 && to == CH_UCS2) {
- /* Can't convert to ucs2 - just widen by adding zero. */
- if (o_len < 2)
- return destlen - o_len;
-
- outbuf[0] = inbuf[0];
- outbuf[1] = '\0';
-
- inbuf++;
- i_len--;
-
- outbuf += 2;
- o_len -= 2;
-
- if (o_len == 0 || i_len == 0)
- return destlen - o_len;
-
- /* Keep trying with the next char... */
- goto again;
-
- } else if (from != CH_UCS2 && to != CH_UCS2) {
- /* Failed multibyte to multibyte. Just copy 1 char and
- try again. */
- outbuf[0] = inbuf[0];
-
- inbuf++;
- i_len--;
-
- outbuf++;
- o_len--;
-
- if (o_len == 0 || i_len == 0)
- return destlen - o_len;
-
- /* Keep trying with the next char... */
- goto again;
-
- } else {
- /* Keep compiler happy.... */
- return destlen - o_len;
- }
- }
-}
-
-/**
- * Convert string from one encoding to another, making error checking etc
- * Fast path version - handles ASCII first.
- *
- * @param src pointer to source string (multibyte or singlebyte)
- * @param srclen length of the source string in bytes, or -1 for nul terminated.
- * @param dest pointer to destination string (multibyte or singlebyte)
- * @param destlen maximal length allowed for string - *NEVER* -1.
- * @param allow_bad_conv determines if a "best effort" conversion is acceptable (never returns errors)
- * @returns the number of bytes occupied in the destination
- *
- * Ensure the srclen contains the terminating zero.
- *
- * This function has been hand-tuned to provide a fast path.
- * Don't change unless you really know what you are doing. JRA.
- **/
-
-size_t convert_string(charset_t from, charset_t to,
- void const *src, size_t srclen,
- void *dest, size_t destlen, BOOL allow_bad_conv)
-{
- /*
- * NB. We deliberately don't do a strlen here if srclen == -1.
- * This is very expensive over millions of calls and is taken
- * care of in the slow path in convert_string_internal. JRA.
- */
-
-#ifdef DEVELOPER
- SMB_ASSERT(destlen != (size_t)-1);
-#endif
-
- if (srclen == 0)
- return 0;
-
- if (from != CH_UCS2 && to != CH_UCS2) {
- const unsigned char *p = (const unsigned char *)src;
- unsigned char *q = (unsigned char *)dest;
- size_t slen = srclen;
- size_t dlen = destlen;
- unsigned char lastp;
- size_t retval = 0;
-
- /* If all characters are ascii, fast path here. */
- while (slen && dlen) {
- if ((lastp = *p) <= 0x7f) {
- *q++ = *p++;
- if (slen != (size_t)-1) {
- slen--;
- }
- dlen--;
- retval++;
- if (!lastp)
- break;
- } else {
-#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
- goto general_case;
-#else
- return retval + convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
-#endif
- }
- }
- return retval;
- } else if (from == CH_UCS2 && to != CH_UCS2) {
- const unsigned char *p = (const unsigned char *)src;
- unsigned char *q = (unsigned char *)dest;
- size_t retval = 0;
- size_t slen = srclen;
- size_t dlen = destlen;
- unsigned char lastp;
-
- /* If all characters are ascii, fast path here. */
- while (((slen == (size_t)-1) || (slen >= 2)) && dlen) {
- if (((lastp = *p) <= 0x7f) && (p[1] == 0)) {
- *q++ = *p;
- if (slen != (size_t)-1) {
- slen -= 2;
- }
- p += 2;
- dlen--;
- retval++;
- if (!lastp)
- break;
- } else {
-#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
- goto general_case;
-#else
- return retval + convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
-#endif
- }
- }
- return retval;
- } else if (from != CH_UCS2 && to == CH_UCS2) {
- const unsigned char *p = (const unsigned char *)src;
- unsigned char *q = (unsigned char *)dest;
- size_t retval = 0;
- size_t slen = srclen;
- size_t dlen = destlen;
- unsigned char lastp;
-
- /* If all characters are ascii, fast path here. */
- while (slen && (dlen >= 2)) {
- if ((lastp = *p) <= 0x7F) {
- *q++ = *p++;
- *q++ = '\0';
- if (slen != (size_t)-1) {
- slen--;
- }
- dlen -= 2;
- retval += 2;
- if (!lastp)
- break;
- } else {
-#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
- goto general_case;
-#else
- return retval + convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
-#endif
- }
- }
- return retval;
- }
-
-#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
- general_case:
-#endif
- return convert_string_internal(from, to, src, srclen, dest, destlen, allow_bad_conv);
}
/**
* Convert between character sets, allocating a new buffer for the result.
*
- * @param ctx TALLOC_CTX to use to allocate with. If NULL use malloc.
* @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.
- *
- * Ensure the srclen contains the terminating zero.
- *
- * I hate the goto's in this function. It's embarressing.....
- * There has to be a cleaner way to do this. JRA.
**/
-size_t convert_string_allocate(TALLOC_CTX *ctx, charset_t from, charset_t to,
- void const *src, size_t srclen, void **dest, BOOL allow_bad_conv)
+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 = MAX(srclen, 512);
+ size_t i_len, o_len, destlen;
size_t retval;
const char *inbuf = (const char *)src;
- char *outbuf = NULL, *ob = NULL;
+ char *outbuf, *ob;
smb_iconv_t descriptor;
*dest = NULL;
- if (src == NULL || srclen == (size_t)-1)
+ if (src == NULL || srclen == (size_t)-1 || srclen == 0)
return (size_t)-1;
- if (srclen == 0)
- return 0;
lazy_initialize_conv();
descriptor = conv_handles[from][to];
if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
- if (!conv_silent)
- DEBUG(0,("convert_string_allocate: Conversion not supported.\n"));
- return (size_t)-1;
+ /* conversion not supported, return -1*/
+ DEBUG(3, ("convert_string_allocate: conversion not supported!\n"));
+ return -1;
}
- convert:
-
- if ((destlen*2) < destlen) {
- /* wrapped ! abort. */
- if (!conv_silent)
- DEBUG(0, ("convert_string_allocate: destlen wrapped !\n"));
- if (!ctx)
- SAFE_FREE(outbuf);
- return (size_t)-1;
- } else {
- destlen = destlen * 2;
- }
-
- if (ctx)
- ob = (char *)talloc_realloc(ctx, ob, destlen);
- else
- ob = (char *)Realloc(ob, destlen);
-
+ 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"));
- if (!ctx)
- SAFE_FREE(outbuf);
+ SAFE_FREE(outbuf);
return (size_t)-1;
- } else {
- outbuf = ob;
}
+ else
+ outbuf = ob;
i_len = srclen;
o_len = destlen;
-
- again:
-
retval = smb_iconv(descriptor,
- (char **)&inbuf, &i_len,
+ &inbuf, &i_len,
&outbuf, &o_len);
if(retval == (size_t)-1) {
const char *reason="unknown error";
switch(errno) {
case EINVAL:
reason="Incomplete multibyte sequence";
- if (!conv_silent)
- DEBUG(3,("convert_string_allocate: Conversion error: %s(%s)\n",reason,inbuf));
- if (allow_bad_conv)
- goto use_as_is;
break;
case E2BIG:
goto convert;
case EILSEQ:
reason="Illegal multibyte sequence";
- if (!conv_silent)
- DEBUG(3,("convert_string_allocate: Conversion error: %s(%s)\n",reason,inbuf));
- if (allow_bad_conv)
- goto use_as_is;
break;
}
- if (!conv_silent)
- DEBUG(0,("Conversion error: %s(%s)\n",reason,inbuf));
+ DEBUG(0,("Conversion error: %s(%s)\n",reason,inbuf));
/* smb_panic(reason); */
return (size_t)-1;
}
-
- out:
-
+
destlen = destlen - o_len;
- if (ctx)
- *dest = (char *)talloc_realloc(ctx,ob,destlen);
- else
- *dest = (char *)Realloc(ob,destlen);
- if (destlen && !*dest) {
+ *dest = (char *)Realloc(ob,destlen);
+ if (!*dest) {
DEBUG(0, ("convert_string_allocate: out of memory!\n"));
- if (!ctx)
- SAFE_FREE(ob);
+ SAFE_FREE(ob);
return (size_t)-1;
}
return destlen;
-
- use_as_is:
-
- /*
- * Conversion not supported. This is actually an error, but there are so
- * many misconfigured iconv systems and smb.conf's out there we can't just
- * fail. Do a very bad conversion instead.... JRA.
- */
-
- {
- if (o_len == 0 || i_len == 0)
- goto out;
-
- if (from == CH_UCS2 && to != CH_UCS2) {
- /* Can't convert from ucs2 to multibyte. Just truncate this char to ascii. */
- if (i_len < 2)
- goto out;
-
- if (i_len >= 2) {
- *outbuf = inbuf[0];
-
- outbuf++;
- o_len--;
-
- inbuf += 2;
- i_len -= 2;
- }
-
- if (o_len == 0 || i_len == 0)
- goto out;
-
- /* Keep trying with the next char... */
- goto again;
-
- } else if (from != CH_UCS2 && to == CH_UCS2) {
- /* Can't convert to ucs2 - just widen by adding zero. */
- if (o_len < 2)
- goto out;
-
- outbuf[0] = inbuf[0];
- outbuf[1] = '\0';
-
- inbuf++;
- i_len--;
-
- outbuf += 2;
- o_len -= 2;
-
- if (o_len == 0 || i_len == 0)
- goto out;
-
- /* Keep trying with the next char... */
- goto again;
-
- } else if (from != CH_UCS2 && to != CH_UCS2) {
- /* Failed multibyte to multibyte. Just copy 1 char and
- try again. */
- outbuf[0] = inbuf[0];
-
- inbuf++;
- i_len--;
-
- outbuf++;
- o_len--;
-
- if (o_len == 0 || i_len == 0)
- goto out;
-
- /* Keep trying with the next char... */
- goto again;
-
- } else {
- /* Keep compiler happy.... */
- goto out;
- }
- }
}
+
/**
* Convert between character sets, allocating a new buffer using talloc for the result.
*
@@ -654,17 +264,25 @@ size_t convert_string_allocate(TALLOC_CTX *ctx, charset_t from, charset_t to,
*
* @returns Size in bytes of the converted string; or -1 in case of error.
**/
-static size_t convert_string_talloc(TALLOC_CTX *ctx, charset_t from, charset_t to,
- void const *src, size_t srclen, void **dest, BOOL allow_bad_conv)
+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(ctx, from, to, src, srclen, dest, allow_bad_conv);
+ dest_len=convert_string_allocate(from, to, src, srclen, &alloced_string);
if (dest_len == (size_t)-1)
return (size_t)-1;
- if (*dest == NULL)
- 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;
}
@@ -673,8 +291,9 @@ size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
size_t size;
smb_ucs2_t *buffer;
- size = push_ucs2_allocate(&buffer, src);
- if (size == (size_t)-1) {
+ 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)) {
@@ -682,105 +301,31 @@ size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
return srclen;
}
- size = convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen, True);
+ size = convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
free(buffer);
return size;
}
-/**
- strdup() a unix string to upper case.
- Max size is pstring.
-**/
-
-char *strdup_upper(const char *s)
-{
- pstring out_buffer;
- const unsigned char *p = (const unsigned char *)s;
- unsigned char *q = (unsigned char *)out_buffer;
-
- /* this is quite a common operation, so we want it to be
- fast. We optimise for the ascii case, knowing that all our
- supported multi-byte character sets are ascii-compatible
- (ie. they match for the first 128 chars) */
-
- while (1) {
- if (*p & 0x80)
- break;
- *q++ = toupper(*p);
- if (!*p)
- break;
- p++;
- if (p - ( const unsigned char *)s >= sizeof(pstring))
- break;
- }
-
- if (*p) {
- /* MB case. */
- size_t size;
- wpstring buffer;
- size = convert_string(CH_UNIX, CH_UCS2, s, -1, buffer, sizeof(buffer), True);
- if (size == (size_t)-1) {
- return NULL;
- }
-
- strupper_w(buffer);
-
- size = convert_string(CH_UCS2, CH_UNIX, buffer, -1, out_buffer, sizeof(out_buffer), True);
- if (size == (size_t)-1) {
- return NULL;
- }
- }
-
- return strdup(out_buffer);
-}
-
size_t unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
{
size_t size;
- smb_ucs2_t *buffer = NULL;
+ smb_ucs2_t *buffer;
- size = convert_string_allocate(NULL, CH_UNIX, CH_UCS2, src, srclen,
- (void **) &buffer, True);
- if (size == (size_t)-1 || !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)) {
- SAFE_FREE(buffer);
+ free(buffer);
return srclen;
}
- size = convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen, True);
- SAFE_FREE(buffer);
+ size = convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
+ free(buffer);
return size;
}
-/**
- strdup() a unix string to lower case.
-**/
-
-char *strdup_lower(const char *s)
-{
- size_t size;
- smb_ucs2_t *buffer = NULL;
- char *out_buffer;
-
- size = push_ucs2_allocate(&buffer, s);
- if (size == -1 || !buffer) {
- return NULL;
- }
-
- strlower_w(buffer);
-
- size = pull_ucs2_allocate(&out_buffer, buffer);
- SAFE_FREE(buffer);
-
- if (size == (size_t)-1) {
- return NULL;
- }
-
- return out_buffer;
-}
-
-static size_t ucs2_align(const void *base_ptr, const void *p, int flags)
+size_t ucs2_align(const void *base_ptr, const void *p, int flags)
{
if (flags & (STR_NOALIGN|STR_ASCII))
return 0;
@@ -802,7 +347,7 @@ static size_t ucs2_align(const void *base_ptr, const void *p, int flags)
* @param dest_len the maximum length in bytes allowed in the
* destination. If @p dest_len is -1 then no maximum is used.
**/
-size_t push_ascii(void *dest, const char *src, size_t dest_len, int flags)
+ssize_t push_ascii(void *dest, const char *src, size_t dest_len, int flags)
{
size_t src_len = strlen(src);
pstring tmpbuf;
@@ -813,63 +358,29 @@ size_t push_ascii(void *dest, const char *src, size_t dest_len, int flags)
if (flags & STR_UPPER) {
pstrcpy(tmpbuf, src);
- strupper_m(tmpbuf);
+ 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, True);
+ return convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len);
}
-size_t push_ascii_fstring(void *dest, const char *src)
+ssize_t push_ascii_fstring(void *dest, const char *src)
{
return push_ascii(dest, src, sizeof(fstring), STR_TERMINATE);
}
-size_t push_ascii_pstring(void *dest, const char *src)
+ssize_t push_ascii_pstring(void *dest, const char *src)
{
return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
}
-/********************************************************************
- Push an nstring - ensure null terminated. Written by
- moriyama@miraclelinux.com (MORIYAMA Masayuki).
-********************************************************************/
-
-size_t push_ascii_nstring(void *dest, const char *src)
+ssize_t push_pstring(void *dest, const char *src)
{
- size_t i, buffer_len, dest_len;
- smb_ucs2_t *buffer;
-
- conv_silent = True;
- buffer_len = push_ucs2_allocate(&buffer, src);
- if (buffer_len == (size_t)-1) {
- smb_panic("failed to create UCS2 buffer");
- }
-
- /* We're using buffer_len below to count ucs2 characters, not bytes. */
- buffer_len /= sizeof(smb_ucs2_t);
-
- dest_len = 0;
- for (i = 0; buffer[i] != 0 && (i < buffer_len); i++) {
- unsigned char mb[10];
- /* Convert one smb_ucs2_t character at a time. */
- size_t mb_len = convert_string(CH_UCS2, CH_DOS, buffer+i, sizeof(smb_ucs2_t), mb, sizeof(mb), False);
- if ((mb_len != (size_t)-1) && (dest_len + mb_len <= MAX_NETBIOSNAME_LEN - 1)) {
- memcpy((char *)dest + dest_len, mb, mb_len);
- dest_len += mb_len;
- } else {
- errno = E2BIG;
- break;
- }
- }
- ((char *)dest)[dest_len] = '\0';
-
- SAFE_FREE(buffer);
- conv_silent = False;
- return dest_len;
+ return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
}
/**
@@ -887,7 +398,7 @@ size_t push_ascii_nstring(void *dest, const char *src)
* @param src_len is the length of the source area in bytes.
* @returns the number of bytes occupied by the string in @p src.
**/
-size_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
+ssize_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
{
size_t ret;
@@ -905,36 +416,24 @@ size_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len,
}
}
- ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len, True);
- if (ret == (size_t)-1) {
- dest_len = 0;
- }
+ ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len);
if (dest_len)
dest[MIN(ret, dest_len-1)] = 0;
- else
- dest[0] = 0;
return src_len;
}
-size_t pull_ascii_pstring(char *dest, const void *src)
+ssize_t pull_ascii_pstring(char *dest, const void *src)
{
return pull_ascii(dest, src, sizeof(pstring), -1, STR_TERMINATE);
}
-size_t pull_ascii_fstring(char *dest, const void *src)
+ssize_t pull_ascii_fstring(char *dest, const void *src)
{
return pull_ascii(dest, src, sizeof(fstring), -1, STR_TERMINATE);
}
-/* When pulling an nstring it can expand into a larger size (dos cp -> utf8). Cope with this. */
-
-size_t pull_ascii_nstring(char *dest, size_t dest_len, const void *src)
-{
- return pull_ascii(dest, src, dest_len, sizeof(nstring), STR_TERMINATE);
-}
-
/**
* Copy a string from a char* src to a unicode destination.
*
@@ -951,51 +450,36 @@ size_t pull_ascii_nstring(char *dest, size_t dest_len, const void *src)
* @param dest_len is the maximum length allowed in the
* destination. If dest_len is -1 then no maxiumum is used.
**/
-
-size_t push_ucs2(const void *base_ptr, void *dest, const char *src, size_t dest_len, int flags)
+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;
- size_t ret;
+ 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 = (size_t)-1;
- else
- src_len = strlen(src);
+ src_len++;
if (ucs2_align(base_ptr, dest, flags)) {
*(char *)dest = 0;
dest = (void *)((char *)dest + 1);
- if (dest_len)
- dest_len--;
+ if (dest_len) dest_len--;
len++;
}
/* ucs2 is always a multiple of 2 bytes */
dest_len &= ~1;
- ret = convert_string(CH_UNIX, CH_UCS2, src, src_len, dest, dest_len, True);
- if (ret == (size_t)-1) {
- return 0;
- }
-
- len += ret;
-
- if (flags & STR_UPPER) {
- smb_ucs2_t *dest_ucs2 = dest;
- size_t i;
- for (i = 0; i < (dest_len / 2) && dest_ucs2[i]; i++) {
- smb_ucs2_t v = toupper_w(dest_ucs2[i]);
- if (v != dest_ucs2[i]) {
- dest_ucs2[i] = v;
- }
- }
- }
-
+ len += convert_string(CH_UNIX, CH_UCS2, src, src_len, dest, dest_len);
return len;
}
@@ -1009,12 +493,12 @@ size_t push_ucs2(const void *base_ptr, void *dest, const char *src, size_t dest_
* @returns The number of bytes occupied by the string in the destination
* or -1 in case of error.
**/
-size_t push_ucs2_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src)
+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, (void **)dest, True);
+ return convert_string_talloc(ctx, CH_UNIX, CH_UCS2, src, src_len, (const void **)dest);
}
@@ -1027,12 +511,12 @@ size_t push_ucs2_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src)
* or -1 in case of error.
**/
-size_t push_ucs2_allocate(smb_ucs2_t **dest, const char *src)
+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(NULL, CH_UNIX, CH_UCS2, src, src_len, (void **)dest, True);
+ return convert_string_allocate(CH_UNIX, CH_UCS2, src, src_len, (void **)dest);
}
/**
@@ -1045,7 +529,7 @@ size_t push_ucs2_allocate(smb_ucs2_t **dest, const char *src)
is -1 then no maxiumum is used.
**/
-static size_t push_utf8(void *dest, const char *src, size_t dest_len, int flags)
+ssize_t push_utf8(void *dest, const char *src, size_t dest_len, int flags)
{
size_t src_len = strlen(src);
pstring tmpbuf;
@@ -1056,21 +540,26 @@ static size_t push_utf8(void *dest, const char *src, size_t dest_len, int flags)
if (flags & STR_UPPER) {
pstrcpy(tmpbuf, src);
- strupper_m(tmpbuf);
+ strupper(tmpbuf);
src = tmpbuf;
}
if (flags & STR_TERMINATE)
src_len++;
- return convert_string(CH_UNIX, CH_UTF8, src, src_len, dest, dest_len, True);
+ return convert_string(CH_UNIX, CH_UTF8, src, src_len, dest, dest_len);
}
-size_t push_utf8_fstring(void *dest, const char *src)
+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
*
@@ -1079,12 +568,12 @@ size_t push_utf8_fstring(void *dest, const char *src)
* @returns The number of bytes occupied by the string in the destination
**/
-size_t push_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src)
+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, (void**)dest, True);
+ return convert_string_talloc(ctx, CH_UNIX, CH_UTF8, src, src_len, (const void **)dest);
}
/**
@@ -1095,12 +584,12 @@ size_t push_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src)
* @returns The number of bytes occupied by the string in the destination
**/
-size_t push_utf8_allocate(char **dest, const char *src)
+ssize_t push_utf8_allocate(char **dest, const char *src)
{
size_t src_len = strlen(src)+1;
*dest = NULL;
- return convert_string_allocate(NULL, CH_UNIX, CH_UTF8, src, src_len, (void **)dest, True);
+ return convert_string_allocate(CH_UNIX, CH_UTF8, src, src_len, (void **)dest);
}
/**
@@ -1123,13 +612,14 @@ size_t pull_ucs2(const void *base_ptr, char *dest, const void *src, size_t dest_
if (ucs2_align(base_ptr, src, flags)) {
src = (const void *)((const char *)src + 1);
- if (src_len != (size_t)-1)
+ if (src_len > 0)
src_len--;
}
if (flags & STR_TERMINATE) {
- /* src_len -1 is the default for null terminated strings. */
- if (src_len != (size_t)-1) {
+ 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++;
@@ -1141,28 +631,19 @@ size_t pull_ucs2(const void *base_ptr, char *dest, const void *src, size_t dest_
if (src_len != (size_t)-1)
src_len &= ~1;
- ret = convert_string(CH_UCS2, CH_UNIX, src, src_len, dest, dest_len, True);
- if (ret == (size_t)-1) {
- return 0;
- }
-
- if (src_len == (size_t)-1)
- src_len = ret*2;
-
+ ret = convert_string(CH_UCS2, CH_UNIX, src, src_len, dest, dest_len);
if (dest_len)
dest[MIN(ret, dest_len-1)] = 0;
- else
- dest[0] = 0;
return src_len;
}
-size_t pull_ucs2_pstring(char *dest, const void *src)
+ssize_t pull_ucs2_pstring(char *dest, const void *src)
{
return pull_ucs2(NULL, dest, src, sizeof(pstring), -1, STR_TERMINATE);
}
-size_t pull_ucs2_fstring(char *dest, const void *src)
+ssize_t pull_ucs2_fstring(char *dest, const void *src)
{
return pull_ucs2(NULL, dest, src, sizeof(fstring), -1, STR_TERMINATE);
}
@@ -1175,11 +656,11 @@ size_t pull_ucs2_fstring(char *dest, const void *src)
* @returns The number of bytes occupied by the string in the destination
**/
-size_t pull_ucs2_talloc(TALLOC_CTX *ctx, char **dest, const smb_ucs2_t *src)
+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, (void **)dest, True);
+ return convert_string_talloc(ctx, CH_UCS2, CH_UNIX, src, src_len, (const void **)dest);
}
/**
@@ -1190,11 +671,56 @@ size_t pull_ucs2_talloc(TALLOC_CTX *ctx, char **dest, const smb_ucs2_t *src)
* @returns The number of bytes occupied by the string in the destination
**/
-size_t pull_ucs2_allocate(char **dest, const smb_ucs2_t *src)
+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(NULL, CH_UCS2, CH_UNIX, src, src_len, (void **)dest, True);
+ 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);
}
/**
@@ -1205,11 +731,11 @@ size_t pull_ucs2_allocate(char **dest, const smb_ucs2_t *src)
* @returns The number of bytes occupied by the string in the destination
**/
-size_t pull_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src)
+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, (void **)dest, True);
+ return convert_string_talloc(ctx, CH_UTF8, CH_UNIX, src, src_len, (const void **)dest);
}
/**
@@ -1220,11 +746,11 @@ size_t pull_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src)
* @returns The number of bytes occupied by the string in the destination
**/
-size_t pull_utf8_allocate(char **dest, const char *src)
+ssize_t pull_utf8_allocate(void **dest, const char *src)
{
size_t src_len = strlen(src)+1;
*dest = NULL;
- return convert_string_allocate(NULL, CH_UTF8, CH_UNIX, src, src_len, (void **)dest, True);
+ return convert_string_allocate(CH_UTF8, CH_UNIX, src, src_len, dest);
}
/**
@@ -1241,27 +767,11 @@ size_t pull_utf8_allocate(char **dest, const char *src)
is -1 then no maxiumum is used.
**/
-size_t push_string_fn(const char *function, unsigned int line, const void *base_ptr, void *dest, const char *src, size_t dest_len, int flags)
+ssize_t push_string(const void *base_ptr, void *dest, const char *src, size_t dest_len, int flags)
{
-#ifdef DEVELOPER
- /* We really need to zero fill here, not clobber
- * region, as we want to ensure that valgrind thinks
- * all of the outgoing buffer has been written to
- * so a send() or write() won't trap an error.
- * JRA.
- */
-#if 0
- if (dest_len != (size_t)-1)
- clobber_region(function, line, dest, dest_len);
-#else
- if (dest_len != (size_t)-1)
- memset(dest, '\0', dest_len);
-#endif
-#endif
-
if (!(flags & STR_ASCII) && \
- ((flags & STR_UNICODE || \
- (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
+ (((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);
@@ -1282,58 +792,135 @@ size_t push_string_fn(const char *function, unsigned int line, const void *base_
The resulting string in "dest" is always null terminated.
**/
-size_t pull_string_fn(const char *function, unsigned int line, const void *base_ptr, char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
+ssize_t pull_string(const void *base_ptr, char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
{
-#ifdef DEVELOPER
- if (dest_len != (size_t)-1)
- clobber_region(function, line, dest, dest_len);
-#endif
-
if (!(flags & STR_ASCII) && \
- ((flags & STR_UNICODE || \
- (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
+ (((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);
}
-size_t align_string(const void *base_ptr, const char *p, int flags)
+ssize_t align_string(const void *base_ptr, const char *p, int flags)
{
if (!(flags & STR_ASCII) && \
((flags & STR_UNICODE || \
- (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
+ (SVAL(base_ptr, NBT_HDR_SIZE+HDR_FLG2) & FLAGS2_UNICODE_STRINGS)))) {
return ucs2_align(base_ptr, p, flags);
}
return 0;
}
-/****************************************************************
- Calculate the size (in bytes) of the next multibyte character in
- our internal character set. Note that p must be pointing to a
- valid mb char, not within one.
-****************************************************************/
+/**
+ 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.
+**/
-size_t next_mb_char_size(const char *s)
+ssize_t pull_string_talloc(TALLOC_CTX *ctx, char **dest, const void *src, size_t src_len, int flags)
{
- size_t i;
-
- if (!(*s & 0x80))
- return 1; /* ascii. */
-
- conv_silent = True;
- for ( i = 1; i <=4; i++ ) {
- smb_ucs2_t uc;
- if (convert_string(CH_UNIX, CH_UCS2, s, i, &uc, 2, False) == 2) {
-#if 0 /* JRATEST */
- DEBUG(10,("next_mb_char_size: size %u at string %s\n",
- (unsigned int)i, s));
-#endif
- conv_silent = False;
- return i;
- }
+ 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);
}
- /* We're hosed - we don't know how big this is... */
- DEBUG(10,("next_mb_char_size: unknown size at string %s\n", s));
- conv_silent = False;
- return 1;
+ *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;
}
diff --git a/source/lib/clobber.c b/source/lib/clobber.c
deleted file mode 100644
index fb3a0dc2815..00000000000
--- a/source/lib/clobber.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
- Samba utility functions
- Copyright (C) Martin Pool 2003
- Copyright (C) Andrew Bartlett 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"
-
-#ifdef DEVELOPER
-const char *global_clobber_region_function;
-unsigned int global_clobber_region_line;
-#endif
-
-/**
- * In developer builds, clobber a region of memory.
- *
- * If we think a string buffer is longer than it really is, this ought
- * to make the failure obvious, by segfaulting (if in the heap) or by
- * killing the return address (on the stack), or by trapping under a
- * memory debugger.
- *
- * This is meant to catch possible string overflows, even if the
- * actual string copied is not big enough to cause an overflow.
- *
- * In addition, under Valgrind the buffer is marked as uninitialized.
- **/
-void clobber_region(const char *fn, unsigned int line, char *dest, size_t len)
-{
-#ifdef DEVELOPER
- global_clobber_region_function = fn;
- global_clobber_region_line = line;
-
- /* F1 is odd and 0xf1f1f1f1 shouldn't be a valid pointer */
- memset(dest, 0xF1, len);
-#ifdef VALGRIND
- /* Even though we just wrote to this, from the application's
- * point of view it is not initialized.
- *
- * (This is not redundant with the clobbering above. The
- * marking might not actually take effect if we're not running
- * under valgrind.) */
- VALGRIND_MAKE_WRITABLE(dest, len);
-#endif /* VALGRIND */
-#endif /* DEVELOPER */
-}
diff --git a/source/lib/cmdline/config.m4 b/source/lib/cmdline/config.m4
new file mode 100644
index 00000000000..6e9a8f45089
--- /dev/null
+++ b/source/lib/cmdline/config.m4
@@ -0,0 +1,79 @@
+#################################################
+
+###############################################
+# Readline included by default unless explicitly asked not to
+test "${with_readline+set}" != "set" && with_readline=yes
+
+# test for where we get readline() from
+AC_MSG_CHECKING(whether to use readline)
+AC_ARG_WITH(readline,
+[ --with-readline[=DIR] Look for readline include/libs in DIR (default=auto) ],
+[ case "$with_readline" in
+ yes)
+ AC_MSG_RESULT(yes)
+
+ AC_CHECK_HEADERS(readline.h history.h readline/readline.h)
+ AC_CHECK_HEADERS(readline/history.h)
+
+ AC_CHECK_HEADERS(readline.h readline/readline.h,[
+ for termlib in ncurses curses termcap terminfo termlib tinfo; do
+ AC_CHECK_LIB(${termlib}, tgetent, [TERMLIBS="-l${termlib}"; break])
+ done
+ AC_CHECK_LIB(readline, rl_callback_handler_install,
+ [TERMLIBS="-lreadline $TERMLIBS"
+ AC_DEFINE(HAVE_LIBREADLINE,1,[Whether the system has readline])
+ break], [TERMLIBS=], $TERMLIBS)])
+ ;;
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+
+ # Needed for AC_CHECK_HEADERS and AC_CHECK_LIB to look at
+ # alternate readline path
+ _ldflags=${LDFLAGS}
+ _cppflags=${CPPFLAGS}
+
+ # Add additional search path
+ LDFLAGS="-L$with_readline/lib $LDFLAGS"
+ CPPFLAGS="-I$with_readline/include $CPPFLAGS"
+
+ AC_CHECK_HEADERS(readline.h history.h readline/readline.h)
+ AC_CHECK_HEADERS(readline/history.h)
+
+ AC_CHECK_HEADERS(readline.h readline/readline.h,[
+ for termlib in ncurses curses termcap terminfo termlib; do
+ AC_CHECK_LIB(${termlib}, tgetent, [TERMLIBS="-l${termlib}"; break])
+ done
+ AC_CHECK_LIB(readline, rl_callback_handler_install,
+ [TERMLDFLAGS="-L$with_readline/lib"
+ TERMCPPFLAGS="-I$with_readline/include"
+ LDFLAGS="-L$with_readline/lib $LDFLAGS"
+ CPPFLAGS="-I$with_readline/include $CPPFLAGS"
+ TERMLIBS="-lreadline $TERMLIBS"
+ AC_DEFINE(HAVE_LIBREADLINE,1,[Whether the system has readline])
+ break], [TERMLIBS= CPPFLAGS=$_cppflags], $TERMLIBS)])
+
+ ;;
+ esac],
+ AC_MSG_RESULT(no)
+)
+
+# The readline API changed slightly from readline3 to readline4, so
+# code will generate warnings on one of them unless we have a few
+# special cases.
+AC_CHECK_LIB(readline, rl_completion_matches,
+ [AC_DEFINE(HAVE_NEW_LIBREADLINE, 1,
+ [Do we have rl_completion_matches?])],
+ [],
+ [$TERMLIBS])
+
+TMP_LIBCMDLINE_OBJS="lib/cmdline/readline.o lib/cmdline/popt_common.o"
+TMP_LIBCMDLINE_LIBS="$TERMLIBS"
+
+SMB_SUBSYSTEM(LIBCMDLINE,[],
+ [${TMP_LIBCMDLINE_OBJS}],
+ [],
+ [],
+ [${TMP_LIBCMDLINE_LIBS}])
diff --git a/source/lib/popt_common.c b/source/lib/cmdline/popt_common.c
index 6c35213d43a..1b8e3bd93e9 100644
--- a/source/lib/popt_common.c
+++ b/source/lib/cmdline/popt_common.c
@@ -35,7 +35,6 @@
extern pstring user_socket_options;
extern BOOL AllowDebugChange;
-extern BOOL override_logfile;
struct user_auth_info cmdline_auth_info;
@@ -57,59 +56,47 @@ static void popt_common_callback(poptContext con,
if (reason == POPT_CALLBACK_REASON_PRE) {
pstr_sprintf(logfile, "%s/log.%s", dyn_LOGFILEBASE, pname);
- lp_set_logfile(logfile);
+ lp_set_cmdline("log file", logfile);
return;
}
switch(opt->val) {
case 'd':
- if (arg) {
- debug_parse_levels(arg);
- AllowDebugChange = False;
- }
+ lp_set_cmdline("log level", arg);
break;
case 'V':
- printf( "Version %s\n", SAMBA_VERSION_STRING);
+ printf( "Version %s\n", SAMBA_VERSION_STRING );
exit(0);
break;
- case 'O':
- if (arg) {
- pstrcpy(user_socket_options,arg);
- }
- break;
-
case 's':
if (arg) {
pstrcpy(dyn_CONFIGFILE, arg);
}
break;
- case 'n':
- if (arg) {
- set_global_myname(arg);
- }
- break;
-
case 'l':
if (arg) {
pstr_sprintf(logfile, "%s/log.%s", arg, pname);
- lp_set_logfile(logfile);
- override_logfile = True;
+ 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':
- if (arg) {
- set_global_scope(arg);
- }
+ lp_set_cmdline("netbios scope", arg);
break;
- case 'W':
- if (arg) {
- set_global_myworkgroup(arg);
- }
+ case 'm':
+ lp_set_cmdline("max protocol", arg);
break;
}
}
@@ -121,7 +108,7 @@ struct poptOption popt_common_connection[] = {
{ "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" },
-
+ { "maxprotocol", 'm', POPT_ARG_STRING, NULL, 'm', "Set max protocol level", "MAXPROTOCOL" },
POPT_TABLEEND
};
@@ -249,8 +236,10 @@ static void get_credentials_file(const char *file, struct user_auth_info *info)
}
else if (strwicmp("username", param) == 0)
pstrcpy(info->username, val);
+#if 0
else if (strwicmp("domain", param) == 0)
set_global_myworkgroup(val);
+#endif
memset(buf, 0, sizeof(buf));
}
x_fclose(auth);
@@ -261,22 +250,19 @@ static void get_credentials_file(const char *file, struct user_auth_info *info)
* -A,--authentication-file
* -k,--use-kerberos
* -N,--no-pass
- * -S,--signing
- * -P --machine-pass
*/
static void popt_common_credentials_callback(poptContext con,
- enum poptCallbackReason reason,
- const struct poptOption *opt,
- const char *arg, const void *data)
+ 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;
- cmdline_auth_info.signing_state = Undefined;
pstrcpy(cmdline_auth_info.username, "GUEST");
if (getenv("LOGNAME"))pstrcpy(cmdline_auth_info.username,getenv("LOGNAME"));
@@ -333,50 +319,6 @@ static void popt_common_credentials_callback(poptContext con,
cmdline_auth_info.got_pass = True;
#endif
break;
-
- case 'S':
- {
- cmdline_auth_info.signing_state = -1;
- if (strequal(arg, "off") || strequal(arg, "no") || strequal(arg, "false"))
- cmdline_auth_info.signing_state = False;
- else if (strequal(arg, "on") || strequal(arg, "yes") || strequal(arg, "true") ||
- strequal(arg, "auto") )
- cmdline_auth_info.signing_state = True;
- else if (strequal(arg, "force") || strequal(arg, "required") || strequal(arg, "forced"))
- cmdline_auth_info.signing_state = Required;
- else {
- fprintf(stderr, "Unknown signing option %s\n", arg );
- exit(1);
- }
- }
- break;
- case 'P':
- {
- char *opt_password = NULL;
- /* it is very useful to be able to make ads queries as the
- machine account for testing purposes and for domain leave */
-
- if (!secrets_init()) {
- d_printf("ERROR: Unable to open secrets database\n");
- exit(1);
- }
-
- opt_password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
-
- if (!opt_password) {
- d_printf("ERROR: Unable to fetch machine password\n");
- exit(1);
- }
- pstr_sprintf(cmdline_auth_info.username, "%s$",
- global_myname());
- pstrcpy(cmdline_auth_info.password,opt_password);
- SAFE_FREE(opt_password);
-
- /* machine accounts only work with kerberos */
- cmdline_auth_info.use_kerberos = True;
- cmdline_auth_info.got_pass = True;
- }
- break;
}
}
@@ -385,10 +327,8 @@ static void popt_common_credentials_callback(poptContext con,
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, 0, "Don't ask for a password" },
- { "kerberos", 'k', POPT_ARG_NONE, &cmdline_auth_info.use_kerberos, 'k', "Use kerberos (active directory) authentication" },
+ { "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" },
- { "signing", 'S', POPT_ARG_STRING, NULL, 'S', "Set the client signing state", "on|off|required" },
- {"machine-pass", 'P', POPT_ARG_NONE, NULL, 'P', "Use stored machine account password" },
POPT_TABLEEND
};
diff --git a/source/lib/readline.c b/source/lib/cmdline/readline.c
index 78b99fd7fb0..c5da88b3e00 100644
--- a/source/lib/readline.c
+++ b/source/lib/cmdline/readline.c
@@ -50,7 +50,7 @@
Display the prompt and wait for input. Call callback() regularly
****************************************************************************/
-static char *smb_readline_replacement(char *prompt, void (*callback)(void),
+static char *smb_readline_replacement(const char *prompt, void (*callback)(void),
char **(completion_fn)(const char *text, int start, int end))
{
fd_set fds;
@@ -59,8 +59,7 @@ static char *smb_readline_replacement(char *prompt, void (*callback)(void),
int fd = x_fileno(x_stdin);
char *ret;
- x_fprintf(dbf, "%s", prompt);
- x_fflush(dbf);
+ do_debug("%s", prompt);
while (1) {
timeout.tv_sec = 5;
@@ -82,7 +81,7 @@ static char *smb_readline_replacement(char *prompt, void (*callback)(void),
Display the prompt and wait for input. Call callback() regularly.
****************************************************************************/
-char *smb_readline(char *prompt, void (*callback)(void),
+char *smb_readline(const char *prompt, void (*callback)(void),
char **(completion_fn)(const char *text, int start, int end))
{
#if HAVE_LIBREADLINE
@@ -127,7 +126,6 @@ const char *smb_readline_get_line_buffer(void)
#endif
}
-
/****************************************************************************
* set completion append character
***************************************************************************/
@@ -138,6 +136,7 @@ void smb_readline_ca_char(char c)
#endif
}
+
/****************************************************************************
history
****************************************************************************/
@@ -158,4 +157,3 @@ int cmd_history(void)
return 0;
}
-
diff --git a/source/lib/crc32.c b/source/lib/crypto/crc32.c
index da3aeaa901d..da3aeaa901d 100644
--- a/source/lib/crc32.c
+++ b/source/lib/crypto/crc32.c
diff --git a/source/lib/hmacmd5.c b/source/lib/crypto/hmacmd5.c
index f436fd30c0e..8ca7dba8411 100644
--- a/source/lib/hmacmd5.c
+++ b/source/lib/crypto/hmacmd5.c
@@ -121,7 +121,7 @@ void hmac_md5_final(uchar *digest, HMACMD5Context *ctx)
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)
+void hmac_md5(const uchar key[16], const uchar *data, int data_len, uchar* digest)
{
HMACMD5Context ctx;
hmac_md5_init_limK_to_64(key, 16, &ctx);
diff --git a/source/lib/md4.c b/source/lib/crypto/md4.c
index 6803b7e8831..417e87bd8e2 100644
--- a/source/lib/md4.c
+++ b/source/lib/crypto/md4.c
@@ -25,7 +25,9 @@
It assumes that a int is at least 32 bits long
*/
-static uint32 A, B, C, D;
+struct mdfour_state {
+ uint32 A, B, C, D;
+};
static uint32 F(uint32 X, uint32 Y, uint32 Z)
{
@@ -53,7 +55,7 @@ static uint32 lshift(uint32 x, int 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(uint32 *M)
+static void mdfour64(struct mdfour_state *s, uint32 *M)
{
int j;
uint32 AA, BB, CC, DD;
@@ -62,39 +64,44 @@ static void mdfour64(uint32 *M)
for (j=0;j<16;j++)
X[j] = M[j];
- AA = A; BB = B; CC = C; DD = D;
-
- ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
- ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
- ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
- ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
- ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
- ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
- ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
- ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
-
- ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
- ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
- ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
- ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
- ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
- ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
- ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
- ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
-
- ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
- ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
- ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
- ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
- ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
- ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
- ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
- ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
-
- A += AA; B += BB; C += CC; D += DD;
+ 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;
- A &= 0xFFFFFFFF; B &= 0xFFFFFFFF;
- C &= 0xFFFFFFFF; D &= 0xFFFFFFFF;
+ s->A &= 0xFFFFFFFF;
+ s->B &= 0xFFFFFFFF;
+ s->C &= 0xFFFFFFFF;
+ s->D &= 0xFFFFFFFF;
for (j=0;j<16;j++)
X[j] = 0;
@@ -124,15 +131,16 @@ void mdfour(unsigned char *out, const unsigned char *in, int n)
uint32 M[16];
uint32 b = n * 8;
int i;
+ struct mdfour_state state;
- A = 0x67452301;
- B = 0xefcdab89;
- C = 0x98badcfe;
- D = 0x10325476;
+ state.A = 0x67452301;
+ state.B = 0xefcdab89;
+ state.C = 0x98badcfe;
+ state.D = 0x10325476;
while (n > 64) {
copy64(M, in);
- mdfour64(M);
+ mdfour64(&state, M);
in += 64;
n -= 64;
}
@@ -145,25 +153,23 @@ void mdfour(unsigned char *out, const unsigned char *in, int n)
if (n <= 55) {
copy4(buf+56, b);
copy64(M, buf);
- mdfour64(M);
+ mdfour64(&state, M);
} else {
copy4(buf+120, b);
copy64(M, buf);
- mdfour64(M);
+ mdfour64(&state, M);
copy64(M, buf+64);
- mdfour64(M);
+ mdfour64(&state, M);
}
for (i=0;i<128;i++)
buf[i] = 0;
copy64(M, buf);
- copy4(out, A);
- copy4(out+4, B);
- copy4(out+8, C);
- copy4(out+12, D);
-
- A = B = C = D = 0;
+ copy4(out, state.A);
+ copy4(out+4, state.B);
+ copy4(out+8, state.C);
+ copy4(out+12, state.D);
}
diff --git a/source/lib/md5.c b/source/lib/crypto/md5.c
index 2121b170479..2121b170479 100644
--- a/source/lib/md5.c
+++ b/source/lib/crypto/md5.c
diff --git a/source/lib/data_blob.c b/source/lib/data_blob.c
index 83afc591a15..b5d1b4076e1 100644
--- a/source/lib/data_blob.c
+++ b/source/lib/data_blob.c
@@ -61,19 +61,25 @@ DATA_BLOB data_blob_talloc(TALLOC_CTX *mem_ctx, const void *p, size_t length)
{
DATA_BLOB ret;
- if (!length) {
+ if (length == 0) {
ZERO_STRUCT(ret);
return ret;
}
- if (p) {
- ret.data = talloc_memdup(mem_ctx, p, length);
- if (ret.data == NULL)
- smb_panic("data_blob_talloc: talloc_memdup failed.\n");
- } else {
+ if (p == NULL) {
+ /* note that we do NOT zero memory in this case */
ret.data = talloc(mem_ctx, length);
- if (ret.data == NULL)
- smb_panic("data_blob_talloc: talloc failed.\n");
+ if (ret.data == NULL) {
+ smb_panic("data_blob_talloc: talloc_memdup failed.\n");
+ }
+ ret.length = length;
+ ret.free = NULL;
+ 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;
@@ -82,6 +88,18 @@ DATA_BLOB data_blob_talloc(TALLOC_CTX *mem_ctx, const void *p, size_t length)
}
/*******************************************************************
+ construct a zero data blob, using supplied TALLOC_CTX.
+ use this sparingly as it initialises data - better to initialise
+ yourself if you want specific data in the blob
+*******************************************************************/
+DATA_BLOB data_blob_talloc_zero(TALLOC_CTX *mem_ctx, size_t length)
+{
+ DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, length);
+ data_blob_clear(&blob);
+ return blob;
+}
+
+/*******************************************************************
free a data blob
*******************************************************************/
void data_blob_free(DATA_BLOB *d)
@@ -97,7 +115,7 @@ void data_blob_free(DATA_BLOB *d)
/*******************************************************************
clear a DATA_BLOB's contents
*******************************************************************/
-static void data_blob_clear(DATA_BLOB *d)
+void data_blob_clear(DATA_BLOB *d)
{
if (d->data) {
memset(d->data, 0, d->length);
@@ -113,3 +131,24 @@ void data_blob_clear_free(DATA_BLOB *d)
data_blob_free(d);
}
+
+/*******************************************************************
+check if two data blobs are equal
+*******************************************************************/
+BOOL data_blob_equal(const DATA_BLOB *d1, const DATA_BLOB *d2)
+{
+ if (d1->length != d2->length) {
+ return False;
+ }
+ if (d1->data == d2->data) {
+ return True;
+ }
+ if (d1->data == NULL || d2->data == NULL) {
+ return False;
+ }
+ if (memcmp(d1->data, d2->data, d1->length) == 0) {
+ return True;
+ }
+ return False;
+}
+
diff --git a/source/lib/debug.c b/source/lib/debug.c
index 1a926053bb0..dbd3946c81b 100644
--- a/source/lib/debug.c
+++ b/source/lib/debug.c
@@ -1,9 +1,8 @@
/*
Unix SMB/CIFS implementation.
- Samba utility functions
- Copyright (C) Andrew Tridgell 1992-1998
- Copyright (C) Elrond 2002
- Copyright (C) Simo Sorce 2002
+ 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
@@ -22,973 +21,145 @@
#include "includes.h"
-/* -------------------------------------------------------------------------- **
- * Defines...
- *
- * FORMAT_BUFR_MAX - Index of the last byte of the format buffer;
- * format_bufr[FORMAT_BUFR_MAX] should always be reserved
- * for a terminating null byte.
- */
+/* this global variable determines what messages are printed */
+int DEBUGLEVEL;
-#define FORMAT_BUFR_MAX ( sizeof( format_bufr ) - 1 )
-/* -------------------------------------------------------------------------- **
- * This module implements Samba's debugging utility.
- *
- * The syntax of a debugging log file is represented as:
- *
- * <debugfile> :== { <debugmsg> }
- *
- * <debugmsg> :== <debughdr> '\n' <debugtext>
- *
- * <debughdr> :== '[' TIME ',' LEVEL ']' [ [FILENAME ':'] [FUNCTION '()'] ]
- *
- * <debugtext> :== { <debugline> }
- *
- * <debugline> :== TEXT '\n'
- *
- * TEXT is a string of characters excluding the newline character.
- * LEVEL is the DEBUG level of the message (an integer in the range 0..10).
- * TIME is a timestamp.
- * FILENAME is the name of the file from which the debug message was generated.
- * FUNCTION is the function from which the debug message was generated.
- *
- * Basically, what that all means is:
- *
- * - A debugging log file is made up of debug messages.
- *
- * - Each debug message is made up of a header and text. The header is
- * separated from the text by a newline.
- *
- * - The header begins with the timestamp and debug level of the message
- * enclosed in brackets. The filename and function from which the
- * message was generated may follow. The filename is terminated by a
- * colon, and the function name is terminated by parenthesis.
- *
- * - The message text is made up of zero or more lines, each terminated by
- * a newline.
- */
+/* the registered mutex handlers */
+static struct {
+ const char *name;
+ struct debug_ops ops;
+} debug_handlers;
-/* -------------------------------------------------------------------------- **
- * External variables.
- *
- * dbf - Global debug file handle.
- * debugf - Debug file name.
- * DEBUGLEVEL - System-wide debug message limit. Messages with message-
- * levels higher than DEBUGLEVEL will not be processed.
- */
-
-XFILE *dbf = NULL;
-pstring debugf = "";
-BOOL debug_warn_unknown_class = True;
-BOOL debug_auto_add_unknown_class = True;
-BOOL AllowDebugChange = True;
-
-/*
- used to check if the user specified a
- logfile on the command line
-*/
-BOOL override_logfile;
-
-
-/*
- * This is to allow assignment to DEBUGLEVEL before the debug
- * system has been initialised.
- */
-static int debug_all_class_hack = 1;
-static BOOL debug_all_class_isset_hack = True;
-
-static int debug_num_classes = 0;
-int *DEBUGLEVEL_CLASS = &debug_all_class_hack;
-BOOL *DEBUGLEVEL_CLASS_ISSET = &debug_all_class_isset_hack;
-
-/* DEBUGLEVEL is #defined to *debug_level */
-int DEBUGLEVEL = &debug_all_class_hack;
-
-
-/* -------------------------------------------------------------------------- **
- * Internal variables.
- *
- * stdout_logging - Default False, if set to True then dbf will be set to
- * stdout and debug output will go to dbf only, and not
- * to syslog. Set in setup_logging() and read in Debug1().
- *
- * debug_count - Number of debug messages that have been output.
- * Used to check log size.
- *
- * syslog_level - Internal copy of the message debug level. Written by
- * dbghdr() and read by Debug1().
- *
- * format_bufr - Used to format debug messages. The dbgtext() function
- * prints debug messages to a string, and then passes the
- * string to format_debug_text(), which uses format_bufr
- * to build the formatted output.
- *
- * format_pos - Marks the first free byte of the format_bufr.
- *
- *
- * log_overflow - When this variable is True, never attempt to check the
- * size of the log. This is a hack, so that we can write
- * a message using DEBUG, from open_logs() when we
- * are unable to open a new log file for some reason.
- */
-
-static BOOL stdout_logging = False;
-static int debug_count = 0;
-#ifdef WITH_SYSLOG
-static int syslog_level = 0;
-#endif
-static pstring format_bufr = { '\0' };
-static size_t format_pos = 0;
-static BOOL log_overflow = False;
+/* state variables for the debug system */
+static struct {
+ int fd;
+ enum debug_logtype logtype;
+ const char *prog_name;
+} state;
/*
- * Define all the debug class selection names here. Names *MUST NOT* contain
- * white space. There must be one name for each DBGC_<class name>, and they
- * must be in the table in the order of DBGC_<class name>..
- */
-static const char *default_classname_table[] = {
- "all", /* DBGC_ALL; index refs traditional DEBUGLEVEL */
- "tdb", /* DBGC_TDB */
- "printdrivers", /* DBGC_PRINTDRIVERS */
- "lanman", /* DBGC_LANMAN */
- "smb", /* DBGC_SMB */
- "rpc_parse", /* DBGC_RPC_PARSE */
- "rpc_srv", /* DBGC_RPC_SRV */
- "rpc_cli", /* DBGC_RPC_CLI */
- "passdb", /* DBGC_PASSDB */
- "sam", /* DBGC_SAM */
- "auth", /* DBGC_AUTH */
- "winbind", /* DBGC_WINBIND */
- "vfs", /* DBGC_VFS */
- "idmap", /* DBGC_IDMAP */
- "quota", /* DBGC_QUOTA */
- NULL
-};
-
-static char **classname_table = NULL;
-
-
-/* -------------------------------------------------------------------------- **
- * Functions...
- */
-
-
-/****************************************************************************
-utility lists registered debug class names's
-****************************************************************************/
-
-#define MAX_CLASS_NAME_SIZE 1024
-
-static char *debug_list_class_names_and_levels(void)
-{
- int i, dim;
- char **list;
- char *buf = NULL;
- char *b;
- BOOL err = False;
-
- if (DEBUGLEVEL_CLASS == &debug_all_class_hack)
- return NULL;
-
- list = calloc(debug_num_classes + 1, sizeof(char *));
- if (!list)
- return NULL;
-
- /* prepare strings */
- for (i = 0, dim = 0; i < debug_num_classes; i++) {
- int l = asprintf(&list[i],
- "%s:%d ",
- classname_table[i],
- DEBUGLEVEL_CLASS_ISSET[i]?DEBUGLEVEL_CLASS[i]:DEBUGLEVEL);
- if (l < 0 || l > MAX_CLASS_NAME_SIZE) {
- err = True;
- goto done;
- }
- dim += l;
- }
-
- /* create single string list */
- b = buf = malloc(dim);
- if (!buf) {
- err = True;
- goto done;
- }
- for (i = 0; i < debug_num_classes; i++) {
- int l = strlen(list[i]);
- strncpy(b, list[i], l);
- b = b + l;
- }
- b[-1] = '\0';
-
-done:
- /* free strings list */
- for (i = 0; i < debug_num_classes; i++)
- if (list[i]) free(list[i]);
- free(list);
-
- if (err) {
- if (buf)
- free(buf);
- return NULL;
- } else {
- return buf;
- }
-}
-
-/****************************************************************************
-utility access to debug class names's
-****************************************************************************/
-const char *debug_classname_from_index(int ndx)
-{
- if (ndx < 0 || ndx >= debug_num_classes)
- return NULL;
- else
- return classname_table[ndx];
-}
-
-/****************************************************************************
-utility to translate names to debug class index's (internal version)
-****************************************************************************/
-static int debug_lookup_classname_int(const char* classname)
+ 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, ...)
{
- int i;
+ va_list ap;
+ char *s = NULL;
- if (!classname) return -1;
-
- for (i=0; i < debug_num_classes; i++) {
- if (strcmp(classname, classname_table[i])==0)
- return i;
+ if (state.fd == 0) {
+ reopen_logs();
}
- return -1;
-}
-/****************************************************************************
-Add a new debug class to the system
-****************************************************************************/
-int debug_add_class(const char *classname)
-{
- int ndx;
- void *new_ptr;
-
- if (!classname)
- return -1;
-
- /* check the init has yet been called */
- debug_init();
+ if (state.fd <= 0) return;
- ndx = debug_lookup_classname_int(classname);
- if (ndx >= 0)
- return ndx;
- ndx = debug_num_classes;
-
- new_ptr = DEBUGLEVEL_CLASS;
- if (DEBUGLEVEL_CLASS == &debug_all_class_hack)
- {
- /* Initial loading... */
- new_ptr = NULL;
- }
- new_ptr = Realloc(new_ptr,
- sizeof(int) * (debug_num_classes + 1));
- if (!new_ptr)
- return -1;
- DEBUGLEVEL_CLASS = new_ptr;
- DEBUGLEVEL_CLASS[ndx] = 0;
+ va_start(ap, format);
+ vasprintf(&s, format, ap);
+ va_end(ap);
- /* debug_level is the pointer used for the DEBUGLEVEL-thingy */
- if (ndx==0)
- {
- /* Transfer the initial level from debug_all_class_hack */
- DEBUGLEVEL_CLASS[ndx] = DEBUGLEVEL;
- }
- debug_level = DEBUGLEVEL_CLASS;
-
- new_ptr = DEBUGLEVEL_CLASS_ISSET;
- if (new_ptr == &debug_all_class_isset_hack)
- {
- new_ptr = NULL;
- }
- new_ptr = Realloc(new_ptr,
- sizeof(BOOL) * (debug_num_classes + 1));
- if (!new_ptr)
- return -1;
- DEBUGLEVEL_CLASS_ISSET = new_ptr;
- DEBUGLEVEL_CLASS_ISSET[ndx] = False;
-
- new_ptr = Realloc(classname_table,
- sizeof(char *) * (debug_num_classes + 1));
- if (!new_ptr)
- return -1;
- classname_table = new_ptr;
-
- classname_table[ndx] = strdup(classname);
- if (! classname_table[ndx])
- return -1;
+ log_task_id();
- debug_num_classes++;
-
- return ndx;
+ write(state.fd, s, strlen(s));
+ free(s);
}
-/****************************************************************************
-utility to translate names to debug class index's (public version)
-****************************************************************************/
-int debug_lookup_classname(const char *classname)
-{
- int ndx;
-
- if (!classname || !*classname) return -1;
-
- ndx = debug_lookup_classname_int(classname);
-
- if (ndx != -1)
- return ndx;
-
- if (debug_warn_unknown_class)
- {
- DEBUG(0, ("debug_lookup_classname(%s): Unknown class\n",
- classname));
- }
- if (debug_auto_add_unknown_class)
- {
- return debug_add_class(classname);
- }
- return -1;
-}
-
-
-/****************************************************************************
-dump the current registered debug levels
-****************************************************************************/
-static void debug_dump_status(int level)
+/*
+ reopen the log file (usually called because the log file name might have changed)
+*/
+void reopen_logs(void)
{
- int q;
+ char *logfile = lp_logfile();
+ char *fname = NULL;
+ int old_fd = state.fd;
- DEBUG(level, ("INFO: Current debug levels:\n"));
- for (q = 0; q < debug_num_classes; q++)
- {
- DEBUGADD(level, (" %s: %s/%d\n",
- classname_table[q],
- (DEBUGLEVEL_CLASS_ISSET[q]
- ? "True" : "False"),
- DEBUGLEVEL_CLASS[q]));
- }
-}
-
-/****************************************************************************
-parse the debug levels from smbcontrol. Example debug level parameter:
- printdrivers:7
-****************************************************************************/
-static BOOL debug_parse_params(char **params)
-{
- int i, ndx;
- char *class_name;
- char *class_level;
+ state.fd = 0;
- if (!params)
- return False;
+ switch (state.logtype) {
+ case DEBUG_STDOUT:
+ state.fd = 1;
+ break;
- /* Allow DBGC_ALL to be specified w/o requiring its class name e.g."10"
- * v.s. "all:10", this is the traditional way to set DEBUGLEVEL
- */
- if (isdigit((int)params[0][0])) {
- DEBUGLEVEL_CLASS[DBGC_ALL] = atoi(params[0]);
- DEBUGLEVEL_CLASS_ISSET[DBGC_ALL] = True;
- i = 1; /* start processing at the next params */
- }
- else
- i = 0; /* DBGC_ALL not specified OR class name was included */
+ case DEBUG_STDERR:
+ state.fd = 2;
+ break;
- /* Fill in new debug class levels */
- for (; i < debug_num_classes && params[i]; i++) {
- if ((class_name=strtok(params[i],":")) &&
- (class_level=strtok(NULL, "\0")) &&
- ((ndx = debug_lookup_classname(class_name)) != -1)) {
- DEBUGLEVEL_CLASS[ndx] = atoi(class_level);
- DEBUGLEVEL_CLASS_ISSET[ndx] = True;
+ case DEBUG_FILE:
+ if ((*logfile) == '/') {
+ fname = strdup(logfile);
} else {
- DEBUG(0,("debug_parse_params: unrecognized debug class name or format [%s]\n", params[i]));
- return False;
+ asprintf(&fname, "%s/%s.log", dyn_LOGFILEBASE, logfile);
+ }
+ if (fname) {
+ state.fd = open(fname, O_CREAT|O_APPEND|O_WRONLY, 0644);
+ free(fname);
}
+ break;
}
- return True;
-}
-
-/****************************************************************************
-parse the debug levels from smb.conf. Example debug level string:
- 3 tdb:5 printdrivers:7
-Note: the 1st param has no "name:" preceeding it.
-****************************************************************************/
-BOOL debug_parse_levels(const char *params_str)
-{
- char **params;
-
- /* Just in case */
- debug_init();
-
- if (AllowDebugChange == False)
- return True;
-
- params = str_list_make(params_str, NULL);
-
- if (debug_parse_params(params))
- {
- debug_dump_status(5);
- str_list_free(&params);
- return True;
- } else {
- str_list_free(&params);
- return False;
+ if (old_fd > 2) {
+ close(old_fd);
}
}
-/****************************************************************************
-receive a "set debug level" message
-****************************************************************************/
-static void debug_message(int msg_type, pid_t src, void *buf, size_t len)
+/*
+ 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)
{
- const char *params_str = buf;
-
- /* Check, it's a proper string! */
- if (params_str[len-1] != '\0')
- {
- DEBUG(1, ("Invalid debug message from pid %u to pid %u\n",
- (unsigned int)src, (unsigned int)getpid()));
- return;
- }
-
- DEBUG(3, ("INFO: Remote set of debug to `%s' (pid %u from pid %u)\n",
- params_str, (unsigned int)getpid(), (unsigned int)src));
-
- debug_parse_levels(params_str);
+ state.logtype = new_logtype;
+ state.prog_name = prog_name;
+ reopen_logs();
}
-
-/****************************************************************************
-send a "set debug level" message
-****************************************************************************/
-void debug_message_send(pid_t pid, const char *params_str)
+/*
+ return a string constant containing n tabs
+ no more than 10 tabs are returned
+*/
+const char *do_debug_tab(uint_t n)
{
- if (!params_str)
- return;
- message_send_pid(pid, MSG_DEBUG, params_str, strlen(params_str) + 1,
- False);
+ 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)];
}
-/****************************************************************************
- Return current debug level.
-****************************************************************************/
-
-static void debuglevel_message(int msg_type, pid_t src, void *buf, size_t len)
-{
- char *message = debug_list_class_names_and_levels();
-
- DEBUG(1,("INFO: Received REQ_DEBUGLEVEL message from PID %u\n",(unsigned int)src));
- message_send_pid(src, MSG_DEBUGLEVEL, message, strlen(message) + 1, True);
- SAFE_FREE(message);
-}
-
-/****************************************************************************
-Init debugging (one time stuff)
-****************************************************************************/
-void debug_init(void)
+/*
+ log/print suspicious usage - print comments and backtrace
+*/
+void log_suspicious_usage(const char *from, const char *info)
{
- static BOOL initialised = False;
- const char **p;
-
- if (initialised)
- return;
-
- initialised = True;
-
- message_register(MSG_DEBUG, debug_message);
- message_register(MSG_REQ_DEBUGLEVEL, debuglevel_message);
-
- for(p = default_classname_table; *p; p++)
- {
- debug_add_class(*p);
+ if (debug_handlers.ops.log_suspicious_usage) {
+ debug_handlers.ops.log_suspicious_usage(from, info);
}
}
-
-
-/* ************************************************************************** **
- * get ready for syslog stuff
- * ************************************************************************** **
- */
-void setup_logging(const char *pname, BOOL interactive)
-{
- debug_init();
-
- /* reset to allow multiple setup calls, going from interactive to
- non-interactive */
- stdout_logging = False;
- dbf = NULL;
-
- if (interactive) {
- stdout_logging = True;
- dbf = x_stdout;
- x_setbuf( x_stdout, NULL );
- }
-#ifdef WITH_SYSLOG
- else {
- const char *p = strrchr_m( pname,'/' );
- if (p)
- pname = p + 1;
-#ifdef LOG_DAEMON
- openlog( pname, LOG_PID, SYSLOG_FACILITY );
-#else
- /* for old systems that have no facility codes. */
- openlog( pname, LOG_PID );
-#endif
- }
-#endif
-} /* setup_logging */
-
-/* ************************************************************************** **
- * reopen the log files
- * note that we now do this unconditionally
- * We attempt to open the new debug fp before closing the old. This means
- * if we run out of fd's we just keep using the old fd rather than aborting.
- * Fix from dgibson@linuxcare.com.
- * ************************************************************************** **
- */
-
-BOOL reopen_logs( void )
+void print_suspicious_usage(const char* from, const char* info)
{
- pstring fname;
- mode_t oldumask;
- XFILE *new_dbf = NULL;
- XFILE *old_dbf = NULL;
- BOOL ret = True;
-
- if (stdout_logging)
- return True;
-
- oldumask = umask( 022 );
-
- pstrcpy(fname, debugf );
-
- if (lp_loaded()) {
- char *logfname;
-
- logfname = lp_logfile();
- if (*logfname)
- pstrcpy(fname, logfname);
+ if (debug_handlers.ops.print_suspicious_usage) {
+ debug_handlers.ops.print_suspicious_usage(from, info);
}
-
- pstrcpy( debugf, fname );
- new_dbf = x_fopen( debugf, O_WRONLY|O_APPEND|O_CREAT, 0644);
-
- if (!new_dbf) {
- log_overflow = True;
- DEBUG(0, ("Unable to open new log file %s: %s\n", debugf, strerror(errno)));
- log_overflow = False;
- if (dbf)
- x_fflush(dbf);
- ret = False;
- } else {
- x_setbuf(new_dbf, NULL);
- old_dbf = dbf;
- dbf = new_dbf;
- if (old_dbf)
- (void) x_fclose(old_dbf);
- }
-
- /* Fix from klausr@ITAP.Physik.Uni-Stuttgart.De
- * to fix problem where smbd's that generate less
- * than 100 messages keep growing the log.
- */
- force_check_log_size();
- (void)umask(oldumask);
-
- /* Take over stderr to catch ouput into logs */
- if (dbf && sys_dup2(x_fileno(dbf), 2) == -1) {
- close_low_fds(True); /* Close stderr too, if dup2 can't point it
- at the logfile */
- }
-
- return ret;
}
-/* ************************************************************************** **
- * Force a check of the log size.
- * ************************************************************************** **
- */
-void force_check_log_size( void )
+uint32 get_task_id(void)
{
- debug_count = 100;
-}
-
-/***************************************************************************
- Check to see if there is any need to check if the logfile has grown too big.
-**************************************************************************/
-
-BOOL need_to_check_log_size( void )
-{
- int maxlog;
-
- if( debug_count < 100 )
- return( False );
-
- maxlog = lp_max_log_size() * 1024;
- if( !dbf || maxlog <= 0 ) {
- debug_count = 0;
- return(False);
+ if (debug_handlers.ops.get_task_id) {
+ return debug_handlers.ops.get_task_id();
}
- return( True );
+ return getpid();
}
-/* ************************************************************************** **
- * Check to see if the log has grown to be too big.
- * ************************************************************************** **
- */
-
-void check_log_size( void )
+void log_task_id(void)
{
- int maxlog;
- SMB_STRUCT_STAT st;
-
- /*
- * We need to be root to check/change log-file, skip this and let the main
- * loop check do a new check as root.
- */
-
- if( geteuid() != 0 )
- return;
-
- if(log_overflow || !need_to_check_log_size() )
- return;
-
- maxlog = lp_max_log_size() * 1024;
-
- if( sys_fstat( x_fileno( dbf ), &st ) == 0 && st.st_size > maxlog ) {
- (void)reopen_logs();
- if( dbf && get_file_size( debugf ) > maxlog ) {
- pstring name;
-
- slprintf( name, sizeof(name)-1, "%s.old", debugf );
- (void)rename( debugf, name );
-
- if (!reopen_logs()) {
- /* We failed to reopen a log - continue using the old name. */
- (void)rename(name, debugf);
- }
- }
+ if (debug_handlers.ops.log_task_id) {
+ debug_handlers.ops.log_task_id(state.fd);
}
-
- /*
- * Here's where we need to panic if dbf == NULL..
- */
-
- if(dbf == NULL) {
- /* This code should only be reached in very strange
- * circumstances. If we merely fail to open the new log we
- * should stick with the old one. ergo this should only be
- * reached when opening the logs for the first time: at
- * startup or when the log level is increased from zero.
- * -dwg 6 June 2000
- */
- dbf = x_fopen( "/dev/console", O_WRONLY, 0);
- if(dbf) {
- DEBUG(0,("check_log_size: open of debug file %s failed - using console.\n",
- debugf ));
- } else {
- /*
- * We cannot continue without a debug file handle.
- */
- abort();
- }
- }
- debug_count = 0;
-} /* check_log_size */
-
-/* ************************************************************************** **
- * Write an debug message on the debugfile.
- * This is called by dbghdr() and format_debug_text().
- * ************************************************************************** **
- */
- int Debug1( const char *format_str, ... )
-{
- va_list ap;
- int old_errno = errno;
-
- debug_count++;
-
- if( stdout_logging )
- {
- va_start( ap, format_str );
- if(dbf)
- (void)x_vfprintf( dbf, format_str, ap );
- va_end( ap );
- errno = old_errno;
- return( 0 );
- }
-
-#ifdef WITH_SYSLOG
- if( !lp_syslog_only() )
-#endif
- {
- if( !dbf )
- {
- mode_t oldumask = umask( 022 );
-
- dbf = x_fopen( debugf, O_WRONLY|O_APPEND|O_CREAT, 0644 );
- (void)umask( oldumask );
- if( dbf )
- {
- x_setbuf( dbf, NULL );
- }
- else
- {
- errno = old_errno;
- return(0);
- }
- }
- }
-
-#ifdef WITH_SYSLOG
- if( syslog_level < lp_syslog() )
- {
- /* map debug levels to syslog() priorities
- * note that not all DEBUG(0, ...) calls are
- * necessarily errors
- */
- static int priority_map[] = {
- LOG_ERR, /* 0 */
- LOG_WARNING, /* 1 */
- LOG_NOTICE, /* 2 */
- LOG_INFO, /* 3 */
- };
- int priority;
- pstring msgbuf;
-
- if( syslog_level >= ( sizeof(priority_map) / sizeof(priority_map[0]) )
- || syslog_level < 0)
- priority = LOG_DEBUG;
- else
- priority = priority_map[syslog_level];
-
- va_start( ap, format_str );
- vslprintf( msgbuf, sizeof(msgbuf)-1, format_str, ap );
- va_end( ap );
-
- msgbuf[255] = '\0';
- syslog( priority, "%s", msgbuf );
- }
-#endif
-
- check_log_size();
-
-#ifdef WITH_SYSLOG
- if( !lp_syslog_only() )
-#endif
- {
- va_start( ap, format_str );
- if(dbf)
- (void)x_vfprintf( dbf, format_str, ap );
- va_end( ap );
- if(dbf)
- (void)x_fflush( dbf );
- }
-
- errno = old_errno;
-
- return( 0 );
- } /* Debug1 */
-
-
-/* ************************************************************************** **
- * Print the buffer content via Debug1(), then reset the buffer.
- *
- * Input: none
- * Output: none
- *
- * ************************************************************************** **
- */
-static void bufr_print( void )
- {
- format_bufr[format_pos] = '\0';
- (void)Debug1( "%s", format_bufr );
- format_pos = 0;
- } /* bufr_print */
-
-/* ************************************************************************** **
- * Format the debug message text.
- *
- * Input: msg - Text to be added to the "current" debug message text.
- *
- * Output: none.
- *
- * Notes: The purpose of this is two-fold. First, each call to syslog()
- * (used by Debug1(), see above) generates a new line of syslog
- * output. This is fixed by storing the partial lines until the
- * newline character is encountered. Second, printing the debug
- * message lines when a newline is encountered allows us to add
- * spaces, thus indenting the body of the message and making it
- * more readable.
- *
- * ************************************************************************** **
- */
-static void format_debug_text( char *msg )
- {
- size_t i;
- BOOL timestamp = (!stdout_logging && (lp_timestamp_logs() ||
- !(lp_loaded())));
-
- for( i = 0; msg[i]; i++ )
- {
- /* Indent two spaces at each new line. */
- if(timestamp && 0 == format_pos)
- {
- format_bufr[0] = format_bufr[1] = ' ';
- format_pos = 2;
- }
-
- /* If there's room, copy the character to the format buffer. */
- if( format_pos < FORMAT_BUFR_MAX )
- format_bufr[format_pos++] = msg[i];
-
- /* If a newline is encountered, print & restart. */
- if( '\n' == msg[i] )
- bufr_print();
-
- /* If the buffer is full dump it out, reset it, and put out a line
- * continuation indicator.
- */
- if( format_pos >= FORMAT_BUFR_MAX )
- {
- bufr_print();
- (void)Debug1( " +>\n" );
- }
- }
-
- /* Just to be safe... */
- format_bufr[format_pos] = '\0';
- } /* format_debug_text */
-
-/* ************************************************************************** **
- * Flush debug output, including the format buffer content.
- *
- * Input: none
- * Output: none
- *
- * ************************************************************************** **
- */
-void dbgflush( void )
- {
- bufr_print();
- if(dbf)
- (void)x_fflush( dbf );
- } /* dbgflush */
-
-/* ************************************************************************** **
- * Print a Debug Header.
- *
- * Input: level - Debug level of the message (not the system-wide debug
- * level. )
- * file - Pointer to a string containing the name of the file
- * from which this function was called, or an empty string
- * if the __FILE__ macro is not implemented.
- * func - Pointer to a string containing the name of the function
- * from which this function was called, or an empty string
- * if the __FUNCTION__ macro is not implemented.
- * line - line number of the call to dbghdr, assuming __LINE__
- * works.
- *
- * Output: Always True. This makes it easy to fudge a call to dbghdr()
- * in a macro, since the function can be called as part of a test.
- * Eg: ( (level <= DEBUGLEVEL) && (dbghdr(level,"",line)) )
- *
- * Notes: This function takes care of setting syslog_level.
- *
- * ************************************************************************** **
- */
-
-BOOL dbghdr( int level, const char *file, const char *func, int line )
+}
+/*
+ register a set of debug handlers.
+*/
+void register_debug_handlers(const char *name, struct debug_ops *ops)
{
- /* Ensure we don't lose any real errno value. */
- int old_errno = errno;
-
- if( format_pos ) {
- /* This is a fudge. If there is stuff sitting in the format_bufr, then
- * the *right* thing to do is to call
- * format_debug_text( "\n" );
- * to write the remainder, and then proceed with the new header.
- * Unfortunately, there are several places in the code at which
- * the DEBUG() macro is used to build partial lines. That in mind,
- * we'll work under the assumption that an incomplete line indicates
- * that a new header is *not* desired.
- */
- return( True );
- }
-
-#ifdef WITH_SYSLOG
- /* Set syslog_level. */
- syslog_level = level;
-#endif
-
- /* Don't print a header if we're logging to stdout. */
- if( stdout_logging )
- return( True );
-
- /* Print the header if timestamps are turned on. If parameters are
- * not yet loaded, then default to timestamps on.
- */
- if( lp_timestamp_logs() || !(lp_loaded()) ) {
- char header_str[200];
-
- header_str[0] = '\0';
-
- if( lp_debug_pid())
- slprintf(header_str,sizeof(header_str)-1,", pid=%u",(unsigned int)sys_getpid());
-
- if( lp_debug_uid()) {
- size_t hs_len = strlen(header_str);
- slprintf(header_str + hs_len,
- sizeof(header_str) - 1 - hs_len,
- ", effective(%u, %u), real(%u, %u)",
- (unsigned int)geteuid(), (unsigned int)getegid(),
- (unsigned int)getuid(), (unsigned int)getgid());
- }
-
- /* Print it all out at once to prevent split syslog output. */
- (void)Debug1( "[%s, %d%s] %s:%s(%d)\n",
- timestring(lp_debug_hires_timestamp()), level,
- header_str, file, func, line );
- }
-
- errno = old_errno;
- return( True );
+ debug_handlers.name = name;
+ debug_handlers.ops = *ops;
}
-
-/* ************************************************************************** **
- * Add text to the body of the "current" debug message via the format buffer.
- *
- * Input: format_str - Format string, as used in printf(), et. al.
- * ... - Variable argument list.
- *
- * ..or.. va_alist - Old style variable parameter list starting point.
- *
- * Output: Always True. See dbghdr() for more info, though this is not
- * likely to be used in the same way.
- *
- * ************************************************************************** **
- */
- BOOL dbgtext( const char *format_str, ... )
- {
- va_list ap;
- pstring msgbuf;
-
- va_start( ap, format_str );
- vslprintf( msgbuf, sizeof(msgbuf)-1, format_str, ap );
- va_end( ap );
-
- format_debug_text( msgbuf );
-
- return( True );
- } /* dbgtext */
-
-
-/* ************************************************************************** */
diff --git a/source/lib/dprintf.c b/source/lib/dprintf.c
index c62a1f41d10..70387bbd618 100644
--- a/source/lib/dprintf.c
+++ b/source/lib/dprintf.c
@@ -59,7 +59,7 @@ again:
SAFE_FREE(p);
return -1;
}
- clen = convert_string(CH_UNIX, CH_DISPLAY, p, ret, p2, maxlen, True);
+ clen = convert_string(CH_UNIX, CH_DISPLAY, p, ret, p2, maxlen);
if (clen >= maxlen) {
/* it didn't fit - try a larger buffer */
diff --git a/source/lib/dummysmbd.c b/source/lib/dummysmbd.c
deleted file mode 100644
index 17bc3217743..00000000000
--- a/source/lib/dummysmbd.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
- RPC pipe client
-
- Copyright (C) Gerald (Jerry) Carter 2004.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/* Stupid dummy functions required due to the horrible dependency mess
- in Samba. */
-
-void decrement_smbd_process_count( void )
-{
- return;
-}
-
diff --git a/source/lib/events.c b/source/lib/events.c
new file mode 100644
index 00000000000..85a2cee70f6
--- /dev/null
+++ b/source/lib/events.c
@@ -0,0 +1,394 @@
+/*
+ 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 NULL on failure (memory allocation error)
+*/
+struct fd_event *event_add_fd(struct event_context *ev, struct fd_event *e)
+{
+ e = memdup(e, sizeof(*e));
+ if (!e) return NULL;
+ DLIST_ADD(ev->fd_events, e);
+ e->ref_count = 1;
+ if (e->fd > ev->maxfd) {
+ ev->maxfd = e->fd;
+ }
+ return e;
+}
+
+
+/*
+ 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;
+ }
+ }
+}
+
+/* to mark the ev->maxfd invalid
+ * this means we need to recalculate it
+ */
+#define EVENT_INVALID_MAXFD (-1)
+
+/*
+ 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--;
+ 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--;
+ }
+ }
+}
+
+/*
+ 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--;
+ }
+ }
+}
+
+
+/*
+ add a timed event
+ return NULL on failure (memory allocation error)
+*/
+struct timed_event *event_add_timed(struct event_context *ev, struct timed_event *e)
+{
+ e = memdup(e, sizeof(*e));
+ if (!e) return NULL;
+ e->ref_count = 1;
+ DLIST_ADD(ev->timed_events, e);
+ return e;
+}
+
+/*
+ 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 NULL on failure (memory allocation error)
+*/
+struct loop_event *event_add_loop(struct event_context *ev, struct loop_event *e)
+{
+ e = memdup(e, sizeof(*e));
+ if (!e) return NULL;
+ e->ref_count = 1;
+ DLIST_ADD(ev->loop_events, e);
+ return e;
+}
+
+/*
+ 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);
+ ev->maxfd = EVENT_INVALID_MAXFD;
+
+ 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);
+ if (ev->maxfd == fe->fd) {
+ ev->maxfd = EVENT_INVALID_MAXFD;
+ }
+ 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;
+ }
+ }
+
+ /* only do a select() if there're fd_events
+ * otherwise we would block for a the time in tval,
+ * and if there're no fd_events present anymore we want to
+ * leave the event loop directly
+ */
+ if (ev->fd_events) {
+ /* we maybe need to recalculate the maxfd */
+ if (ev->maxfd == EVENT_INVALID_MAXFD) {
+ calc_maxfd(ev);
+ }
+
+ /* TODO:
+ * we don't use sys_select() as it isn't thread
+ * safe. We need to replace the magic pipe handling in
+ * sys_select() with something in the events
+ * structure - for now just use select()
+ */
+ selrtn = 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;
+}
diff --git a/source/lib/fault.c b/source/lib/fault.c
index d8364ff2257..47a43bca840 100644
--- a/source/lib/fault.c
+++ b/source/lib/fault.c
@@ -22,22 +22,27 @@
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);
- counter++;
-
DEBUG(0,("===============================================================\n"));
- DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)sys_getpid(),SAMBA_VERSION_STRING));
- DEBUG(0,("\nPlease read the appendix Bugs of the Samba HOWTO collection\n"));
+ DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)getpid(),SAMBA_VERSION_STRING));
+ DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n"));
DEBUG(0,("===============================================================\n"));
-
+
smb_panic("internal error");
if (cont_fn) {
@@ -48,9 +53,6 @@ static void fault_report(int sig)
#ifdef SIGBUS
CatchSignal(SIGBUS,SIGNAL_CAST SIG_DFL);
#endif
-#ifdef SIGABRT
- CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
-#endif
return; /* this should cause a core dump */
}
exit(1);
@@ -61,6 +63,11 @@ 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);
}
@@ -77,7 +84,24 @@ void fault_setup(void (*fn)(void *))
#ifdef SIGBUS
CatchSignal(SIGBUS,SIGNAL_CAST sig_fault);
#endif
-#ifdef SIGABRT
- CatchSignal(SIGABRT,SIGNAL_CAST sig_fault);
-#endif
+}
+
+/*
+ register a fault handler.
+ Should only be called once in the execution of smbd.
+*/
+BOOL register_fault_handler(const char *name, void (*fault_handler)(int sig))
+{
+ if (fault_handlers.name != NULL) {
+ /* it's already registered! */
+ DEBUG(2,("fault handler '%s' already registered - failed '%s'\n",
+ fault_handlers.name, name));
+ return False;
+ }
+
+ fault_handlers.name = name;
+ fault_handlers.fault_handler = fault_handler;
+
+ DEBUG(2,("fault handler '%s' registered\n", name));
+ return True;
}
diff --git a/source/lib/gencache.c b/source/lib/gencache.c
index 39e727c24fa..f3740e3e127 100644
--- a/source/lib/gencache.c
+++ b/source/lib/gencache.c
@@ -121,11 +121,10 @@ BOOL gencache_set(const char *keystr, const char *value, time_t timeout)
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"));
-
+ 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);
@@ -357,9 +356,6 @@ void gencache_iterate(void (*fn)(const char* key, const char *value, time_t time
int gencache_lock_entry( const char *key )
{
- if (!gencache_init())
- return -1;
-
return tdb_lock_bystring(cache, key, 0);
}
@@ -369,9 +365,6 @@ int gencache_lock_entry( const char *key )
void gencache_unlock_entry( const char *key )
{
- if (!gencache_init())
- return;
-
tdb_unlock_bystring(cache, key);
return;
}
diff --git a/source/lib/genparser.c b/source/lib/genparser.c
index 7476b5d0aff..0f5d26620b2 100644
--- a/source/lib/genparser.c
+++ b/source/lib/genparser.c
@@ -22,17 +22,6 @@
#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)
{
@@ -46,7 +35,7 @@ static char *encode_bytes(TALLOC_CTX *mem_ctx, const char *ptr, unsigned len)
(ispunct(ptr[i]) && !strchr("\\{}", ptr[i]))) {
*p++ = ptr[i];
} else {
- unsigned char c = *(unsigned char *)(ptr+i);
+ 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];
@@ -202,7 +191,7 @@ int gen_dump_enum(TALLOC_CTX *mem_ctx,
const char *ptr,
unsigned indent)
{
- unsigned v = *(unsigned *)ptr;
+ unsigned v = *(const unsigned *)ptr;
int i;
for (i=0;einfo[i].name;i++) {
if (v == einfo[i].value) {
@@ -256,6 +245,7 @@ static int gen_dump_array(TALLOC_CTX *mem_ctx,
addstr(mem_ctx, p, "}\n")) {
return -1;
}
+ free(s);
return 0;
}
@@ -320,9 +310,9 @@ static int find_var(const struct parse_struct *pinfo,
switch (pinfo[i].size) {
case sizeof(int):
- return *(int *)ptr;
+ return *(const int *)ptr;
case sizeof(char):
- return *(char *)ptr;
+ return *(const char *)ptr;
}
return -1;
@@ -351,7 +341,7 @@ static int gen_dump_string(TALLOC_CTX *mem_ctx,
const char *data,
unsigned indent)
{
- const char *ptr = *(char **)data;
+ 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, " = ") ||
@@ -432,13 +422,13 @@ char *gen_dump(TALLOC_CTX *mem_ctx,
}
if (len > 0) {
if (pinfo[i].flags & FLAG_NULLTERM) {
- len = len_nullterm(*(char **)ptr,
+ 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,
- *(char **)ptr,
+ *(const char **)ptr,
len, indent) != 0) {
goto failed;
}
@@ -672,7 +662,7 @@ int gen_parse(TALLOC_CTX *mem_ctx, const struct parse_struct *pinfo, char *data,
{
char *str, *s0;
- s0 = talloc_strdup(mem_ctx, s);
+ s0 = strdup(s);
str = s0;
while (*str) {
@@ -705,10 +695,12 @@ int gen_parse(TALLOC_CTX *mem_ctx, const struct parse_struct *pinfo, char *data,
*str++ = 0;
if (gen_parse_one(mem_ctx, pinfo, name, data, value) != 0) {
+ free(s0);
return -1;
}
}
+ free(s0);
return 0;
}
diff --git a/source/lib/genparser_samba.c b/source/lib/genparser_samba.c
index 8f469a46d6a..bece5877473 100644
--- a/source/lib/genparser_samba.c
+++ b/source/lib/genparser_samba.c
@@ -63,7 +63,7 @@ int gen_parse_SEC_ACCESS(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
int gen_parse_GUID(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
{
- int info[UUID_FLAT_SIZE];
+ int info[GUID_SIZE];
int i;
char *sc;
char *p;
@@ -74,7 +74,7 @@ int gen_parse_GUID(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
sc = m;
memset(info, 0, sizeof(info));
- for (i = 0; i < UUID_FLAT_SIZE; i++) {
+ for (i = 0; i < GUID_SIZE; i++) {
p = strchr(sc, ',');
if (p != NULL) p = '\0';
info[i] = atoi(sc);
@@ -82,8 +82,8 @@ int gen_parse_GUID(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
}
free(m);
- for (i = 0; i < UUID_FLAT_SIZE; i++) {
- ((UUID_FLAT *)ptr)->info[i] = info[i];
+ for (i = 0; i < GUID_SIZE; i++) {
+ ((GUID *)ptr)->info[i] = info[i];
}
return 0;
@@ -118,16 +118,7 @@ int gen_parse_LUID(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
return 0;
}
-int gen_parse_DATA_BLOB(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
-{
- return gen_parse_struct(mem_ctx, pinfo_data_blob_info, ptr, str);
-}
-int gen_parse_TALLOC_CTX(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
-{
- (TALLOC_CTX *)ptr = NULL;
- return 0;
-}
/* DUMP functions */
@@ -172,10 +163,10 @@ int gen_dump_GUID(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr,
{
int i, r;
- for (i = 0; i < (UUID_FLAT_SIZE - 1); i++) {
- if (!(r = addshort(mem_ctx, p, "%d,", ((UUID_FLAT *)ptr)->info[i]))) return 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", ((UUID_FLAT *)ptr)->info[i]);
+ 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)
@@ -207,12 +198,3 @@ int gen_dump_LUID(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr,
return addshort(mem_ctx, p, "%u,%u", high, low);
}
-int gen_dump_DATA_BLOB(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
-{
- return gen_dump_struct(mem_ctx, pinfo_data_blob_info, p, ptr, indent);
-}
-
-int gen_dump_TALLOC_CTX(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
-{
- return addshort(mem_ctx, p, "TALLOC_CTX");
-}
diff --git a/source/lib/genrand.c b/source/lib/genrand.c
index bc9f21c6403..e2e66f7e580 100644
--- a/source/lib/genrand.c
+++ b/source/lib/genrand.c
@@ -172,7 +172,7 @@ static int do_reseed(BOOL use_fd, int fd)
*/
GetTimeOfDay(&tval);
- mypid = sys_getpid();
+ mypid = getpid();
v1 = (counter++) + mypid + tval.tv_sec;
v2 = (counter++) * mypid + tval.tv_usec;
diff --git a/source/lib/getsmbpass.c b/source/lib/getsmbpass.c
index df5e0359aa2..b6ae09b3181 100644
--- a/source/lib/getsmbpass.c
+++ b/source/lib/getsmbpass.c
@@ -83,96 +83,71 @@ static int tcsetattr(int fd, int flags, struct sgttyb *t)
static struct termios t;
#endif /* SYSV_TERMIO */
-static SIG_ATOMIC_T gotintr;
-static int in_fd = -1;
-
-/***************************************************************
- Signal function to tell us were ^C'ed.
-****************************************************************/
-
-static void gotintr_sig(void)
-{
- gotintr = 1;
- if (in_fd != -1)
- close(in_fd); /* Safe way to force a return. */
- in_fd = -1;
-}
-
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 gotintr_sig);
-
- /* 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;
- if (!gotintr) {
- in_fd = fileno(in);
- fgets(buf, bufsize, in);
- }
- nread = strlen(buf);
- if (buf[nread - 1] == '\n')
- buf[nread - 1] = '\0';
-
- /* Restore echoing. */
- if (echo_off) {
- if (gotintr && in_fd == -1)
- in = fopen ("/dev/tty", "w+");
- if (in != NULL)
- tcsetattr (fileno (in), TCSANOW, &t);
- }
-
- fprintf(out, "\n");
- fflush(out);
-
- if (in != stdin) /* We opened the terminal; now close it. */
- fclose(in);
-
- /* Catch problematic signals */
- CatchSignal(SIGINT, SIGNAL_CAST SIG_DFL);
-
- if (gotintr) {
- printf("Interupted by signal.\n");
- fflush(stdout);
- exit(1);
+ 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);
}
- return buf;
+ 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
diff --git a/source/lib/hash.c b/source/lib/hash.c
deleted file mode 100644
index 18b6534dec2..00000000000
--- a/source/lib/hash.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
-
- Copyright (C) Ying Chen 2000.
- Copyright (C) Jeremy Allison 2000.
- - added some defensive programming.
-
- 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.
-*/
-
-/*
- * NB. We may end up replacing this functionality in a future 2.x
- * release to reduce the number of hashing/lookup methods we support. JRA.
- */
-
-#include "includes.h"
-
-static BOOL enlarge_hash_table(hash_table *table);
-static unsigned primes[] =
- {17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, 16411};
-
-/****************************************************************************
- * This function initializes the hash table.
- * This hash function hashes on string keys.
- * This number of hash buckets is always rounded up to a power of
- * 2 first, then to a prime number that is large than the power of two.
- * Input:
- * table -- the hash table pointer.
- * num_buckets -- the number of buckets to be allocated. This
- * hash function can dynamically increase its size when the
- * the hash table size becomes small. There is a MAX hash table
- * size defined in hash.h.
- * compare_func -- the function pointer to a comparison function
- * used by the hash key comparison.
- ****************************************************************************
- */
-
-BOOL hash_table_init(hash_table *table, unsigned num_buckets, compare_function compare_func)
-{
- unsigned i;
- ubi_dlList *bucket;
-
- table->num_elements = 0;
- table->size = 2;
- table->comp_func = compare_func;
- while (table->size < num_buckets)
- table->size <<= 1;
- for (i = 0; i < ARRAY_SIZE(primes); i++) {
- if (primes[i] > table->size) {
- table->size = primes[i];
- break;
- }
- }
-
- DEBUG(5, ("Hash size = %d.\n", table->size));
-
- if(!(table->buckets = (ubi_dlList *) malloc(sizeof(ubi_dlList) * table->size))) {
- DEBUG(0,("hash_table_init: malloc fail !\n"));
- return False;
- }
- ubi_dlInitList(&(table->lru_chain));
- for (i=0, bucket = table->buckets; i < table->size; i++, bucket++)
- ubi_dlInitList(bucket);
-
- return True;
-}
-
-/*
- **************************************************************
- * Compute a hash value based on a string key value.
- * Make the string key into an array of int's if possible.
- * For the last few chars that cannot be int'ed, use char instead.
- * The function returns the bucket index number for the hashed
- * key.
- * JRA. Use a djb-algorithm hash for speed.
- **************************************************************
- */
-
-static int string_hash(int hash_size, const char *key)
-{
- u32 n = 0;
- const char *p;
- for (p = key; *p != '\0'; p++) {
- n = ((n << 5) + n) ^ (u32)(*p);
- }
- return (n % hash_size);
-}
-
-/* *************************************************************************
- * Search the hash table for the entry in the hash chain.
- * The function returns the pointer to the
- * element found in the chain or NULL if none is found.
- * If the element is found, the element is also moved to
- * the head of the LRU list.
- *
- * Input:
- * table -- The hash table where the element is stored in.
- * hash_chain -- The pointer to the bucket that stores the
- * element to be found.
- * key -- The hash key to be found.
- ***************************************************************************
- */
-
-static hash_element *hash_chain_find(hash_table *table, ubi_dlList *hash_chain, char *key)
-{
- hash_element *hash_elem;
- ubi_dlNodePtr lru_item;
- unsigned int i = 0;
-
- for (hash_elem = (hash_element *)(ubi_dlFirst(hash_chain)); i < hash_chain->count;
- i++, hash_elem = (hash_element *)(ubi_dlNext(hash_elem))) {
- if ((table->comp_func)(hash_elem->key, key) == 0) {
- /* Move to the head of the lru List. */
- lru_item = ubi_dlRemove(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
- ubi_dlAddHead(&(table->lru_chain), lru_item);
- return(hash_elem);
- }
- }
- return ((hash_element *) NULL);
-}
-
-/* ***************************************************************************
- *
- * Lookup a hash table for an element with key.
- * The function returns a pointer to the hash element.
- * If no element is found, the function returns NULL.
- *
- * Input:
- * table -- The hash table to be searched on.
- * key -- The key to be found.
- *****************************************************************************
- */
-
-hash_element *hash_lookup(hash_table *table, char *key)
-{
- return (hash_chain_find(table, &table->buckets[string_hash(table->size, key)], key));
-}
-
-/* ***************************************************************
- *
- * This function first checks if an element with key "key"
- * exists in the hash table. If so, the function moves the
- * element to the front of the LRU list. Otherwise, a new
- * hash element corresponding to "value" and "key" is allocated
- * and inserted into the hash table. The new elements are
- * always inserted in the LRU order to the LRU list as well.
- *
- * Input:
- * table -- The hash table to be inserted in.
- * value -- The content of the element to be inserted.
- * key -- The key of the new element to be inserted.
- *
- ****************************************************************
- */
-
-hash_element *hash_insert(hash_table *table, char *value, char *key)
-{
- hash_element *hash_elem;
- ubi_dlNodePtr lru_item;
- ubi_dlList *bucket;
- size_t string_length;
-
- /*
- * If the hash table size has not reached the MAX_HASH_TABLE_SIZE,
- * the hash table may be enlarged if the current hash table is full.
- * If the hash table size has reached the MAX_HASH_TABLE_SIZE,
- * use LRU to remove the oldest element from the hash table.
- */
-
- if ((table->num_elements >= table->size) &&
- (table->num_elements < MAX_HASH_TABLE_SIZE)) {
- if(!enlarge_hash_table(table))
- return (hash_element *)NULL;
- table->num_elements += 1;
- } else if (table->num_elements >= MAX_HASH_TABLE_SIZE) {
- /* Do an LRU replacement. */
- lru_item = ubi_dlLast(&(table->lru_chain));
- hash_elem = (hash_element *)(((lru_node *)lru_item)->hash_elem);
- bucket = hash_elem->bucket;
- ubi_dlRemThis(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
- ubi_dlRemThis(bucket, (ubi_dlNodePtr)hash_elem);
- SAFE_FREE(hash_elem->value);
- SAFE_FREE(hash_elem);
- } else {
- table->num_elements += 1;
- }
-
- bucket = &table->buckets[string_hash(table->size, key)];
-
- /* Since we only have 1-byte for the key string, we need to
- * allocate extra space in the hash_element to store the entire key
- * string.
- */
-
- string_length = strlen(key);
- if(!(hash_elem = (hash_element *) malloc(sizeof(hash_element) + string_length))) {
- DEBUG(0,("hash_insert: malloc fail !\n"));
- return (hash_element *)NULL;
- }
-
- safe_strcpy((char *) hash_elem->key, key, string_length);
-
- hash_elem->value = (char *)value;
- hash_elem->bucket = bucket;
- /* Insert in front of the lru list and the bucket list. */
- ubi_dlAddHead(bucket, hash_elem);
- hash_elem->lru_link.hash_elem = hash_elem;
- ubi_dlAddHead(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
-
- return(hash_elem);
-}
-
-/* **************************************************************************
- *
- * Remove a hash element from the hash table. The hash element is
- * removed from both the LRU list and the hash bucket chain.
- *
- * Input:
- * table -- the hash table to be manipulated on.
- * hash_elem -- the element to be removed.
- **************************************************************************
- */
-
-void hash_remove(hash_table *table, hash_element *hash_elem)
-{
- if (hash_elem) {
- ubi_dlRemove(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
- ubi_dlRemove(hash_elem->bucket, (ubi_dlNodePtr) hash_elem);
- SAFE_FREE(hash_elem->value);
- SAFE_FREE(hash_elem);
- table->num_elements--;
- }
-}
-
-/* ******************************************************************
- * Increase the hash table size if it is too small.
- * The hash table size is increased by the HASH_TABLE_INCREMENT
- * ratio.
- * Input:
- * table -- the hash table to be enlarged.
- ******************************************************************
- */
-
-static BOOL enlarge_hash_table(hash_table *table)
-{
- hash_element *hash_elem;
- int size, hash_value;
- ubi_dlList *buckets;
- ubi_dlList *old_bucket;
- ubi_dlList *bucket;
- ubi_dlList lru_chain;
-
- buckets = table->buckets;
- lru_chain = table->lru_chain;
- size = table->size;
-
- /* Reinitialize the hash table. */
- if(!hash_table_init(table, table->size * HASH_TABLE_INCREMENT, table->comp_func))
- return False;
-
- for (old_bucket = buckets; size > 0; size--, old_bucket++) {
- while (old_bucket->count != 0) {
- hash_elem = (hash_element *) ubi_dlRemHead(old_bucket);
- ubi_dlRemove(&lru_chain, &(hash_elem->lru_link.lru_link));
- hash_value = string_hash(table->size, (char *) hash_elem->key);
- bucket = &(table->buckets[hash_value]);
- ubi_dlAddHead(bucket, hash_elem);
- ubi_dlAddHead(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
- hash_elem->bucket = bucket;
- hash_elem->lru_link.hash_elem = hash_elem;
- table->num_elements++;
- }
- }
- SAFE_FREE(buckets);
-
- return True;
-}
-
-/* **********************************************************************
- *
- * Remove everything from a hash table and free up the memory it
- * occupies.
- * Input:
- * table -- the hash table to be cleared.
- *
- *************************************************************************
- */
-
-void hash_clear(hash_table *table)
-{
- unsigned int i;
- ubi_dlList *bucket = table->buckets;
- hash_element *hash_elem;
- for (i = 0; i < table->size; bucket++, i++) {
- while (bucket->count != 0) {
- hash_elem = (hash_element *) ubi_dlRemHead(bucket);
- SAFE_FREE(hash_elem->value);
- SAFE_FREE(hash_elem);
- }
- }
- table->size = 0;
- SAFE_FREE(table->buckets);
- table->buckets = NULL;
-}
diff --git a/source/lib/iconv.c b/source/lib/iconv.c
index 7df73192f24..3f37583e393 100644
--- a/source/lib/iconv.c
+++ b/source/lib/iconv.c
@@ -2,7 +2,7 @@
Unix SMB/CIFS implementation.
minimal iconv implementation
Copyright (C) Andrew Tridgell 2001
- Copyright (C) Jelmer Vernooij 2002,2003
+ 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
@@ -21,12 +21,6 @@
#include "includes.h"
-/*
- * We have to use strcasecmp here as the character conversions
- * haven't been initialised yet. JRA.
- */
-
-#undef strcasecmp
/**
* @file
@@ -51,54 +45,41 @@
* @sa Samba Developers Guide
**/
-static size_t ascii_pull(void *,char **, size_t *, char **, size_t *);
-static size_t ascii_push(void *,char **, size_t *, char **, size_t *);
-static size_t latin1_push(void *,char **, size_t *, char **, size_t *);
-static size_t utf8_pull(void *,char **, size_t *, char **, size_t *);
-static size_t utf8_push(void *,char **, size_t *, char **, size_t *);
-static size_t ucs2hex_pull(void *,char **, size_t *, char **, size_t *);
-static size_t ucs2hex_push(void *,char **, size_t *, char **, size_t *);
-static size_t iconv_copy(void *,char **, size_t *, char **, size_t *);
+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 size_t iconv_swab (void *,const char **, size_t *, char **, size_t *);
static struct charset_functions builtin_functions[] = {
{"UCS-2LE", iconv_copy, iconv_copy},
+ {"UCS-2BE", iconv_swab, iconv_swab},
{"UTF8", utf8_pull, utf8_push},
{"ASCII", ascii_pull, ascii_push},
- {"646", ascii_pull, ascii_push},
- {"ISO-8859-1", ascii_pull, latin1_push},
{"UCS2-HEX", ucs2hex_pull, ucs2hex_push},
{NULL, NULL, NULL}
};
static struct charset_functions *charsets = NULL;
-static struct charset_functions *find_charset_functions(const char *name)
+static NTSTATUS charset_register_backend(void *_funcs)
{
+ struct charset_functions *funcs = (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(name, c->name) == 0) {
- return c;
+ if(!strcasecmp(c->name, funcs->name)){
+ DEBUG(2, ("Duplicate charset %s, not registering\n", funcs->name));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
}
c = c->next;
}
- return NULL;
-}
-
-NTSTATUS smb_register_charset(struct charset_functions *funcs)
-{
- if (!funcs) {
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- DEBUG(5, ("Attempting to register new charset %s\n", funcs->name));
- /* Check whether we already have this charset... */
- if (find_charset_functions(funcs->name)) {
- DEBUG(0, ("Duplicate charset %s, not registering\n", funcs->name));
- return NT_STATUS_OBJECT_NAME_COLLISION;
- }
-
funcs->next = funcs->prev = NULL;
DEBUG(5, ("Registered charset %s\n", funcs->name));
DLIST_ADD(charsets, funcs);
@@ -107,35 +88,33 @@ NTSTATUS smb_register_charset(struct charset_functions *funcs)
static void lazy_initialize_iconv(void)
{
- static BOOL initialized;
+ static BOOL initialized = False;
int i;
if (!initialized) {
initialized = True;
+ register_subsystem("charset", charset_register_backend);
+
for(i = 0; builtin_functions[i].name; i++)
- smb_register_charset(&builtin_functions[i]);
- static_init_charset;
+ register_backend("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,
- char **inbuf, size_t *inbytesleft,
+ const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
-#ifdef HAVE_NATIVE_ICONV
size_t ret = iconv((iconv_t)cd,
inbuf, inbytesleft,
outbuf, outbytesleft);
if (ret == (size_t)-1) iconv(cd, NULL, NULL, NULL, NULL);
return ret;
-#else
- errno = EINVAL;
- return -1;
-#endif
}
+#endif
/**
* This is a simple portable iconv() implementaion.
@@ -144,7 +123,7 @@ static size_t sys_iconv(void *cd,
* enough that Samba works on systems that don't have iconv.
**/
size_t smb_iconv(smb_iconv_t cd,
- char **inbuf, size_t *inbytesleft,
+ const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
char cvtbuf[2048];
@@ -154,7 +133,7 @@ size_t smb_iconv(smb_iconv_t cd,
/* in many cases we can go direct */
if (cd->direct) {
return cd->direct(cd->cd_direct,
- (char **)inbuf, inbytesleft, outbuf, outbytesleft);
+ inbuf, inbytesleft, outbuf, outbytesleft);
}
@@ -164,7 +143,7 @@ size_t smb_iconv(smb_iconv_t cd,
bufsize = sizeof(cvtbuf);
if (cd->pull(cd->cd_pull,
- (char **)inbuf, inbytesleft, &bufp, &bufsize) == -1
+ inbuf, inbytesleft, &bufp, &bufsize) == -1
&& errno != E2BIG) return -1;
bufp = cvtbuf;
@@ -201,70 +180,49 @@ smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
ret->to_name = strdup(tocode);
/* check for the simplest null conversion */
- if (strcasecmp(fromcode, tocode) == 0) {
+ if (strcmp(fromcode, tocode) == 0) {
ret->direct = iconv_copy;
return ret;
}
- /* check if we have a builtin function for this conversion */
- from = find_charset_functions(fromcode);
- if(from)ret->pull = from->pull;
-
- to = find_charset_functions(tocode);
- if(to)ret->push = to->push;
+ while (from) {
+ if (strcasecmp(from->name, fromcode) == 0) break;
+ from = from->next;
+ }
+
+ while (to) {
+ if (strcasecmp(to->name, tocode) == 0) break;
+ to = to->next;
+ }
- /* check if we can use iconv for this conversion */
#ifdef HAVE_NATIVE_ICONV
- if (!ret->pull) {
+ if (!from) {
+ ret->pull = sys_iconv;
ret->cd_pull = iconv_open("UCS-2LE", fromcode);
- if (ret->cd_pull != (iconv_t)-1)
- ret->pull = sys_iconv;
+ if (ret->cd_pull == (iconv_t)-1) goto failed;
}
- if (!ret->push) {
+ if (!to) {
+ ret->push = sys_iconv;
ret->cd_push = iconv_open(tocode, "UCS-2LE");
- if (ret->cd_push != (iconv_t)-1)
- ret->push = sys_iconv;
+ if (ret->cd_push == (iconv_t)-1) goto failed;
}
-#endif
-
- /* check if there is a module available that can do this conversion */
- if (!ret->pull && NT_STATUS_IS_OK(smb_probe_module("charset", fromcode))) {
- if(!(from = find_charset_functions(fromcode)))
- DEBUG(0, ("Module %s doesn't provide charset %s!\n", fromcode, fromcode));
- else
- ret->pull = from->pull;
- }
-
- if (!ret->push && NT_STATUS_IS_OK(smb_probe_module("charset", tocode))) {
- if(!(to = find_charset_functions(tocode)))
- DEBUG(0, ("Module %s doesn't provide charset %s!\n", tocode, tocode));
- else
- ret->push = to->push;
- }
-
- if (!ret->push || !ret->pull) {
- SAFE_FREE(ret->from_name);
- SAFE_FREE(ret->to_name);
- SAFE_FREE(ret);
- errno = EINVAL;
- return (smb_iconv_t)-1;
+#else
+ if (!from || !to) {
+ goto failed;
}
+#endif
/* check for conversion to/from ucs2 */
if (strcasecmp(fromcode, "UCS-2LE") == 0 && to) {
ret->direct = to->push;
- ret->push = ret->pull = NULL;
return ret;
}
-
if (strcasecmp(tocode, "UCS-2LE") == 0 && from) {
ret->direct = from->pull;
- ret->push = ret->pull = NULL;
return ret;
}
- /* Check if we can do the conversion direct */
#ifdef HAVE_NATIVE_ICONV
if (strcasecmp(fromcode, "UCS-2LE") == 0) {
ret->direct = sys_iconv;
@@ -280,7 +238,15 @@ smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
}
#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;
}
/*
@@ -308,8 +274,7 @@ int smb_iconv_close (smb_iconv_t cd)
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, char **inbuf, size_t *inbytesleft,
+static size_t ascii_pull(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
while (*inbytesleft >= 1 && *outbytesleft >= 2) {
@@ -329,7 +294,7 @@ static size_t ascii_pull(void *cd, char **inbuf, size_t *inbytesleft,
return 0;
}
-static size_t ascii_push(void *cd, char **inbuf, size_t *inbytesleft,
+static size_t ascii_push(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
int ir_count=0;
@@ -356,34 +321,8 @@ static size_t ascii_push(void *cd, char **inbuf, size_t *inbytesleft,
return ir_count;
}
-static size_t latin1_push(void *cd, char **inbuf, size_t *inbytesleft,
- char **outbuf, size_t *outbytesleft)
-{
- int ir_count=0;
- while (*inbytesleft >= 2 && *outbytesleft >= 1) {
- (*outbuf)[0] = (*inbuf)[0];
- 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, char **inbuf, size_t *inbytesleft,
+static size_t ucs2hex_pull(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
while (*inbytesleft >= 1 && *outbytesleft >= 2) {
@@ -426,7 +365,7 @@ static size_t ucs2hex_pull(void *cd, char **inbuf, size_t *inbytesleft,
return 0;
}
-static size_t ucs2hex_push(void *cd, char **inbuf, size_t *inbytesleft,
+static size_t ucs2hex_push(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
while (*inbytesleft >= 2 && *outbytesleft >= 1) {
@@ -467,8 +406,33 @@ static size_t ucs2hex_push(void *cd, char **inbuf, size_t *inbytesleft,
return 0;
}
+static size_t iconv_swab(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int n;
+
+ n = MIN(*inbytesleft, *outbytesleft);
+
+ swab(*inbuf, *outbuf, (n&~1));
+ if (n&1) {
+ (*outbuf)[n-1] = 0;
+ }
+
+ (*inbytesleft) -= n;
+ (*outbytesleft) -= n;
+ (*inbuf) += n;
+ (*outbuf) += n;
-static size_t iconv_copy(void *cd, char **inbuf, size_t *inbytesleft,
+ if (*inbytesleft > 0) {
+ 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;
@@ -490,11 +454,11 @@ static size_t iconv_copy(void *cd, char **inbuf, size_t *inbytesleft,
return 0;
}
-static size_t utf8_pull(void *cd, char **inbuf, size_t *inbytesleft,
+static size_t utf8_pull(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
while (*inbytesleft >= 1 && *outbytesleft >= 2) {
- unsigned char *c = (unsigned char *)*inbuf;
+ const unsigned char *c = (const unsigned char *)*inbuf;
unsigned char *uc = (unsigned char *)*outbuf;
int len = 1;
@@ -537,12 +501,12 @@ badseq:
return -1;
}
-static size_t utf8_push(void *cd, char **inbuf, size_t *inbytesleft,
+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;
- unsigned char *uc = (unsigned char *)*inbuf;
+ const unsigned char *uc = (const unsigned char *)*inbuf;
int len=1;
if (uc[1] & 0xf8) {
@@ -589,3 +553,4 @@ toobig:
errno = E2BIG;
return -1;
}
+
diff --git a/source/lib/iconv.m4 b/source/lib/iconv.m4
new file mode 100644
index 00000000000..26512ff326d
--- /dev/null
+++ b/source/lib/iconv.m4
@@ -0,0 +1,66 @@
+dnl # ICONV/CHARSET subsystem
+
+ICONV_LOCATION=standard
+LOOK_DIRS="/usr /usr/local /sw"
+AC_ARG_WITH(libiconv,
+[ --with-libiconv=BASEDIR Use libiconv in BASEDIR/lib and BASEDIR/include (default=auto) ],
+[
+ if test "$withval" = "no" ; then
+ AC_MSG_ERROR(I won't take no for an answer)
+ else
+ if test "$withval" != "yes" ; then
+ LOOK_DIRS="$withval $LOOK_DIRS"
+ fi
+ fi
+])
+
+ICONV_FOUND="no"
+for i in $LOOK_DIRS ; do
+ save_LIBS=$LIBS
+ save_LDFLAGS=$LDFLAGS
+ save_CPPFLAGS=$CPPFLAGS
+ CPPFLAGS="-I$i/include"
+ LDFLAGS="-L$i/lib"
+ LIBS=
+ export LDFLAGS LIBS CPPFLAGS
+dnl Try to find iconv(3)
+ jm_ICONV($i)
+
+ CPPFLAGS=$save_CPPFLAGS
+ if test -n "$ICONV_FOUND" ; then
+ LDFLAGS=$save_LDFLAGS
+ LIB_ADD_DIR(LDFLAGS, "$i/lib")
+ CFLAGS_ADD_DIR(CPPFLAGS, "$i/include")
+ LIBS="$save_LIBS $LIBS"
+ ICONV_LOCATION=$i
+ export LDFLAGS LIBS CPPFLAGS
+ break
+ else
+ LDFLAGS=$save_LDFLAGS
+ LIBS=$save_LIBS
+ export LDFLAGS LIBS CPPFLAGS
+ fi
+done
+
+############
+# check for iconv in libc
+AC_CACHE_CHECK([for working iconv],samba_cv_HAVE_NATIVE_ICONV,[
+AC_TRY_RUN([
+#include <iconv.h>
+main() {
+ iconv_t cd = iconv_open("ASCII", "UCS-2LE");
+ if (cd == 0 || cd == (iconv_t)-1) return -1;
+ return 0;
+}
+],
+samba_cv_HAVE_NATIVE_ICONV=yes,samba_cv_HAVE_NATIVE_ICONV=no,samba_cv_HAVE_NATIVE_ICONV=cross)])
+if test x"$samba_cv_HAVE_NATIVE_ICONV" = x"yes"; then
+ AC_DEFINE(HAVE_NATIVE_ICONV,1,[Whether to use native iconv])
+fi
+
+if test x"$ICONV_FOUND" = x"no" -o x"$samba_cv_HAVE_NATIVE_ICONV" != x"yes" ; then
+ AC_MSG_WARN([Sufficient support for iconv function was not found.
+ Install libiconv from http://freshmeat.net/projects/libiconv/ for better charset compatibility!])
+fi
+
+SMB_SUBSYSTEM(CHARSET,lib/iconv.o,lib/charcnv.o)
diff --git a/source/lib/interface.c b/source/lib/interface.c
index 4d8010e31bc..2540c898ffd 100644
--- a/source/lib/interface.c
+++ b/source/lib/interface.c
@@ -23,7 +23,7 @@
static struct iface_struct *probed_ifaces;
static int total_probed;
-struct in_addr allones_ip;
+static struct in_addr allones_ip;
struct in_addr loopback_ip;
static struct interface *local_interfaces;
@@ -94,14 +94,14 @@ This handles the following different forms:
4) ip/mask
5) bcast/mask
****************************************************************************/
-static void interpret_interface(const char *token)
+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);
+ zero_ip(&ip);
+ zero_ip(&nmask);
/* first check if it is an interface name */
for (i=0;i<total_probed;i++) {
@@ -116,7 +116,7 @@ static void interpret_interface(const char *token)
/* maybe it is a DNS name */
p = strchr_m(token,'/');
if (!p) {
- ip = *interpret_addr2(token);
+ 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)) {
@@ -132,10 +132,10 @@ static void interpret_interface(const char *token)
/* parse it into an IP address/netmasklength pair */
*p++ = 0;
- ip = *interpret_addr2(token);
+ ip = *interpret_addr2(mem_ctx, token);
if (strlen(p) > 2) {
- nmask = *interpret_addr2(p);
+ nmask = *interpret_addr2(mem_ctx, p);
} else {
nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
}
@@ -165,11 +165,17 @@ 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("255.255.255.255");
- loopback_ip = *interpret_addr2("127.0.0.1");
+ allones_ip = *interpret_addr2(mem_ctx, "255.255.255.255");
+ loopback_ip = *interpret_addr2(mem_ctx, "127.0.0.1");
SAFE_FREE(probed_ifaces);
@@ -202,12 +208,12 @@ void load_interfaces(void)
probed_ifaces[i].netmask);
}
}
- return;
+ goto exit;
}
if (ptr) {
while (*ptr) {
- interpret_interface(*ptr);
+ interpret_interface(mem_ctx, *ptr);
ptr++;
}
}
@@ -215,6 +221,9 @@ void load_interfaces(void)
if (!local_interfaces) {
DEBUG(0,("WARNING: no network interfaces found\n"));
}
+
+exit:
+ talloc_destroy(mem_ctx);
}
@@ -276,20 +285,6 @@ int iface_count(void)
}
/****************************************************************************
- return the Nth interface
- **************************************************************************/
-struct interface *get_interface(int n)
-{
- struct interface *i;
-
- for (i=local_interfaces;i && n;i=i->next)
- n--;
-
- if (i) return i;
- return NULL;
-}
-
-/****************************************************************************
return IP of the Nth interface
**************************************************************************/
struct in_addr *iface_n_ip(int n)
diff --git a/source/lib/ldb/Makefile.ldb b/source/lib/ldb/Makefile.ldb
new file mode 100644
index 00000000000..0610ccf19ba
--- /dev/null
+++ b/source/lib/ldb/Makefile.ldb
@@ -0,0 +1,56 @@
+OPENLDAP=/home/tridge/samba/openldap/prefix
+TDBDIR=../tdb
+
+CFLAGS=-Wall -g -Iinclude -I. -I.. -DSTANDALONE=1 -DUSE_MMAP=1
+
+LIB_FLAGS=-Llib -lldb -L$(OPENLDAP)/lib -lldap
+
+TDB_OBJ=$(TDBDIR)/tdb.o $(TDBDIR)/spinlock.o
+
+LDB_TDB_OBJ=ldb_tdb/ldb_match.o ldb_tdb/ldb_tdb.o \
+ ldb_tdb/ldb_pack.o ldb_tdb/ldb_search.o ldb_tdb/ldb_index.o
+
+LDB_LDAP_OBJ=ldb_ldap/ldb_ldap.o
+
+COMMON_OBJ=common/ldb.o common/ldb_ldif.o common/util.o common/ldb_parse.o
+
+OBJS = $(COMMON_OBJ) $(LDB_TDB_OBJ) $(TDB_OBJ) $(LDB_LDAP_OBJ)
+
+LDB_LIB = lib/libldb.a
+
+BINS = bin/ldbadd bin/ldbsearch bin/ldbdel bin/ldbmodify
+
+LIBS = $(LDB_LIB)($(OBJS))
+
+DIRS = lib bin
+
+all: $(DIRS) $(BINS) $(LIBS)
+
+lib:
+ mkdir -p lib
+
+bin:
+ mkdir -p bin
+
+lib/libldb.a: $(OBJS)
+
+bin/ldbadd: tools/ldbadd.o $(LIBS)
+ $(CC) -o bin/ldbadd tools/ldbadd.o $(LIB_FLAGS)
+
+bin/ldbsearch: tools/ldbsearch.o $(LIBS)
+ $(CC) -o bin/ldbsearch tools/ldbsearch.o $(LIB_FLAGS)
+
+bin/ldbdel: tools/ldbdel.o $(LIBS)
+ $(CC) -o bin/ldbdel tools/ldbdel.o $(LIB_FLAGS)
+
+bin/ldbmodify: tools/ldbmodify.o $(LIBS)
+ $(CC) -o bin/ldbmodify tools/ldbmodify.o $(LIB_FLAGS)
+
+clean:
+ rm -f */*.o *~ */*~ $(BINS) $(LDB_LIB)
+
+proto:
+ mkproto.pl */*.c > include/proto.h
+
+etags:
+ etags */*.[ch]
diff --git a/source/lib/ldb/common/ldb.c b/source/lib/ldb/common/ldb.c
new file mode 100644
index 00000000000..90b77e1e7f2
--- /dev/null
+++ b/source/lib/ldb/common/ldb.c
@@ -0,0 +1,129 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb core API
+ *
+ * Description: core API routines interfacing to ldb backends
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+
+/*
+ connect to a database. The URL can either be one of the following forms
+ ldb://path
+ ldapi://path
+
+ flags is made up of LDB_FLG_*
+
+ the options are passed uninterpreted to the backend, and are
+ backend specific
+*/
+struct ldb_context *ldb_connect(const char *url, unsigned int flags,
+ const char *options[])
+{
+
+ if (strncmp(url, "tdb:", 4) == 0) {
+ return ltdb_connect(url, flags, options);
+ }
+
+ if (strncmp(url, "ldap", 4) == 0) {
+ return lldb_connect(url, flags, options);
+ }
+
+ errno = EINVAL;
+ return NULL;
+}
+
+/*
+ close the connection to the database
+*/
+int ldb_close(struct ldb_context *ldb)
+{
+ return ldb->ops->close(ldb);
+}
+
+
+/*
+ search the database given a LDAP-like search expression
+
+ return the number of records found, or -1 on error
+*/
+int ldb_search(struct ldb_context *ldb,
+ const char *base,
+ enum ldb_scope scope,
+ const char *expression,
+ const char *attrs[], struct ldb_message ***res)
+{
+ return ldb->ops->search(ldb, base, scope, expression, attrs, res);
+}
+
+/*
+ free a set of messages returned by ldb_search
+*/
+int ldb_search_free(struct ldb_context *ldb, struct ldb_message **msgs)
+{
+ return ldb->ops->search_free(ldb, msgs);
+}
+
+
+/*
+ add a record to the database. Will fail if a record with the given class and key
+ already exists
+*/
+int ldb_add(struct ldb_context *ldb,
+ const struct ldb_message *message)
+{
+ return ldb->ops->add(ldb, message);
+}
+
+/*
+ modify the specified attributes of a record
+*/
+int ldb_modify(struct ldb_context *ldb,
+ const struct ldb_message *message)
+{
+ return ldb->ops->modify(ldb, message);
+}
+
+
+/*
+ delete a record from the database
+*/
+int ldb_delete(struct ldb_context *ldb, const char *dn)
+{
+ return ldb->ops->delete(ldb, dn);
+}
+
+/*
+ return extended error information
+*/
+const char *ldb_errstring(struct ldb_context *ldb)
+{
+ return ldb->ops->errstring(ldb);
+}
diff --git a/source/lib/ldb/common/ldb_ldif.c b/source/lib/ldb/common/ldb_ldif.c
new file mode 100644
index 00000000000..b4c27c3369e
--- /dev/null
+++ b/source/lib/ldb/common/ldb_ldif.c
@@ -0,0 +1,623 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldif routines
+ *
+ * Description: ldif pack/unpack routines
+ *
+ * Author: Andrew Tridgell
+ */
+
+/*
+ see RFC2849 for the LDIF format definition
+*/
+
+#include "includes.h"
+
+
+/*
+ this base64 decoder was taken from jitterbug (written by tridge).
+ we might need to replace it with a new version
+*/
+static int base64_decode(char *s)
+{
+ const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ int bit_offset, byte_offset, idx, i, n;
+ unsigned char *d = (unsigned char *)s;
+ char *p;
+
+ n=i=0;
+
+ while (*s && (p=strchr(b64,*s))) {
+ idx = (int)(p - b64);
+ byte_offset = (i*6)/8;
+ bit_offset = (i*6)%8;
+ d[byte_offset] &= ~((1<<(8-bit_offset))-1);
+ if (bit_offset < 3) {
+ d[byte_offset] |= (idx << (2-bit_offset));
+ n = byte_offset+1;
+ } else {
+ d[byte_offset] |= (idx >> (bit_offset-2));
+ d[byte_offset+1] = 0;
+ d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
+ n = byte_offset+2;
+ }
+ s++; i++;
+ }
+
+ if (*s && !p) {
+ /* the only termination allowed */
+ if (*s != '=') {
+ return -1;
+ }
+ }
+
+ /* null terminate */
+ d[n] = 0;
+ return n;
+}
+
+
+/*
+ encode as base64
+ caller frees
+*/
+char *ldb_base64_encode(const char *buf, int len)
+{
+ const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ int bit_offset, byte_offset, idx, i;
+ unsigned char *d = (unsigned char *)buf;
+ int bytes = (len*8 + 5)/6;
+ char *out;
+
+ out = malloc(bytes+2);
+ if (!out) return NULL;
+
+ for (i=0;i<bytes;i++) {
+ byte_offset = (i*6)/8;
+ bit_offset = (i*6)%8;
+ if (bit_offset < 3) {
+ idx = (d[byte_offset] >> (2-bit_offset)) & 0x3F;
+ } else {
+ idx = (d[byte_offset] << (bit_offset-2)) & 0x3F;
+ if (byte_offset+1 < len) {
+ idx |= (d[byte_offset+1] >> (8-(bit_offset-2)));
+ }
+ }
+ out[i] = b64[idx];
+ }
+
+ out[i++] = '=';
+ out[i] = 0;
+
+ return out;
+}
+
+/*
+ see if a buffer should be base64 encoded
+*/
+int ldb_should_b64_encode(const struct ldb_val *val)
+{
+ int i;
+ unsigned char *p = val->data;
+
+ if (val->length == 0 || p[0] == ' ' || p[0] == ':') {
+ return 1;
+ }
+
+ for (i=0; i<val->length; i++) {
+ if (!isprint(p[i]) || p[i] == '\n') {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* this macro is used to handle the return checking on fprintf_fn() */
+#define CHECK_RET do { if (ret < 0) return ret; total += ret; } while (0)
+
+/*
+ write a line folded string onto a file
+*/
+static int fold_string(int (*fprintf_fn)(void *, const char *, ...), void *private,
+ const char *buf, size_t length, int start_pos)
+{
+ int i;
+ int total=0, ret;
+
+ for (i=0;i<length;i++) {
+ ret = fprintf_fn(private, "%c", buf[i]);
+ CHECK_RET;
+ if (i != (length-1) && (i + start_pos) % 77 == 0) {
+ ret = fprintf_fn(private, "\n ");
+ CHECK_RET;
+ }
+ }
+
+ return total;
+}
+
+/*
+ encode as base64 to a file
+*/
+static int base64_encode_f(int (*fprintf_fn)(void *, const char *, ...), void *private,
+ const char *buf, int len, int start_pos)
+{
+ char *b = ldb_base64_encode(buf, len);
+ int ret;
+
+ if (!b) {
+ return -1;
+ }
+
+ ret = fold_string(fprintf_fn, private, b, strlen(b), start_pos);
+
+ free(b);
+ return ret;
+}
+
+
+static const struct {
+ const char *name;
+ enum ldb_changetype changetype;
+} ldb_changetypes[] = {
+ {"add", LDB_CHANGETYPE_ADD},
+ {"delete", LDB_CHANGETYPE_DELETE},
+ {"modify", LDB_CHANGETYPE_MODIFY},
+ {NULL, 0}
+};
+
+/*
+ write to ldif, using a caller supplied write method
+*/
+int ldif_write(int (*fprintf_fn)(void *, const char *, ...),
+ void *private,
+ const struct ldb_ldif *ldif)
+{
+ int i, j;
+ int total=0, ret;
+ const struct ldb_message *msg;
+
+ msg = &ldif->msg;
+
+ ret = fprintf_fn(private, "dn: %s\n", msg->dn);
+ CHECK_RET;
+
+ if (ldif->changetype != LDB_CHANGETYPE_NONE) {
+ for (i=0;ldb_changetypes[i].name;i++) {
+ if (ldb_changetypes[i].changetype == ldif->changetype) {
+ break;
+ }
+ }
+ if (!ldb_changetypes[i].name) {
+ fprintf(stderr,"Invalid changetype\n");
+ return -1;
+ }
+ ret = fprintf_fn(private, "changetype: %s\n", ldb_changetypes[i].name);
+ CHECK_RET;
+ }
+
+ for (i=0;i<msg->num_elements;i++) {
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ if (ldb_should_b64_encode(&msg->elements[i].values[j])) {
+ ret = fprintf_fn(private, "%s:: ",
+ msg->elements[i].name);
+ CHECK_RET;
+ ret = base64_encode_f(fprintf_fn, private,
+ msg->elements[i].values[j].data,
+ msg->elements[i].values[j].length,
+ strlen(msg->elements[i].name)+3);
+ CHECK_RET;
+ ret = fprintf_fn(private, "\n");
+ CHECK_RET;
+ } else {
+ ret = fprintf_fn(private, "%s: ", msg->elements[i].name);
+ CHECK_RET;
+ ret = fold_string(fprintf_fn, private,
+ msg->elements[i].values[j].data,
+ msg->elements[i].values[j].length,
+ strlen(msg->elements[i].name)+2);
+ CHECK_RET;
+ ret = fprintf_fn(private, "\n");
+ CHECK_RET;
+ }
+ }
+ }
+ ret = fprintf_fn(private,"\n");
+ CHECK_RET;
+
+ return total;
+}
+
+#undef CHECK_RET
+
+
+/*
+ pull a ldif chunk, which is defined as a piece of data ending in \n\n or EOF
+ this routine removes any RFC2849 continuations and comments
+
+ caller frees
+*/
+static char *next_chunk(int (*fgetc_fn)(void *), void *private)
+{
+ size_t alloc_size=0, chunk_size = 0;
+ char *chunk = NULL;
+ int c;
+ int in_comment = 0;
+
+ while ((c = fgetc_fn(private)) != EOF) {
+ if (chunk_size+1 >= alloc_size) {
+ char *c2;
+ alloc_size += 1024;
+ c2 = realloc_p(chunk, char, alloc_size);
+ if (!c2) {
+ free(chunk);
+ errno = ENOMEM;
+ return NULL;
+ }
+ chunk = c2;
+ }
+
+ if (in_comment) {
+ if (c == '\n') {
+ in_comment = 0;
+ }
+ continue;
+ }
+
+ /* handle continuation lines - see RFC2849 */
+ if (c == ' ' && chunk_size > 1 && chunk[chunk_size-1] == '\n') {
+ chunk_size--;
+ continue;
+ }
+
+ /* chunks are terminated by a double line-feed */
+ if (c == '\n' && chunk_size > 0 && chunk[chunk_size-1] == '\n') {
+ chunk[chunk_size-1] = 0;
+ return chunk;
+ }
+
+ if (c == '#' && (chunk_size == 0 || chunk[chunk_size-1] == '\n')) {
+ in_comment = 1;
+ continue;
+ }
+
+ /* ignore leading blank lines */
+ if (chunk_size == 0 && c == '\n') {
+ continue;
+ }
+
+ chunk[chunk_size++] = c;
+ }
+
+ if (chunk) {
+ chunk[chunk_size] = 0;
+ }
+
+ return chunk;
+}
+
+
+/* simple ldif attribute parser */
+static int next_attr(char **s, char **attr, struct ldb_val *value)
+{
+ char *p;
+ int base64_encoded = 0;
+
+ if (strncmp(*s, "-\n", 2) == 0) {
+ value->length = 0;
+ *attr = "-";
+ *s += 2;
+ return 0;
+ }
+
+ p = strchr(*s, ':');
+ if (!p) {
+ return -1;
+ }
+
+ *p++ = 0;
+
+ if (*p == ':') {
+ base64_encoded = 1;
+ p++;
+ }
+
+ *attr = *s;
+
+ while (isspace(*p)) {
+ p++;
+ }
+
+ value->data = p;
+
+ p = strchr(p, '\n');
+
+ if (!p) {
+ value->length = strlen((char *)value->data);
+ *s = ((char *)value->data) + value->length;
+ } else {
+ value->length = p - (char *)value->data;
+ *s = p+1;
+ *p = 0;
+ }
+
+ if (base64_encoded) {
+ int len = base64_decode(value->data);
+ if (len == -1) {
+ /* it wasn't valid base64 data */
+ return -1;
+ }
+ value->length = len;
+ }
+
+ return 0;
+}
+
+
+/*
+ free a message from a ldif_read
+*/
+void ldif_read_free(struct ldb_ldif *ldif)
+{
+ struct ldb_message *msg = &ldif->msg;
+ int i;
+ for (i=0;i<msg->num_elements;i++) {
+ if (msg->elements[i].values) free(msg->elements[i].values);
+ }
+ if (msg->elements) free(msg->elements);
+ if (msg->private) free(msg->private);
+ free(ldif);
+}
+
+/*
+ add an empty element
+*/
+static int msg_add_empty(struct ldb_message *msg, const char *name, unsigned flags)
+{
+ struct ldb_message_element *el2, *el;
+
+ el2 = realloc_p(msg->elements, struct ldb_message_element, msg->num_elements+1);
+ if (!el2) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ msg->elements = el2;
+
+ el = &msg->elements[msg->num_elements];
+
+ el->name = name;
+ el->num_values = 0;
+ el->values = NULL;
+ el->flags = flags;
+
+ msg->num_elements++;
+
+ return 0;
+}
+
+/*
+ read from a LDIF source, creating a ldb_message
+*/
+struct ldb_ldif *ldif_read(int (*fgetc_fn)(void *), void *private)
+{
+ struct ldb_ldif *ldif;
+ struct ldb_message *msg;
+ char *attr=NULL, *chunk=NULL, *s;
+ struct ldb_val value;
+ unsigned flags = 0;
+
+ value.data = NULL;
+
+ ldif = malloc_p(struct ldb_ldif);
+ if (!ldif) return NULL;
+
+ ldif->changetype = LDB_CHANGETYPE_NONE;
+ msg = &ldif->msg;
+
+ msg->dn = NULL;
+ msg->elements = NULL;
+ msg->num_elements = 0;
+ msg->private = NULL;
+
+ chunk = next_chunk(fgetc_fn, private);
+ if (!chunk) {
+ goto failed;
+ }
+
+ msg->private = chunk;
+ s = chunk;
+
+ if (next_attr(&s, &attr, &value) != 0) {
+ goto failed;
+ }
+
+ /* first line must be a dn */
+ if (strcmp(attr, "dn") != 0) {
+ fprintf(stderr, "First line must be a dn not '%s'\n", attr);
+ goto failed;
+ }
+
+ msg->dn = value.data;
+
+ while (next_attr(&s, &attr, &value) == 0) {
+ struct ldb_message_element *el;
+ int empty = 0;
+
+ if (strcmp(attr, "changetype") == 0) {
+ int i;
+ for (i=0;ldb_changetypes[i].name;i++) {
+ if (strcmp((char *)value.data, ldb_changetypes[i].name) == 0) {
+ ldif->changetype = ldb_changetypes[i].changetype;
+ break;
+ }
+ }
+ if (!ldb_changetypes[i].name) {
+ fprintf(stderr,"Bad changetype '%s'\n",
+ (char *)value.data);
+ }
+ flags = 0;
+ continue;
+ }
+
+ if (strcmp(attr, "add") == 0) {
+ flags = LDB_FLAG_MOD_ADD;
+ empty = 1;
+ }
+ if (strcmp(attr, "delete") == 0) {
+ flags = LDB_FLAG_MOD_DELETE;
+ empty = 1;
+ }
+ if (strcmp(attr, "replace") == 0) {
+ flags = LDB_FLAG_MOD_REPLACE;
+ empty = 1;
+ }
+ if (strcmp(attr, "-") == 0) {
+ flags = 0;
+ continue;
+ }
+
+ if (empty) {
+ if (msg_add_empty(msg, (char *)value.data, flags) != 0) {
+ goto failed;
+ }
+ continue;
+ }
+
+ el = &msg->elements[msg->num_elements-1];
+
+ if (msg->num_elements > 0 && strcmp(attr, el->name) == 0 &&
+ flags == el->flags) {
+ /* its a continuation */
+ el->values =
+ realloc_p(el->values, struct ldb_val, el->num_values+1);
+ if (!el->values) {
+ goto failed;
+ }
+ el->values[el->num_values] = value;
+ el->num_values++;
+ } else {
+ /* its a new attribute */
+ msg->elements = realloc_p(msg->elements,
+ struct ldb_message_element,
+ msg->num_elements+1);
+ if (!msg->elements) {
+ goto failed;
+ }
+ msg->elements[msg->num_elements].flags = flags;
+ msg->elements[msg->num_elements].name = attr;
+ el = &msg->elements[msg->num_elements];
+ el->values = malloc_p(struct ldb_val);
+ if (!el->values) {
+ goto failed;
+ }
+ el->num_values = 1;
+ el->values[0] = value;
+ msg->num_elements++;
+ }
+ }
+
+ return ldif;
+
+failed:
+ if (ldif) ldif_read_free(ldif);
+ return NULL;
+}
+
+
+
+/*
+ a wrapper around ldif_read() for reading from FILE*
+*/
+struct ldif_read_file_state {
+ FILE *f;
+};
+
+static int fgetc_file(void *private)
+{
+ struct ldif_read_file_state *state = private;
+ return fgetc(state->f);
+}
+
+struct ldb_ldif *ldif_read_file(FILE *f)
+{
+ struct ldif_read_file_state state;
+ state.f = f;
+ return ldif_read(fgetc_file, &state);
+}
+
+
+/*
+ a wrapper around ldif_read() for reading from const char*
+*/
+struct ldif_read_string_state {
+ const char *s;
+};
+
+static int fgetc_string(void *private)
+{
+ struct ldif_read_string_state *state = private;
+ if (state->s[0] != 0) {
+ return *state->s++;
+ }
+ return EOF;
+}
+
+struct ldb_ldif *ldif_read_string(const char *s)
+{
+ struct ldif_read_string_state state;
+ state.s = s;
+ return ldif_read(fgetc_string, &state);
+}
+
+
+/*
+ wrapper around ldif_write() for a file
+*/
+struct ldif_write_file_state {
+ FILE *f;
+};
+
+static int fprintf_file(void *private, const char *fmt, ...)
+{
+ struct ldif_write_file_state *state = private;
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfprintf(state->f, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+int ldif_write_file(FILE *f, const struct ldb_ldif *ldif)
+{
+ struct ldif_write_file_state state;
+ state.f = f;
+ return ldif_write(fprintf_file, &state, ldif);
+}
diff --git a/source/lib/ldb/common/ldb_parse.c b/source/lib/ldb/common/ldb_parse.c
new file mode 100644
index 00000000000..4f8d469e6c6
--- /dev/null
+++ b/source/lib/ldb/common/ldb_parse.c
@@ -0,0 +1,460 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb expression parsing
+ *
+ * Description: parse LDAP-like search expressions
+ *
+ * Author: Andrew Tridgell
+ */
+
+/*
+ TODO:
+ - add RFC2254 binary string handling
+ - possibly add ~=, <= and >= handling
+ - expand the test suite
+ - add better parse error handling
+
+*/
+
+#include "includes.h"
+
+
+/*
+a filter is defined by:
+ <filter> ::= '(' <filtercomp> ')'
+ <filtercomp> ::= <and> | <or> | <not> | <simple>
+ <and> ::= '&' <filterlist>
+ <or> ::= '|' <filterlist>
+ <not> ::= '!' <filter>
+ <filterlist> ::= <filter> | <filter> <filterlist>
+ <simple> ::= <attributetype> <filtertype> <attributevalue>
+ <filtertype> ::= '=' | '~=' | '<=' | '>='
+*/
+
+/*
+ return next token element. Caller frees
+*/
+static char *ldb_parse_lex(const char **s)
+{
+ const char *p = *s;
+ char *ret;
+
+ while (isspace(*p)) {
+ p++;
+ }
+ *s = p;
+
+ if (*p == 0) {
+ return NULL;
+ }
+
+ if (strchr("()&|=!", *p)) {
+ (*s) = p+1;
+ ret = strndup(p, 1);
+ if (!ret) {
+ errno = ENOMEM;
+ }
+ return ret;
+ }
+
+ while (*p && (isalnum(*p) || !strchr("()&|=!", *p))) {
+ p++;
+ }
+
+ if (p == *s) {
+ return NULL;
+ }
+
+ ret = strndup(*s, p - *s);
+ if (!ret) {
+ errno = ENOMEM;
+ }
+
+ *s = p;
+
+ return ret;
+}
+
+/*
+ find a matching close brace in a string
+*/
+static const char *match_brace(const char *s)
+{
+ unsigned int count = 0;
+ while (*s && (count != 0 || *s != ')')) {
+ if (*s == '(') {
+ count++;
+ }
+ if (*s == ')') {
+ count--;
+ }
+ s++;
+ }
+ if (! *s) {
+ return NULL;
+ }
+ return s;
+}
+
+
+static struct ldb_parse_tree *ldb_parse_filter(const char **s);
+
+/*
+ <simple> ::= <attributetype> <filtertype> <attributevalue>
+*/
+static struct ldb_parse_tree *ldb_parse_simple(const char *s)
+{
+ char *eq, *val, *l;
+ struct ldb_parse_tree *ret;
+
+ l = ldb_parse_lex(&s);
+ if (!l) {
+ fprintf(stderr, "Unexpected end of expression\n");
+ return NULL;
+ }
+
+ if (strchr("()&|=", *l)) {
+ fprintf(stderr, "Unexpected token '%s'\n", l);
+ free(l);
+ return NULL;
+ }
+
+ eq = ldb_parse_lex(&s);
+ if (!eq || strcmp(eq, "=") != 0) {
+ fprintf(stderr, "Expected '='\n");
+ free(l);
+ if (eq) free(eq);
+ return NULL;
+ }
+ free(eq);
+
+ val = ldb_parse_lex(&s);
+ if (val && strchr("()&|=", *val)) {
+ fprintf(stderr, "Unexpected token '%s'\n", val);
+ free(l);
+ if (val) free(val);
+ return NULL;
+ }
+
+ ret = malloc_p(struct ldb_parse_tree);
+ if (!ret) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ ret->operation = LDB_OP_SIMPLE;
+ ret->u.simple.attr = l;
+ ret->u.simple.value.data = val;
+ ret->u.simple.value.length = val?strlen(val):0;
+
+ return ret;
+}
+
+
+/*
+ parse a filterlist
+ <and> ::= '&' <filterlist>
+ <or> ::= '|' <filterlist>
+ <filterlist> ::= <filter> | <filter> <filterlist>
+*/
+static struct ldb_parse_tree *ldb_parse_filterlist(enum ldb_parse_op op, const char *s)
+{
+ struct ldb_parse_tree *ret, *next;
+
+ ret = malloc_p(struct ldb_parse_tree);
+ if (!ret) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ ret->operation = op;
+ ret->u.list.num_elements = 1;
+ ret->u.list.elements = malloc_p(struct ldb_parse_tree *);
+ if (!ret->u.list.elements) {
+ errno = ENOMEM;
+ free(ret);
+ return NULL;
+ }
+
+ ret->u.list.elements[0] = ldb_parse_filter(&s);
+ if (!ret->u.list.elements[0]) {
+ free(ret->u.list.elements);
+ free(ret);
+ return NULL;
+ }
+
+ while (isspace(*s)) s++;
+
+ while (*s && (next = ldb_parse_filter(&s))) {
+ struct ldb_parse_tree **e;
+ e = realloc_p(ret->u.list.elements,
+ struct ldb_parse_tree *,
+ ret->u.list.num_elements+1);
+ if (!e) {
+ errno = ENOMEM;
+ ldb_parse_tree_free(next);
+ ldb_parse_tree_free(ret);
+ return NULL;
+ }
+ ret->u.list.elements = e;
+ ret->u.list.elements[ret->u.list.num_elements] = next;
+ ret->u.list.num_elements++;
+ while (isspace(*s)) s++;
+ }
+
+ return ret;
+}
+
+
+/*
+ <not> ::= '!' <filter>
+*/
+static struct ldb_parse_tree *ldb_parse_not(const char *s)
+{
+ struct ldb_parse_tree *ret;
+
+ ret = malloc_p(struct ldb_parse_tree);
+ if (!ret) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ ret->operation = LDB_OP_NOT;
+ ret->u.not.child = ldb_parse_filter(&s);
+ if (!ret->u.not.child) {
+ free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+/*
+ parse a filtercomp
+ <filtercomp> ::= <and> | <or> | <not> | <simple>
+*/
+static struct ldb_parse_tree *ldb_parse_filtercomp(const char *s)
+{
+ while (isspace(*s)) s++;
+
+ switch (*s) {
+ case '&':
+ return ldb_parse_filterlist(LDB_OP_AND, s+1);
+
+ case '|':
+ return ldb_parse_filterlist(LDB_OP_OR, s+1);
+
+ case '!':
+ return ldb_parse_not(s+1);
+
+ case '(':
+ case ')':
+ fprintf(stderr, "Unexpected token '%c'\n", *s);
+ return NULL;
+ }
+
+ return ldb_parse_simple(s);
+}
+
+
+/*
+ <filter> ::= '(' <filtercomp> ')'
+*/
+static struct ldb_parse_tree *ldb_parse_filter(const char **s)
+{
+ char *l, *s2;
+ const char *p, *p2;
+ struct ldb_parse_tree *ret;
+
+ l = ldb_parse_lex(s);
+ if (!l) {
+ fprintf(stderr, "Unexpected end of expression\n");
+ return NULL;
+ }
+
+ if (strcmp(l, "(") != 0) {
+ free(l);
+ fprintf(stderr, "Expected '('\n");
+ return NULL;
+ }
+ free(l);
+
+ p = match_brace(*s);
+ if (!p) {
+ fprintf(stderr, "Parse error - mismatched braces\n");
+ return NULL;
+ }
+ p2 = p + 1;
+
+ s2 = strndup(*s, p - *s);
+ if (!s2) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ ret = ldb_parse_filtercomp(s2);
+ free(s2);
+
+ *s = p2;
+
+ return ret;
+}
+
+
+/*
+ main parser entry point. Takes a search string and returns a parse tree
+
+ expression ::= <simple> | <filter>
+*/
+struct ldb_parse_tree *ldb_parse_tree(const char *s)
+{
+ while (isspace(*s)) s++;
+
+ if (*s == '(') {
+ return ldb_parse_filter(&s);
+ }
+
+ return ldb_parse_simple(s);
+}
+
+/*
+ free a parse tree returned from ldb_parse_tree()
+*/
+void ldb_parse_tree_free(struct ldb_parse_tree *tree)
+{
+ int i;
+
+ switch (tree->operation) {
+ case LDB_OP_SIMPLE:
+ free(tree->u.simple.attr);
+ if (tree->u.simple.value.data) free(tree->u.simple.value.data);
+ break;
+
+ case LDB_OP_AND:
+ case LDB_OP_OR:
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ ldb_parse_tree_free(tree->u.list.elements[i]);
+ }
+ if (tree->u.list.elements) free(tree->u.list.elements);
+ break;
+
+ case LDB_OP_NOT:
+ ldb_parse_tree_free(tree->u.not.child);
+ break;
+ }
+
+ free(tree);
+}
+
+#if TEST_PROGRAM
+/*
+ return a string representation of a parse tree
+ used for debugging
+*/
+static char *tree_string(struct ldb_parse_tree *tree)
+{
+ char *s = NULL;
+ char *s1, *s2;
+ int i;
+
+ switch (tree->operation) {
+ case LDB_OP_SIMPLE:
+ asprintf(&s, "( %s = \"%s\" )", tree->u.simple.attr,
+ (char *)tree->u.simple.value.data);
+ break;
+
+ case LDB_OP_AND:
+ case LDB_OP_OR:
+ asprintf(&s, "( %c", tree->operation==LDB_OP_AND?'&':'|');
+ if (!s) return NULL;
+
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ s1 = tree_string(tree->u.list.elements[i]);
+ if (!s1) {
+ free(s);
+ return NULL;
+ }
+ asprintf(&s2, "%s %s", s, s1);
+ free(s);
+ free(s1);
+ s = s2;
+ }
+ if (!s) {
+ return NULL;
+ }
+ asprintf(&s2, "%s )", s);
+ free(s);
+ s = s2;
+ break;
+
+ case LDB_OP_NOT:
+ s1 = tree_string(tree->u.not.child);
+ asprintf(&s, "( ! %s )", s1);
+ free(s1);
+ break;
+ }
+ return s;
+}
+
+
+/*
+ print a tree
+ */
+static void print_tree(struct ldb_parse_tree *tree)
+{
+ char *s = tree_string(tree);
+ printf("%s\n", s);
+ free(s);
+}
+
+
+ int main(void)
+{
+ char line[1000];
+ int ret = 0;
+
+ while (fgets(line, sizeof(line)-1, stdin)) {
+ struct ldb_parse_tree *tree;
+
+ if (line[strlen(line)-1] == '\n') {
+ line[strlen(line)-1] = 0;
+ }
+ tree = ldb_parse_tree(line);
+ if (!tree) {
+ fprintf(stderr, "Failed to parse\n");
+ ret = 1;
+ continue;
+ }
+ print_tree(tree);
+ ldb_parse_tree_free(tree);
+ }
+
+ return ret;
+}
+#endif /* TEST_PROGRAM */
+
diff --git a/source/lib/ldb/common/util.c b/source/lib/ldb/common/util.c
new file mode 100644
index 00000000000..d198a1ad921
--- /dev/null
+++ b/source/lib/ldb/common/util.c
@@ -0,0 +1,102 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb utility functions
+ *
+ * Description: miscellanous utility functions for ldb
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+
+
+#define MAX_MALLOC_SIZE 0x7fffffff
+
+/*
+ realloc an array, checking for integer overflow in the array size
+*/
+void *realloc_array(void *ptr, size_t el_size, unsigned count)
+{
+ if (count == 0 ||
+ count >= MAX_MALLOC_SIZE/el_size) {
+ return NULL;
+ }
+ if (!ptr) {
+ return malloc(el_size * count);
+ }
+ return realloc(ptr, el_size * count);
+}
+
+
+/*
+ find an element in a list, using the given comparison function and
+ assuming that the list is already sorted using comp_fn
+
+ return -1 if not found, or the index of the first occurance of needle if found
+*/
+int list_find(const void *needle,
+ const void *base, size_t nmemb, size_t size, comparison_fn_t comp_fn)
+{
+ const char *base_p = base;
+ size_t min_i, max_i, test_i;
+
+ if (nmemb == 0) {
+ return -1;
+ }
+
+ min_i = 0;
+ max_i = nmemb-1;
+
+ while (min_i < max_i) {
+ size_t test_t;
+ int r;
+
+ test_i = (min_i + max_i) / 2;
+ r = comp_fn(needle, *(void **)(base_p + (size * test_i)));
+ if (r == 0) {
+ /* scan back for first element */
+ while (test_t > 0 &&
+ comp_fn(needle, *(void **)(base_p + (size * (test_i-1)))) == 0) {
+ test_i--;
+ }
+ return test_i;
+ }
+ if (r == -1) {
+ max_i = test_i - 1;
+ }
+ if (r == 1) {
+ min_i = test_i + 1;
+ }
+ }
+
+ if (comp_fn(needle, *(void **)(base_p + (size * min_i))) == 0) {
+ return min_i;
+ }
+
+ return -1;
+}
diff --git a/source/lib/ldb/docs/design.txt b/source/lib/ldb/docs/design.txt
new file mode 100644
index 00000000000..0bb278b5b42
--- /dev/null
+++ b/source/lib/ldb/docs/design.txt
@@ -0,0 +1,41 @@
+The list of indexed fields
+--------------------------
+
+dn=@INDEXLIST
+ list of field names that are indexed
+
+ contains fields of type @IDXATTR which contain attriute names
+ of indexed fields
+
+
+Data records
+------------
+
+for each user record in the db there is:
+ main record
+ key: DN=dn
+ data: packed attribute/value list
+
+ a index record for each indexed field in the record
+
+
+Index Records
+-------------
+
+The index records contain the list of dn's that contain records
+matching the index key
+
+All index records are of the form:
+ dn=@INDEX:field:value
+
+and contain fields of type @IDX which are the dns of the records
+that have that value for some attribute
+
+
+Search Expressions
+------------------
+
+Very similar to LDAP search expressions, but does not allow ~=, <= or >=
+
+ attrib0 := (field=value)
+ attrib := attrib0 | (attrib&&attrib) | (attrib||attrib) | !attrib
diff --git a/source/lib/ldb/include/includes.h b/source/lib/ldb/include/includes.h
new file mode 100644
index 00000000000..ea8540d3306
--- /dev/null
+++ b/source/lib/ldb/include/includes.h
@@ -0,0 +1,22 @@
+/*
+ a temporary includes file until I work on the ldb build system
+*/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <signal.h>
+#include "ldb.h"
+#include "ldb_parse.h"
+
+#define malloc_p(type) (type *)malloc(sizeof(type))
+#define malloc_array_p(type, count) (type *)realloc_array(NULL, sizeof(type), count)
+#define realloc_p(p, type, count) (type *)realloc_array(p, sizeof(type), count)
+
+#include "tdb/tdb.h"
+#include "proto.h"
diff --git a/source/lib/ldb/include/ldb.h b/source/lib/ldb/include/ldb.h
new file mode 100644
index 00000000000..12064bbf754
--- /dev/null
+++ b/source/lib/ldb/include/ldb.h
@@ -0,0 +1,219 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb header
+ *
+ * Description: defines for base ldb API
+ *
+ * Author: Andrew Tridgell
+ */
+
+/*
+ major restrictions as compared to normal LDAP:
+
+ - no async calls.
+ - each record must have a unique key field
+ - the key must be representable as a NULL terminated C string and may not
+ contain a comma or braces
+
+ major restrictions as compared to tdb:
+
+ - no explicit locking calls
+
+*/
+
+
+/*
+ an individual lump of data in a result comes in this format. The
+ pointer will usually be to a UTF-8 string if the application is
+ sensible, but it can be to anything you like, including binary data
+ blobs of arbitrary size.
+*/
+struct ldb_val {
+ unsigned int length;
+ void *data;
+};
+
+/* these flags are used in ldd_message_element.flags fields. The
+ LDA_FLAGS_MOD_* flags are used in ldap_modify() calls to specify
+ whether attributes are being added, deleted or modified */
+#define LDB_FLAG_MOD_MASK 0x3
+#define LDB_FLAG_MOD_ADD 1
+#define LDB_FLAG_MOD_REPLACE 2
+#define LDB_FLAG_MOD_DELETE 3
+
+
+/*
+ results are given back as arrays of ldb_message_element
+*/
+struct ldb_message_element {
+ unsigned int flags;
+ char *name;
+ unsigned int num_values;
+ struct ldb_val *values;
+};
+
+
+/*
+ a ldb_message represents all or part of a record. It can contain an arbitrary
+ number of elements.
+*/
+struct ldb_message {
+ char *dn;
+ unsigned int num_elements;
+ struct ldb_message_element *elements;
+ void *private; /* private to the backend */
+};
+
+enum ldb_changetype {
+ LDB_CHANGETYPE_NONE=0,
+ LDB_CHANGETYPE_ADD,
+ LDB_CHANGETYPE_DELETE,
+ LDB_CHANGETYPE_MODIFY
+};
+
+/*
+ a ldif record - from ldif_read
+*/
+struct ldb_ldif {
+ enum ldb_changetype changetype;
+ struct ldb_message msg;
+};
+
+enum ldb_scope {LDB_SCOPE_DEFAULT=-1,
+ LDB_SCOPE_BASE=0,
+ LDB_SCOPE_ONELEVEL=1,
+ LDB_SCOPE_SUBTREE=2};
+
+struct ldb_context;
+
+/*
+ the fuction type for the callback used in traversing the database
+*/
+typedef int (*ldb_traverse_fn)(struct ldb_context *, const struct ldb_message *);
+
+
+/*
+ these function pointers define the operations that a ldb backend must perform
+ they correspond exactly to the ldb_*() interface
+*/
+struct ldb_backend_ops {
+ int (*close)(struct ldb_context *);
+ int (*search)(struct ldb_context *, const char *, enum ldb_scope,
+ const char *, const char *[], struct ldb_message ***);
+ int (*search_free)(struct ldb_context *, struct ldb_message **);
+ int (*add)(struct ldb_context *, const struct ldb_message *);
+ int (*modify)(struct ldb_context *, const struct ldb_message *);
+ int (*delete)(struct ldb_context *, const char *);
+ const char * (*errstring)(struct ldb_context *);
+};
+
+/*
+ every ldb connection is started by establishing a ldb_context
+*/
+struct ldb_context {
+ /* a private pointer for the backend to use */
+ void *private;
+
+ /* the operations provided by the backend */
+ const struct ldb_backend_ops *ops;
+};
+
+
+#define LDB_FLG_RDONLY 1
+
+/*
+ connect to a database. The URL can either be one of the following forms
+ ldb://path
+ ldapi://path
+
+ flags is made up of LDB_FLG_*
+
+ the options are passed uninterpreted to the backend, and are
+ backend specific
+*/
+struct ldb_context *ldb_connect(const char *url, unsigned int flags,
+ const char *options[]);
+
+/*
+ close the connection to the database
+*/
+int ldb_close(struct ldb_context *ldb);
+
+
+/*
+ search the database given a LDAP-like search expression
+
+ return the number of records found, or -1 on error
+*/
+int ldb_search(struct ldb_context *ldb,
+ const char *base,
+ enum ldb_scope scope,
+ const char *expression,
+ const char *attrs[], struct ldb_message ***res);
+
+/*
+ free a set of messages returned by ldb_search
+*/
+int ldb_search_free(struct ldb_context *ldb, struct ldb_message **msgs);
+
+
+/*
+ add a record to the database. Will fail if a record with the given class and key
+ already exists
+*/
+int ldb_add(struct ldb_context *ldb,
+ const struct ldb_message *message);
+
+/*
+ modify the specified attributes of a record
+*/
+int ldb_modify(struct ldb_context *ldb,
+ const struct ldb_message *message);
+
+/*
+ delete a record from the database
+*/
+int ldb_delete(struct ldb_context *ldb, const char *dn);
+
+
+/*
+ return extended error information from the last call
+*/
+const char *ldb_errstring(struct ldb_context *ldb);
+
+/*
+ ldif manipulation functions
+*/
+int ldif_write(int (*fprintf_fn)(void *, const char *, ...),
+ void *private,
+ const struct ldb_ldif *ldif);
+void ldif_read_free(struct ldb_ldif *);
+struct ldb_ldif *ldif_read(int (*fgetc_fn)(void *), void *private);
+struct ldb_ldif *ldif_read_file(FILE *f);
+struct ldb_ldif *ldif_read_string(const char *s);
+int ldif_write_file(FILE *f, const struct ldb_ldif *msg);
diff --git a/source/lib/ldb/include/ldb_parse.h b/source/lib/ldb/include/ldb_parse.h
new file mode 100644
index 00000000000..c0d5806cc9a
--- /dev/null
+++ b/source/lib/ldb/include/ldb_parse.h
@@ -0,0 +1,53 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb expression parse header
+ *
+ * Description: structure for expression parsing
+ *
+ * Author: Andrew Tridgell
+ */
+
+
+enum ldb_parse_op {LDB_OP_SIMPLE, LDB_OP_AND, LDB_OP_OR, LDB_OP_NOT};
+
+struct ldb_parse_tree {
+ enum ldb_parse_op operation;
+ union {
+ struct {
+ char *attr;
+ struct ldb_val value;
+ } simple;
+ struct {
+ unsigned int num_elements;
+ struct ldb_parse_tree **elements;
+ } list;
+ struct {
+ struct ldb_parse_tree *child;
+ } not;
+ } u;
+};
diff --git a/source/lib/ldb/include/proto.h b/source/lib/ldb/include/proto.h
new file mode 100644
index 00000000000..8690d96fee5
--- /dev/null
+++ b/source/lib/ldb/include/proto.h
@@ -0,0 +1,126 @@
+#ifndef _PROTO_H_
+#define _PROTO_H_
+
+/* This file is automatically generated with "make proto". DO NOT EDIT */
+
+
+/* The following definitions come from common/ldb.c */
+
+struct ldb_context *ldb_connect(const char *url, unsigned int flags,
+ const char *options[]);
+int ldb_close(struct ldb_context *ldb);
+int ldb_search(struct ldb_context *ldb,
+ const char *base,
+ enum ldb_scope scope,
+ const char *expression,
+ const char *attrs[], struct ldb_message ***res);
+int ldb_search_free(struct ldb_context *ldb, struct ldb_message **msgs);
+int ldb_add(struct ldb_context *ldb,
+ const struct ldb_message *message);
+int ldb_modify(struct ldb_context *ldb,
+ const struct ldb_message *message);
+int ldb_delete(struct ldb_context *ldb, const char *dn);
+const char *ldb_errstring(struct ldb_context *ldb);
+
+/* The following definitions come from common/ldb_ldif.c */
+
+char *ldb_base64_encode(const char *buf, int len);
+int ldb_should_b64_encode(const struct ldb_val *val);
+int ldif_write(int (*fprintf_fn)(void *, const char *, ...),
+ void *private,
+ const struct ldb_message *msg);
+void ldif_read_free(struct ldb_message *msg);
+struct ldb_message *ldif_read(int (*fgetc_fn)(void *), void *private);
+struct ldb_message *ldif_read_file(FILE *f);
+struct ldb_message *ldif_read_string(const char *s);
+int ldif_write_file(FILE *f, const struct ldb_message *msg);
+
+/* The following definitions come from common/ldb_parse.c */
+
+struct ldb_parse_tree *ldb_parse_tree(const char *s);
+void ldb_parse_tree_free(struct ldb_parse_tree *tree);
+
+/* The following definitions come from common/util.c */
+
+void *realloc_array(void *ptr, size_t el_size, unsigned count);
+int list_find(const void *needle,
+ const void *base, size_t nmemb, size_t size, comparison_fn_t comp_fn);
+
+/* The following definitions come from ldb_ldap/ldb_ldap.c */
+
+struct ldb_context *lldb_connect(const char *url,
+ unsigned int flags,
+ const char *options[]);
+
+/* The following definitions come from ldb_tdb/ldb_index.c */
+
+int ltdb_search_indexed(struct ldb_context *ldb,
+ const char *base,
+ enum ldb_scope scope,
+ struct ldb_parse_tree *tree,
+ const char *attrs[], struct ldb_message ***res);
+int ltdb_index_add(struct ldb_context *ldb, const struct ldb_message *msg);
+int ltdb_index_del(struct ldb_context *ldb, const struct ldb_message *msg);
+
+/* The following definitions come from ldb_tdb/ldb_match.c */
+
+int ldb_message_match(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ struct ldb_parse_tree *tree,
+ const char *base,
+ enum ldb_scope scope);
+
+/* The following definitions come from ldb_tdb/ldb_pack.c */
+
+int ltdb_pack_data(struct ldb_context *ctx,
+ const struct ldb_message *message,
+ struct TDB_DATA *data);
+int ltdb_unpack_data(struct ldb_context *ctx,
+ const struct TDB_DATA *data,
+ struct ldb_message *message);
+
+/* The following definitions come from ldb_tdb/ldb_search.c */
+
+int ldb_msg_find_attr(const struct ldb_message *msg, const char *attr);
+int ltdb_has_wildcard(const struct ldb_val *val);
+void ltdb_search_dn1_free(struct ldb_context *ldb, struct ldb_message *msg);
+int ltdb_search_dn1(struct ldb_context *ldb, const char *dn, struct ldb_message *msg);
+int ltdb_search_dn(struct ldb_context *ldb, char *dn,
+ const char *attrs[], struct ldb_message ***res);
+int ltdb_add_attr_results(struct ldb_context *ldb, struct ldb_message *msg,
+ const char *attrs[],
+ unsigned int *count,
+ struct ldb_message ***res);
+int ltdb_search_free(struct ldb_context *ldb, struct ldb_message **msgs);
+int ltdb_search(struct ldb_context *ldb, const char *base,
+ enum ldb_scope scope, const char *expression,
+ const char *attrs[], struct ldb_message ***res);
+
+/* The following definitions come from ldb_tdb/ldb_tdb.c */
+
+struct TDB_DATA ltdb_key(const char *dn);
+int ltdb_store(struct ldb_context *ldb, const struct ldb_message *msg, int flgs);
+int ltdb_delete_noindex(struct ldb_context *ldb, const char *dn);
+struct ldb_context *ltdb_connect(const char *url,
+ unsigned int flags,
+ const char *options[]);
+
+/* The following definitions come from ldb_tdb/ldbadd.c */
+
+
+/* The following definitions come from ldb_tdb/ldbdel.c */
+
+
+/* The following definitions come from ldb_tdb/ldbsearch.c */
+
+
+/* The following definitions come from tools/ldbadd.c */
+
+
+/* The following definitions come from tools/ldbdel.c */
+
+
+/* The following definitions come from tools/ldbsearch.c */
+
+
+#endif /* _PROTO_H_ */
diff --git a/source/lib/ldb/ldb_ldap/ldb_ldap.c b/source/lib/ldb/ldb_ldap/ldb_ldap.c
new file mode 100644
index 00000000000..e6cbb52cad8
--- /dev/null
+++ b/source/lib/ldb/ldb_ldap/ldb_ldap.c
@@ -0,0 +1,520 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb ldap backend
+ *
+ * Description: core files for LDAP backend
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb_ldap/ldb_ldap.h"
+
+#if 0
+/*
+ we don't need this right now, but will once we add some backend
+ options
+*/
+
+/*
+ find an option in an option list (a null terminated list of strings)
+
+ this assumes the list is short. If it ever gets long then we really
+ should do this in some smarter way
+ */
+static const char *lldb_option_find(const struct lldb_private *lldb, const char *name)
+{
+ int i;
+ size_t len = strlen(name);
+
+ if (!lldb->options) return NULL;
+
+ for (i=0;lldb->options[i];i++) {
+ if (strncmp(lldb->options[i], name, len) == 0 &&
+ lldb->options[i][len] == '=') {
+ return &lldb->options[i][len+1];
+ }
+ }
+
+ return NULL;
+}
+#endif
+
+/*
+ close/free the connection
+*/
+static int lldb_close(struct ldb_context *ldb)
+{
+ int i, ret = 0;
+ struct lldb_private *lldb = ldb->private;
+
+ if (ldap_unbind(lldb->ldap) != LDAP_SUCCESS) {
+ ret = -1;
+ }
+
+ if (lldb->options) {
+ for (i=0;lldb->options[i];i++) {
+ free(lldb->options[i]);
+ }
+ free(lldb->options);
+ }
+ free(lldb);
+ free(ldb);
+
+ return ret;
+}
+
+/*
+ delete a record
+*/
+static int lldb_delete(struct ldb_context *ldb, const char *dn)
+{
+ struct lldb_private *lldb = ldb->private;
+ int ret = 0;
+
+ lldb->last_rc = ldap_delete_s(lldb->ldap, dn);
+ if (lldb->last_rc != LDAP_SUCCESS) {
+ ret = -1;
+ }
+
+ return ret;
+}
+
+/*
+ free a search message
+*/
+static int lldb_msg_free(struct ldb_context *ldb, struct ldb_message *msg)
+{
+ int i, j;
+ free(msg->dn);
+ for (i=0;i<msg->num_elements;i++) {
+ free(msg->elements[i].name);
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ if (msg->elements[i].values[j].data) {
+ free(msg->elements[i].values[j].data);
+ }
+ }
+ free(msg->elements[i].values);
+ }
+ if (msg->elements) free(msg->elements);
+ free(msg);
+ return 0;
+}
+
+/*
+ free a search result
+*/
+static int lldb_search_free(struct ldb_context *ldb, struct ldb_message **res)
+{
+ int i;
+ for (i=0;res[i];i++) {
+ if (lldb_msg_free(ldb, res[i]) != 0) {
+ return -1;
+ }
+ }
+ free(res);
+ return 0;
+}
+
+
+/*
+ add a single set of ldap message values to a ldb_message
+*/
+static int lldb_add_msg_attr(struct ldb_message *msg,
+ const char *attr, struct berval **bval)
+{
+ int count, i;
+ struct ldb_message_element *el;
+
+ count = ldap_count_values_len(bval);
+
+ if (count <= 0) {
+ return -1;
+ }
+
+ el = realloc_p(msg->elements, struct ldb_message_element,
+ msg->num_elements + 1);
+ if (!el) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ msg->elements = el;
+
+ el = &msg->elements[msg->num_elements];
+
+ el->name = strdup(attr);
+ if (!el->name) {
+ errno = ENOMEM;
+ return -1;
+ }
+ el->flags = 0;
+
+ el->num_values = 0;
+ el->values = malloc_array_p(struct ldb_val, count);
+ if (!el->values) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ for (i=0;i<count;i++) {
+ el->values[i].data = malloc(bval[i]->bv_len);
+ if (!el->values[i].data) {
+ return -1;
+ }
+ memcpy(el->values[i].data, bval[i]->bv_val, bval[i]->bv_len);
+ el->values[i].length = bval[i]->bv_len;
+ el->num_values++;
+ }
+
+ msg->num_elements++;
+
+ return 0;
+}
+
+/*
+ search for matching records
+*/
+static int lldb_search(struct ldb_context *ldb, const char *base,
+ enum ldb_scope scope, const char *expression,
+ const char **attrs, struct ldb_message ***res)
+{
+ struct lldb_private *lldb = ldb->private;
+ int count, msg_count;
+ LDAPMessage *ldapres, *msg;
+
+ lldb->last_rc = ldap_search_s(lldb->ldap, base, (int)scope,
+ expression, attrs, 0, &ldapres);
+ if (lldb->last_rc != LDAP_SUCCESS) {
+ return -1;
+ }
+
+ count = ldap_count_entries(lldb->ldap, ldapres);
+ if (count == -1 || count == 0) {
+ ldap_msgfree(ldapres);
+ return count;
+ }
+
+ (*res) = malloc_array_p(struct ldb_message *, count+1);
+ if (! *res) {
+ ldap_msgfree(ldapres);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ (*res)[0] = NULL;
+
+ msg_count = 0;
+
+ /* loop over all messages */
+ for (msg=ldap_first_entry(lldb->ldap, ldapres);
+ msg;
+ msg=ldap_next_entry(lldb->ldap, msg)) {
+ BerElement *berptr = NULL;
+ char *attr, *dn;
+
+ if (msg_count == count) {
+ /* hmm, got too many? */
+ fprintf(stderr,"Too many messages?!\n");
+ break;
+ }
+
+ (*res)[msg_count] = malloc_p(struct ldb_message);
+ if (!(*res)[msg_count]) {
+ goto failed;
+ }
+ (*res)[msg_count+1] = NULL;
+
+ dn = ldap_get_dn(lldb->ldap, msg);
+ if (!dn) {
+ goto failed;
+ }
+
+ (*res)[msg_count]->dn = strdup(dn);
+ ldap_memfree(dn);
+ if (!(*res)[msg_count]->dn) {
+ goto failed;
+ }
+
+
+ (*res)[msg_count]->num_elements = 0;
+ (*res)[msg_count]->elements = NULL;
+ (*res)[msg_count]->private = NULL;
+
+ /* loop over all attributes */
+ for (attr=ldap_first_attribute(lldb->ldap, msg, &berptr);
+ attr;
+ attr=ldap_next_attribute(lldb->ldap, msg, berptr)) {
+ struct berval **bval;
+ bval = ldap_get_values_len(lldb->ldap, msg, attr);
+
+ if (bval) {
+ lldb_add_msg_attr((*res)[msg_count], attr, bval);
+ ldap_value_free_len(bval);
+ }
+
+ ldap_memfree(attr);
+ }
+ if (berptr) ber_free(berptr, 0);
+
+ msg_count++;
+ }
+
+ ldap_msgfree(ldapres);
+
+ return msg_count;
+
+failed:
+ if (*res) lldb_search_free(ldb, *res);
+ return -1;
+}
+
+
+/*
+ free a set of mods from lldb_msg_to_mods()
+*/
+static void lldb_mods_free(LDAPMod **mods)
+{
+ int i, j;
+
+ if (!mods) return;
+
+ for (i=0;mods[i];i++) {
+ if (mods[i]->mod_vals.modv_bvals) {
+ for (j=0;mods[i]->mod_vals.modv_bvals[j];j++) {
+ free(mods[i]->mod_vals.modv_bvals[j]);
+ }
+ free(mods[i]->mod_vals.modv_bvals);
+ }
+ free(mods[i]);
+ }
+ free(mods);
+}
+
+
+/*
+ convert a ldb_message structure to a list of LDAPMod structures
+ ready for ldap_add() or ldap_modify()
+*/
+static LDAPMod **lldb_msg_to_mods(const struct ldb_message *msg, int use_flags)
+{
+ LDAPMod **mods;
+ int i, j, num_mods = 0;
+
+ /* allocate maximum number of elements needed */
+ mods = malloc_array_p(LDAPMod *, msg->num_elements+1);
+ if (!mods) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ mods[0] = NULL;
+
+ for (i=0;i<msg->num_elements;i++) {
+ const struct ldb_message_element *el = &msg->elements[i];
+
+ mods[num_mods] = malloc_p(LDAPMod);
+ if (!mods[num_mods]) {
+ goto failed;
+ }
+ mods[num_mods+1] = NULL;
+ mods[num_mods]->mod_op = LDAP_MOD_BVALUES;
+ if (use_flags) {
+ switch (el->flags & LDB_FLAG_MOD_MASK) {
+ case LDB_FLAG_MOD_ADD:
+ mods[num_mods]->mod_op |= LDAP_MOD_ADD;
+ break;
+ case LDB_FLAG_MOD_DELETE:
+ mods[num_mods]->mod_op |= LDAP_MOD_DELETE;
+ break;
+ case LDB_FLAG_MOD_REPLACE:
+ mods[num_mods]->mod_op |= LDAP_MOD_REPLACE;
+ break;
+ }
+ }
+ mods[num_mods]->mod_type = el->name;
+ mods[num_mods]->mod_vals.modv_bvals = malloc_array_p(struct berval *,
+ 1+el->num_values);
+ if (!mods[num_mods]->mod_vals.modv_bvals) {
+ goto failed;
+ }
+
+ for (j=0;j<el->num_values;j++) {
+ mods[num_mods]->mod_vals.modv_bvals[j] = malloc_p(struct berval);
+ if (!mods[num_mods]->mod_vals.modv_bvals[j]) {
+ goto failed;
+ }
+ mods[num_mods]->mod_vals.modv_bvals[j]->bv_val = el->values[j].data;
+ mods[num_mods]->mod_vals.modv_bvals[j]->bv_len = el->values[j].length;
+ }
+ mods[num_mods]->mod_vals.modv_bvals[j] = NULL;
+ num_mods++;
+ }
+
+ return mods;
+
+failed:
+ lldb_mods_free(mods);
+ return NULL;
+}
+
+
+/*
+ add a record
+*/
+static int lldb_add(struct ldb_context *ldb, const struct ldb_message *msg)
+{
+ struct lldb_private *lldb = ldb->private;
+ LDAPMod **mods;
+ int ret = 0;
+
+ mods = lldb_msg_to_mods(msg, 0);
+
+ lldb->last_rc = ldap_add_s(lldb->ldap, msg->dn, mods);
+ if (lldb->last_rc != LDAP_SUCCESS) {
+ ret = -1;
+ }
+
+ lldb_mods_free(mods);
+
+ return ret;
+}
+
+
+/*
+ modify a record
+*/
+static int lldb_modify(struct ldb_context *ldb, const struct ldb_message *msg)
+{
+ struct lldb_private *lldb = ldb->private;
+ LDAPMod **mods;
+ int ret = 0;
+
+ mods = lldb_msg_to_mods(msg, 1);
+
+ lldb->last_rc = ldap_modify_s(lldb->ldap, msg->dn, mods);
+ if (lldb->last_rc != LDAP_SUCCESS) {
+ ret = -1;
+ }
+
+ lldb_mods_free(mods);
+
+ return ret;
+}
+
+
+/*
+ return extended error information
+*/
+static const char *lldb_errstring(struct ldb_context *ldb)
+{
+ struct lldb_private *lldb = ldb->private;
+ return ldap_err2string(lldb->last_rc);
+}
+
+
+static const struct ldb_backend_ops lldb_ops = {
+ lldb_close,
+ lldb_search,
+ lldb_search_free,
+ lldb_add,
+ lldb_modify,
+ lldb_delete,
+ lldb_errstring
+};
+
+
+/*
+ connect to the database
+*/
+struct ldb_context *lldb_connect(const char *url,
+ unsigned int flags,
+ const char *options[])
+{
+ struct ldb_context *ldb = NULL;
+ struct lldb_private *lldb = NULL;
+ int i;
+
+ ldb = malloc_p(struct ldb_context);
+ if (!ldb) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ lldb = malloc_p(struct lldb_private);
+ if (!lldb) {
+ free(ldb);
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ lldb->ldap = NULL;
+ lldb->options = NULL;
+
+ lldb->last_rc = ldap_initialize(&lldb->ldap, url);
+ if (lldb->last_rc != LDAP_SUCCESS) {
+ goto failed;
+ }
+
+ ldb->ops = &lldb_ops;
+ ldb->private = lldb;
+
+ if (options) {
+ /* take a copy of the options array, so we don't have to rely
+ on the caller keeping it around (it might be dynamic) */
+ for (i=0;options[i];i++) ;
+
+ lldb->options = malloc_array_p(char *, i+1);
+ if (!lldb->options) {
+ goto failed;
+ }
+
+ for (i=0;options[i];i++) {
+ lldb->options[i+1] = NULL;
+ lldb->options[i] = strdup(options[i]);
+ if (!lldb->options[i]) {
+ goto failed;
+ }
+ }
+ }
+
+ return ldb;
+
+failed:
+ if (lldb && lldb->options) {
+ for (i=0;lldb->options[i];i++) {
+ free(lldb->options[i]);
+ }
+ free(lldb->options);
+ }
+ if (lldb && lldb->ldap) {
+ ldap_unbind(lldb->ldap);
+ }
+ if (lldb) free(lldb);
+ if (ldb) free(ldb);
+ return NULL;
+}
diff --git a/source/lib/ldb/ldb_ldap/ldb_ldap.h b/source/lib/ldb/ldb_ldap/ldb_ldap.h
new file mode 100644
index 00000000000..ba68283abd5
--- /dev/null
+++ b/source/lib/ldb/ldb_ldap/ldb_ldap.h
@@ -0,0 +1,8 @@
+#include <ldap.h>
+
+struct lldb_private {
+ char **options;
+ const char *basedn;
+ LDAP *ldap;
+ int last_rc;
+};
diff --git a/source/lib/ldb/ldb_tdb/.cvsignore b/source/lib/ldb/ldb_tdb/.cvsignore
new file mode 100644
index 00000000000..8f968d06f49
--- /dev/null
+++ b/source/lib/ldb/ldb_tdb/.cvsignore
@@ -0,0 +1,7 @@
+ldbadd
+ldbsearch
+ldbdel
+test.ldb
+TAGS
+.*~
+*.o
diff --git a/source/lib/ldb/ldb_tdb/ldb_index.c b/source/lib/ldb/ldb_tdb/ldb_index.c
new file mode 100644
index 00000000000..8cda8abff89
--- /dev/null
+++ b/source/lib/ldb/ldb_tdb/ldb_index.c
@@ -0,0 +1,725 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb tdb backend - indexing
+ *
+ * Description: indexing routines for ldb tdb backend
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+
+struct dn_list {
+ unsigned int count;
+ char **dn;
+};
+
+/*
+ free a struct dn_list
+*/
+static void dn_list_free(struct dn_list *list)
+{
+ int i;
+ for (i=0;i<list->count;i++) {
+ free(list->dn[i]);
+ }
+ if (list->dn) free(list->dn);
+}
+
+/*
+ return the dn key to be used for an index
+ caller frees
+*/
+static char *ldb_dn_key(const char *attr, const struct ldb_val *value)
+{
+ char *ret = NULL;
+
+ if (ldb_should_b64_encode(value)) {
+ char *vstr = ldb_base64_encode(value->data, value->length);
+ if (!vstr) return NULL;
+ asprintf(&ret, "@INDEX:%s::%s", attr, vstr);
+ free(vstr);
+ return ret;
+ }
+
+ asprintf(&ret, "@INDEX:%s:%s", attr, (char *)value->data);
+ return ret;
+}
+
+/*
+ see if a attribute value is in the list of indexed attributes
+*/
+static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr,
+ int *v_idx)
+{
+ int i, j;
+ for (i=0;i<msg->num_elements;i++) {
+ if (strcmp(msg->elements[i].name, "@IDXATTR") == 0) {
+ const struct ldb_message_element *el =
+ &msg->elements[i];
+ for (j=0;j<el->num_values;j++) {
+ if (strcmp((char *)el->values[j].data, attr) == 0) {
+ if (v_idx) {
+ *v_idx = j;
+ }
+ return i;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+/*
+ return a list of dn's that might match a simple indexed search or
+ */
+static int ltdb_index_dn_simple(struct ldb_context *ldb,
+ struct ldb_parse_tree *tree,
+ const struct ldb_message *index_list,
+ struct dn_list *list)
+{
+ char *dn = NULL;
+ int ret, i, j;
+ struct ldb_message msg;
+
+ list->count = 0;
+ list->dn = NULL;
+
+ /*
+ if the value is a wildcard then we can't do a match via indexing
+ */
+ if (ltdb_has_wildcard(&tree->u.simple.value)) {
+ return -1;
+ }
+
+ /* if the attribute isn't in the list of indexed attributes then
+ this node needs a full search */
+ if (ldb_msg_find_idx(index_list, tree->u.simple.attr, NULL) == -1) {
+ return -1;
+ }
+
+ /* the attribute is indexed. Pull the list of DNs that match the
+ search criterion */
+ dn = ldb_dn_key(tree->u.simple.attr, &tree->u.simple.value);
+ if (!dn) return -1;
+
+ ret = ltdb_search_dn1(ldb, dn, &msg);
+ free(dn);
+ if (ret == 0 || ret == -1) {
+ return ret;
+ }
+
+ for (i=0;i<msg.num_elements;i++) {
+ struct ldb_message_element *el;
+
+ if (strcmp(msg.elements[i].name, "@IDX") != 0) {
+ continue;
+ }
+
+ el = &msg.elements[i];
+
+ list->dn = malloc_array_p(char *, el->num_values);
+ if (!list->dn) {
+ break;
+ }
+
+ for (j=0;j<el->num_values;j++) {
+ list->dn[list->count] =
+ strdup((char *)el->values[j].data);
+ if (!list->dn[list->count]) {
+ dn_list_free(list);
+ ltdb_search_dn1_free(ldb, &msg);
+ return -1;
+ }
+ list->count++;
+ }
+ }
+
+ ltdb_search_dn1_free(ldb, &msg);
+
+ qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t) strcmp);
+
+ return 1;
+}
+
+/*
+ list intersection
+ list = list & list2
+ relies on the lists being sorted
+*/
+static int list_intersect(struct dn_list *list, const struct dn_list *list2)
+{
+ struct dn_list list3;
+ int i;
+
+ if (list->count == 0 || list2->count == 0) {
+ /* 0 & X == 0 */
+ dn_list_free(list);
+ return 0;
+ }
+
+ list3.dn = malloc_array_p(char *, list->count);
+ if (!list3.dn) {
+ dn_list_free(list);
+ return -1;
+ }
+ list3.count = 0;
+
+ for (i=0;i<list->count;i++) {
+ if (list_find(list->dn[i], list2->dn, list2->count,
+ sizeof(char *), (comparison_fn_t)strcmp) != -1) {
+ list3.dn[list3.count] = list->dn[i];
+ list3.count++;
+ } else {
+ free(list->dn[i]);
+ }
+ }
+
+ free(list->dn);
+ list->dn = list3.dn;
+ list->count = list3.count;
+
+ return 0;
+}
+
+
+/*
+ list union
+ list = list | list2
+ relies on the lists being sorted
+*/
+static int list_union(struct dn_list *list, const struct dn_list *list2)
+{
+ int i;
+ char **d;
+ unsigned int count = list->count;
+
+ if (list->count == 0 && list2->count == 0) {
+ /* 0 | 0 == 0 */
+ dn_list_free(list);
+ return 0;
+ }
+
+ d = realloc_p(list->dn, char *, list->count + list2->count);
+ if (!d) {
+ dn_list_free(list);
+ return -1;
+ }
+ list->dn = d;
+
+ for (i=0;i<list2->count;i++) {
+ if (list_find(list2->dn[i], list->dn, count,
+ sizeof(char *), (comparison_fn_t)strcmp) == -1) {
+ list->dn[list->count] = strdup(list2->dn[i]);
+ if (!list->dn[list->count]) {
+ dn_list_free(list);
+ return -1;
+ }
+ list->count++;
+ }
+ }
+
+ if (list->count != count) {
+ qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t)strcmp);
+ }
+
+ return 0;
+}
+
+static int ltdb_index_dn(struct ldb_context *ldb,
+ struct ldb_parse_tree *tree,
+ const struct ldb_message *index_list,
+ struct dn_list *list);
+
+
+/*
+ OR two index results
+ */
+static int ltdb_index_dn_or(struct ldb_context *ldb,
+ struct ldb_parse_tree *tree,
+ const struct ldb_message *index_list,
+ struct dn_list *list)
+{
+ int ret, i;
+
+ ret = -1;
+ list->dn = NULL;
+ list->count = 0;
+
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ struct dn_list list2;
+ int v;
+ v = ltdb_index_dn(ldb, tree->u.list.elements[i], index_list, &list2);
+
+ if (v == 0) {
+ /* 0 || X == X */
+ if (ret == -1) {
+ ret = 0;
+ }
+ continue;
+ }
+
+ if (v == -1) {
+ /* 1 || X == 1 */
+ dn_list_free(list);
+ return -1;
+ }
+
+ if (ret == -1) {
+ ret = 1;
+ *list = list2;
+ } else {
+ if (list_union(list, &list2) == -1) {
+ dn_list_free(&list2);
+ return -1;
+ }
+ dn_list_free(&list2);
+ }
+ }
+
+ if (list->count == 0) {
+ dn_list_free(list);
+ return 0;
+ }
+
+ return ret;
+}
+
+
+/*
+ NOT an index results
+ */
+static int ltdb_index_dn_not(struct ldb_context *ldb,
+ struct ldb_parse_tree *tree,
+ const struct ldb_message *index_list,
+ struct dn_list *list)
+{
+ /* the only way to do an indexed not would be if we could
+ negate the not via another not or if we knew the total
+ number of database elements so we could know that the
+ existing expression covered the whole database.
+
+ instead, we just give up, and rely on a full index scan
+ (unless an outer & manages to reduce the list)
+ */
+ return -1;
+}
+
+/*
+ AND two index results
+ */
+static int ltdb_index_dn_and(struct ldb_context *ldb,
+ struct ldb_parse_tree *tree,
+ const struct ldb_message *index_list,
+ struct dn_list *list)
+{
+ int ret, i;
+
+ ret = -1;
+ list->dn = NULL;
+ list->count = 0;
+
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ struct dn_list list2;
+ int v;
+ v = ltdb_index_dn(ldb, tree->u.list.elements[i], index_list, &list2);
+
+ if (v == 0) {
+ /* 0 && X == 0 */
+ dn_list_free(list);
+ return 0;
+ }
+
+ if (v == -1) {
+ continue;
+ }
+
+ if (ret == -1) {
+ ret = 1;
+ *list = list2;
+ } else {
+ if (list_intersect(list, &list2) == -1) {
+ dn_list_free(&list2);
+ return -1;
+ }
+ dn_list_free(&list2);
+ }
+
+ if (list->count == 0) {
+ if (list->dn) free(list->dn);
+ return 0;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ return a list of dn's that might match a indexed search or
+ -1 if an error. return 0 for no matches, or 1 for matches
+ */
+static int ltdb_index_dn(struct ldb_context *ldb,
+ struct ldb_parse_tree *tree,
+ const struct ldb_message *index_list,
+ struct dn_list *list)
+{
+ int ret;
+
+ switch (tree->operation) {
+ case LDB_OP_SIMPLE:
+ ret = ltdb_index_dn_simple(ldb, tree, index_list, list);
+ break;
+
+ case LDB_OP_AND:
+ ret = ltdb_index_dn_and(ldb, tree, index_list, list);
+ break;
+
+ case LDB_OP_OR:
+ ret = ltdb_index_dn_or(ldb, tree, index_list, list);
+ break;
+
+ case LDB_OP_NOT:
+ ret = ltdb_index_dn_not(ldb, tree, index_list, list);
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ filter a candidate dn_list from an indexed search into a set of results
+ extracting just the given attributes
+*/
+static int ldb_index_filter(struct ldb_context *ldb, struct ldb_parse_tree *tree,
+ const char *base,
+ enum ldb_scope scope,
+ const struct dn_list *dn_list,
+ const char *attrs[], struct ldb_message ***res)
+{
+ int i;
+ unsigned int count = 0;
+
+ for (i=0;i<dn_list->count;i++) {
+ struct ldb_message msg;
+ int ret;
+ ret = ltdb_search_dn1(ldb, dn_list->dn[i], &msg);
+ if (ret == 0) {
+ /* the record has disappeared? yes, this can happen */
+ continue;
+ }
+
+ if (ret == -1) {
+ /* an internal error */
+ return -1;
+ }
+
+ if (ldb_message_match(ldb, &msg, tree, base, scope) == 1) {
+ ret = ltdb_add_attr_results(ldb, &msg, attrs, &count, res);
+ }
+ ltdb_search_dn1_free(ldb, &msg);
+ if (ret != 0) {
+ return -1;
+ }
+ }
+
+ return count;
+}
+
+/*
+ search the database with a LDAP-like expression using indexes
+ returns -1 if an indexed search is not possible, in which
+ case the caller should call ltdb_search_full()
+*/
+int ltdb_search_indexed(struct ldb_context *ldb,
+ const char *base,
+ enum ldb_scope scope,
+ struct ldb_parse_tree *tree,
+ const char *attrs[], struct ldb_message ***res)
+{
+ struct ldb_message index_list;
+ struct dn_list dn_list;
+ int ret;
+
+ /* find the list of indexed fields */
+ ret = ltdb_search_dn1(ldb, "@INDEXLIST", &index_list);
+ if (ret != 1) {
+ /* no index list? must do full search */
+ return -1;
+ }
+
+ ret = ltdb_index_dn(ldb, tree, &index_list, &dn_list);
+ ltdb_search_dn1_free(ldb, &index_list);
+
+ if (ret == 1) {
+ /* we've got a candidate list - now filter by the full tree
+ and extract the needed attributes */
+ ret = ldb_index_filter(ldb, tree, base, scope, &dn_list,
+ attrs, res);
+ dn_list_free(&dn_list);
+ }
+
+ return ret;
+}
+
+/*
+ add a index element where this is the first indexed DN for this value
+*/
+static int ltdb_index_add1_new(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ struct ldb_message_element *el,
+ const char *dn)
+{
+ struct ldb_message_element *el2;
+
+ /* add another entry */
+ el2 = realloc_p(msg->elements, struct ldb_message_element, msg->num_elements+1);
+ if (!el2) {
+ return -1;
+ }
+
+ msg->elements = el2;
+ msg->elements[msg->num_elements].name = "@IDX";
+ msg->elements[msg->num_elements].num_values = 0;
+ msg->elements[msg->num_elements].values = malloc_p(struct ldb_val);
+ if (!msg->elements[msg->num_elements].values) {
+ return -1;
+ }
+ msg->elements[msg->num_elements].values[0].length = strlen(dn);
+ msg->elements[msg->num_elements].values[0].data = dn;
+ msg->elements[msg->num_elements].num_values = 1;
+ msg->num_elements++;
+
+ return 0;
+}
+
+
+/*
+ add a index element where this is not the first indexed DN for this
+ value
+*/
+static int ltdb_index_add1_add(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ struct ldb_message_element *el,
+ int idx,
+ const char *dn)
+{
+ struct ldb_val *v2;
+
+ v2 = realloc_p(msg->elements[idx].values,
+ struct ldb_val,
+ msg->elements[idx].num_values+1);
+ if (!v2) {
+ return -1;
+ }
+ msg->elements[idx].values = v2;
+
+ msg->elements[idx].values[msg->elements[idx].num_values].length = strlen(dn);
+ msg->elements[idx].values[msg->elements[idx].num_values].data = dn;
+ msg->elements[idx].num_values++;
+
+ return 0;
+}
+
+/*
+ add an index entry for one message element
+*/
+static int ltdb_index_add1(struct ldb_context *ldb, const char *dn,
+ struct ldb_message_element *el, int v_idx)
+{
+ struct ldb_message msg;
+ char *dn_key;
+ int ret, i;
+
+ dn_key = ldb_dn_key(el->name, &el->values[v_idx]);
+ if (!dn_key) {
+ return -1;
+ }
+
+ ret = ltdb_search_dn1(ldb, dn_key, &msg);
+ if (ret == -1) {
+ free(dn_key);
+ return -1;
+ }
+
+ if (ret == 0) {
+ msg.dn = strdup(dn_key);
+ if (!msg.dn) {
+ free(dn_key);
+ errno = ENOMEM;
+ return -1;
+ }
+ msg.num_elements = 0;
+ msg.elements = NULL;
+ msg.private = NULL;
+ }
+
+ free(dn_key);
+
+ for (i=0;i<msg.num_elements;i++) {
+ if (strcmp("@IDX", msg.elements[i].name) == 0) {
+ break;
+ }
+ }
+
+ if (i == msg.num_elements) {
+ ret = ltdb_index_add1_new(ldb, &msg, el, dn);
+ } else {
+ ret = ltdb_index_add1_add(ldb, &msg, el, i, dn);
+ }
+
+ if (ret == 0) {
+ ret = ltdb_store(ldb, &msg, TDB_REPLACE);
+ }
+
+ ltdb_search_dn1_free(ldb, &msg);
+
+ return ret;
+}
+
+/*
+ add the index entries for a new record
+ return -1 on failure
+*/
+int ltdb_index_add(struct ldb_context *ldb, const struct ldb_message *msg)
+{
+ int ret, i, j;
+ struct ldb_message index_list;
+
+ /* find the list of indexed fields */
+ ret = ltdb_search_dn1(ldb, "@INDEXLIST", &index_list);
+ if (ret != 1) {
+ /* no indexed fields or an error */
+ return ret;
+ }
+
+ for (i=0;i<msg->num_elements;i++) {
+ ret = ldb_msg_find_idx(&index_list, msg->elements[i].name, NULL);
+ if (ret == -1) {
+ continue;
+ }
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ ret = ltdb_index_add1(ldb, msg->dn, &msg->elements[i], j);
+ if (ret == -1) {
+ ltdb_search_dn1_free(ldb, &index_list);
+ return -1;
+ }
+ }
+ }
+
+ ltdb_search_dn1_free(ldb, &index_list);
+
+ return 0;
+}
+
+
+/*
+ delete an index entry for one message element
+*/
+static int ltdb_index_del1(struct ldb_context *ldb, const char *dn,
+ struct ldb_message_element *el, int v_idx)
+{
+ struct ldb_message msg;
+ char *dn_key;
+ int ret, i, j;
+
+ dn_key = ldb_dn_key(el->name, &el->values[v_idx]);
+ if (!dn_key) {
+ return -1;
+ }
+
+ ret = ltdb_search_dn1(ldb, dn_key, &msg);
+ if (ret == -1) {
+ free(dn_key);
+ return -1;
+ }
+
+ if (ret == 0) {
+ /* it wasn't indexed. Did we have an earlier error? If we did then
+ its gone now */
+ ltdb_search_dn1_free(ldb, &msg);
+ return 0;
+ }
+
+ i = ldb_msg_find_idx(&msg, dn, &j);
+ if (i == -1) {
+ /* it ain't there. hmmm */
+ ltdb_search_dn1_free(ldb, &msg);
+ return 0;
+ }
+
+ if (j != msg.elements[i].num_values - 1) {
+ memmove(&msg.elements[i].values[j],
+ &msg.elements[i].values[j+1],
+ (msg.elements[i].num_values-1) *
+ sizeof(msg.elements[i].values[0]));
+ }
+ msg.elements[i].num_values--;
+
+ if (msg.elements[i].num_values == 0) {
+ ret = ltdb_delete_noindex(ldb, dn_key);
+ } else {
+ ret = ltdb_store(ldb, &msg, TDB_REPLACE);
+ }
+
+ ltdb_search_dn1_free(ldb, &msg);
+
+ return ret;
+}
+
+/*
+ delete the index entries for a record
+ return -1 on failure
+*/
+int ltdb_index_del(struct ldb_context *ldb, const struct ldb_message *msg)
+{
+ int ret, i, j;
+ struct ldb_message index_list;
+
+ /* find the list of indexed fields */
+ ret = ltdb_search_dn1(ldb, "@INDEXLIST", &index_list);
+ if (ret != 1) {
+ /* no indexed fields or an error */
+ return ret;
+ }
+
+ for (i=0;i<msg->num_elements;i++) {
+ ret = ldb_msg_find_idx(&index_list, msg->elements[i].name, NULL);
+ if (ret == -1) {
+ continue;
+ }
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ ret = ltdb_index_del1(ldb, msg->dn, &msg->elements[i], j);
+ if (ret == -1) {
+ ltdb_search_dn1_free(ldb, &index_list);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/source/lib/ldb/ldb_tdb/ldb_match.c b/source/lib/ldb/ldb_tdb/ldb_match.c
new file mode 100644
index 00000000000..6f29726ee7c
--- /dev/null
+++ b/source/lib/ldb/ldb_tdb/ldb_match.c
@@ -0,0 +1,182 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb expression matching
+ *
+ * Description: ldb expression matching for tdb backend
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+
+
+/*
+ see if two ldb_val structures contain the same data
+ return 1 for a match, 0 for a mis-match
+*/
+int ldb_val_equal(const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ if (v1->length != v2->length) return 0;
+
+ if (v1->length == 0) return 1;
+
+ if (memcmp(v1->data, v2->data, v1->length) == 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ check if the scope matches in a search result
+*/
+static int scope_match(const char *dn, const char *base, enum ldb_scope scope)
+{
+ size_t dn_len, base_len;
+
+ if (base == NULL) {
+ return 1;
+ }
+
+ base_len = strlen(base);
+ dn_len = strlen(dn);
+
+ if (strcmp(dn, base) == 0) {
+ return 1;
+ }
+
+ if (base_len+1 >= dn_len) {
+ return 0;
+ }
+
+ switch (scope) {
+ case LDB_SCOPE_BASE:
+ break;
+
+ case LDB_SCOPE_ONELEVEL:
+ if (strcmp(dn + (dn_len - base_len), base) == 0 &&
+ dn[dn_len - base_len - 1] == ',' &&
+ strchr(dn, ',') == &dn[dn_len - base_len - 1]) {
+ return 1;
+ }
+ break;
+
+ case LDB_SCOPE_SUBTREE:
+ default:
+ if (strcmp(dn + (dn_len - base_len), base) == 0 &&
+ dn[dn_len - base_len - 1] == ',') {
+ return 1;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+
+/*
+ match a leaf node
+*/
+static int match_leaf(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ struct ldb_parse_tree *tree,
+ const char *base,
+ enum ldb_scope scope)
+{
+ int i, j;
+
+ if (!scope_match(msg->dn, base, scope)) {
+ return 0;
+ }
+
+ if (strcmp(tree->u.simple.attr, "dn") == 0) {
+ if (strcmp(tree->u.simple.value.data, "*") == 0) {
+ return 1;
+ }
+ return strcmp(msg->dn, tree->u.simple.value.data) == 0;
+ }
+
+ for (i=0;i<msg->num_elements;i++) {
+ if (strcmp(msg->elements[i].name, tree->u.simple.attr) == 0) {
+ if (strcmp(tree->u.simple.value.data, "*") == 0) {
+ return 1;
+ }
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ if (ldb_val_equal(&msg->elements[i].values[j],
+ &tree->u.simple.value)) {
+ return 1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ return 0 if the given parse tree matches the given message. Assumes
+ the message is in sorted order
+
+ return 1 if it matches, and 0 if it doesn't match
+
+ this is a recursive function, and does short-circuit evaluation
+ */
+int ldb_message_match(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ struct ldb_parse_tree *tree,
+ const char *base,
+ enum ldb_scope scope)
+{
+ int v, i;
+
+ switch (tree->operation) {
+ case LDB_OP_SIMPLE:
+ break;
+
+ case LDB_OP_NOT:
+ return ! ldb_message_match(ldb, msg, tree->u.not.child, base, scope);
+
+ case LDB_OP_AND:
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ v = ldb_message_match(ldb, msg, tree->u.list.elements[i],
+ base, scope);
+ if (!v) return 0;
+ }
+ return 1;
+
+ case LDB_OP_OR:
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ v = ldb_message_match(ldb, msg, tree->u.list.elements[i],
+ base, scope);
+ if (v) return 1;
+ }
+ return 0;
+ }
+
+ return match_leaf(ldb, msg, tree, base, scope);
+}
diff --git a/source/lib/ldb/ldb_tdb/ldb_pack.c b/source/lib/ldb/ldb_tdb/ldb_pack.c
new file mode 100644
index 00000000000..1b0c8a18577
--- /dev/null
+++ b/source/lib/ldb/ldb_tdb/ldb_pack.c
@@ -0,0 +1,218 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb pack/unpack
+ *
+ * Description: pack/unpack routines for ldb messages as key/value blobs
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb_tdb/ldb_tdb.h"
+
+/* change this if the data format ever changes */
+#define LTDB_PACKING_FORMAT 0x26011966
+
+/*
+ pack a ldb message into a linear buffer in a TDB_DATA
+
+ note that this routine avoids saving elements with zero values,
+ as these are equivalent to having no element
+
+ caller frees the data buffer after use
+*/
+int ltdb_pack_data(struct ldb_context *ctx,
+ const struct ldb_message *message,
+ struct TDB_DATA *data)
+{
+ int i, j;
+ size_t size;
+ char *p;
+
+ /* work out how big it needs to be */
+ size = 8;
+
+ for (i=0;i<message->num_elements;i++) {
+ if (message->elements[i].num_values == 0) {
+ continue;
+ }
+ size += 1 + strlen(message->elements[i].name) + 4;
+ for (j=0;j<message->elements[i].num_values;j++) {
+ size += 4 + message->elements[i].values[j].length + 1;
+ }
+ }
+
+ /* allocate it */
+ data->dptr = malloc(size);
+ if (!data->dptr) {
+ errno = ENOMEM;
+ return -1;
+ }
+ data->dsize = size;
+
+ p = data->dptr;
+ SIVAL(p, 0, LTDB_PACKING_FORMAT);
+ SIVAL(p, 4, message->num_elements);
+ p += 8;
+
+ for (i=0;i<message->num_elements;i++) {
+ size_t len;
+ if (message->elements[i].num_values == 0) {
+ continue;
+ }
+ len = strlen(message->elements[i].name);
+ memcpy(p, message->elements[i].name, len+1);
+ p += len + 1;
+ SIVAL(p, 0, message->elements[i].num_values);
+ p += 4;
+ for (j=0;j<message->elements[i].num_values;j++) {
+ SIVAL(p, 0, message->elements[i].values[j].length);
+ memcpy(p+4, message->elements[i].values[j].data,
+ message->elements[i].values[j].length);
+ p[4+message->elements[i].values[j].length] = 0;
+ p += 4 + message->elements[i].values[j].length + 1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ free the memory allocated from a ltdb_unpack_data()
+*/
+void ltdb_unpack_data_free(struct ldb_message *message)
+{
+ int i;
+
+ for (i=0;i<message->num_elements;i++) {
+ if (message->elements[i].values) free(message->elements[i].values);
+ }
+ if (message->elements) free(message->elements);
+}
+
+
+/*
+ unpack a ldb message from a linear buffer in TDB_DATA
+
+ note that this does not fill in the class and key elements
+
+ caller frees. Memory for the elements[] and values[] arrays are
+ malloced, but the memory for the elements is re-used from the
+ TDB_DATA data. This means the caller only has to free the elements
+ and values arrays. This can be done with ltdb_unpack_data_free()
+*/
+int ltdb_unpack_data(struct ldb_context *ctx,
+ const struct TDB_DATA *data,
+ struct ldb_message *message)
+{
+ char *p;
+ unsigned int remaining;
+ int i, j;
+
+ message->elements = NULL;
+
+ p = data->dptr;
+ if (data->dsize < 4) {
+ errno = EIO;
+ goto failed;
+ }
+
+ if (IVAL(p, 0) != LTDB_PACKING_FORMAT) {
+ /* this is where we will cope with upgrading the
+ format if/when the format is ever changed */
+ errno = EIO;
+ goto failed;
+ }
+
+ message->num_elements = IVAL(p, 4);
+ p += 8;
+
+ if (message->num_elements == 0) {
+ message->elements = NULL;
+ return 0;
+ }
+
+ /* basic sanity check */
+ remaining = data->dsize - 8;
+
+ if (message->num_elements > remaining / 6) {
+ errno = EIO;
+ goto failed;
+ }
+
+ message->elements = malloc_array_p(struct ldb_message_element,
+ message->num_elements);
+
+ if (!message->elements) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ for (i=0;i<message->num_elements;i++) {
+ size_t len;
+ if (remaining < 10) {
+ errno = EIO;
+ goto failed;
+ }
+ len = strnlen(p, remaining-6);
+ message->elements[i].flags = 0;
+ message->elements[i].name = p;
+ remaining -= len + 1;
+ p += len + 1;
+ message->elements[i].num_values = IVAL(p, 0);
+ message->elements[i].values = NULL;
+ if (message->elements[i].num_values != 0) {
+ message->elements[i].values = malloc_array_p(struct ldb_val,
+ message->elements[i].num_values);
+ if (!message->elements[i].values) {
+ errno = ENOMEM;
+ goto failed;
+ }
+ }
+ p += 4;
+ for (j=0;j<message->elements[i].num_values;j++) {
+ len = IVAL(p, 0);
+ if (len > remaining-5) {
+ errno = EIO;
+ goto failed;
+ }
+
+ message->elements[i].values[j].length = len;
+ message->elements[i].values[j].data = p+4;
+ remaining -= len+4+1;
+ p += len+4+1;
+ }
+ }
+
+ return 0;
+
+failed:
+ ltdb_unpack_data_free(message);
+
+ return -1;
+}
diff --git a/source/lib/ldb/ldb_tdb/ldb_search.c b/source/lib/ldb/ldb_tdb/ldb_search.c
new file mode 100644
index 00000000000..d7a7b7ffbd5
--- /dev/null
+++ b/source/lib/ldb/ldb_tdb/ldb_search.c
@@ -0,0 +1,508 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb search functions
+ *
+ * Description: functions to search ldb+tdb databases
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb_tdb/ldb_tdb.h"
+
+/*
+ free a message that has all parts separately allocated
+*/
+static void msg_free_all_parts(struct ldb_message *msg)
+{
+ int i, j;
+ if (msg->dn) free(msg->dn);
+ for (i=0;i<msg->num_elements;i++) {
+ if (msg->elements[i].name) free(msg->elements[i].name);
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ if (msg->elements[i].values[j].data)
+ free(msg->elements[i].values[j].data);
+ }
+ if (msg->elements[i].values) free(msg->elements[i].values);
+ }
+ free(msg->elements);
+ free(msg);
+}
+
+
+/*
+ TODO: this should take advantage of the sorted nature of the message
+
+ return index of the attribute, or -1 if not found
+*/
+int ldb_msg_find_attr(const struct ldb_message *msg, const char *attr)
+{
+ int i;
+ for (i=0;i<msg->num_elements;i++) {
+ if (strcmp(msg->elements[i].name, attr) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/*
+ duplicate a ldb_val structure
+*/
+struct ldb_val ldb_val_dup(const struct ldb_val *v)
+{
+ struct ldb_val v2;
+ v2.length = v->length;
+ if (v->length == 0) {
+ v2.data = NULL;
+ return v2;
+ }
+
+ /* the +1 is to cope with buggy C library routines like strndup
+ that look one byte beyond */
+ v2.data = malloc(v->length+1);
+ if (!v2.data) {
+ v2.length = 0;
+ return v2;
+ }
+
+ memcpy(v2.data, v->data, v->length);
+ ((char *)v2.data)[v->length] = 0;
+ return v2;
+}
+
+
+
+/*
+ add one element to a message
+*/
+static int msg_add_element(struct ldb_message *ret, const struct ldb_message_element *el)
+{
+ int i;
+ struct ldb_message_element *e2, *elnew;
+
+ e2 = realloc_p(ret->elements, struct ldb_message_element, ret->num_elements+1);
+ if (!e2) {
+ return -1;
+ }
+ ret->elements = e2;
+
+ elnew = &e2[ret->num_elements];
+
+ elnew->name = strdup(el->name);
+ if (!elnew->name) {
+ return -1;
+ }
+
+ if (el->num_values) {
+ elnew->values = malloc_array_p(struct ldb_val, el->num_values);
+ if (!elnew->values) {
+ return -1;
+ }
+ } else {
+ elnew->values = NULL;
+ }
+
+ for (i=0;i<el->num_values;i++) {
+ elnew->values[i] = ldb_val_dup(&el->values[i]);
+ if (elnew->values[i].length != el->values[i].length) {
+ return -1;
+ }
+ }
+
+ elnew->num_values = el->num_values;
+
+ ret->num_elements++;
+
+ return 0;
+}
+
+/*
+ add all elements from one message into another
+ */
+static int msg_add_all_elements(struct ldb_message *ret,
+ const struct ldb_message *msg)
+{
+ int i;
+ for (i=0;i<msg->num_elements;i++) {
+ if (msg_add_element(ret, &msg->elements[i]) != 0) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ pull the specified list of attributes from a message
+ */
+static struct ldb_message *ltdb_pull_attrs(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const char **attrs)
+{
+ struct ldb_message *ret;
+ int i;
+
+ ret = malloc_p(struct ldb_message);
+ if (!ret) {
+ return NULL;
+ }
+
+ ret->dn = strdup(msg->dn);
+ if (!ret->dn) {
+ free(ret);
+ return NULL;
+ }
+
+ ret->num_elements = 0;
+ ret->elements = NULL;
+ ret->private = NULL;
+
+ if (!attrs) {
+ if (msg_add_all_elements(ret, msg) != 0) {
+ msg_free_all_parts(ret);
+ return NULL;
+ }
+ return ret;
+ }
+
+ for (i=0;attrs[i];i++) {
+ int j;
+
+ if (strcmp(attrs[i], "*") == 0) {
+ if (msg_add_all_elements(ret, msg) != 0) {
+ msg_free_all_parts(ret);
+ return NULL;
+ }
+ continue;
+ }
+ j = ldb_msg_find_attr(msg, attrs[i]);
+ if (j == -1) {
+ continue;
+ }
+ do {
+ if (msg_add_element(ret, &msg->elements[j]) != 0) {
+ msg_free_all_parts(ret);
+ return NULL;
+ }
+ } while (++j < msg->num_elements &&
+ strcmp(attrs[i], msg->elements[j].name) == 0);
+ }
+
+ return ret;
+}
+
+
+
+/*
+ see if a ldb_val is a wildcard
+*/
+int ltdb_has_wildcard(const struct ldb_val *val)
+{
+ if (val->length == 1 && ((char *)val->data)[0] == '*') {
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ free the results of a ltdb_search_dn1 search
+*/
+void ltdb_search_dn1_free(struct ldb_context *ldb, struct ldb_message *msg)
+{
+ int i;
+ if (msg->dn) free(msg->dn);
+ if (msg->private) free(msg->private);
+ for (i=0;i<msg->num_elements;i++) {
+ if (msg->elements[i].values) free(msg->elements[i].values);
+ }
+ if (msg->elements) free(msg->elements);
+}
+
+
+/*
+ search the database for a single simple dn, returning all attributes
+ in a single message
+
+ return 1 on success, 0 on record-not-found and -1 on error
+*/
+int ltdb_search_dn1(struct ldb_context *ldb, const char *dn, struct ldb_message *msg)
+{
+ struct ltdb_private *ltdb = ldb->private;
+ int ret;
+ TDB_DATA tdb_key, tdb_data;
+
+ /* form the key */
+ tdb_key = ltdb_key(dn);
+ if (!tdb_key.dptr) {
+ return -1;
+ }
+
+ tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
+ free(tdb_key.dptr);
+ if (!tdb_data.dptr) {
+ return 0;
+ }
+
+ msg->dn = strdup(dn);
+ if (!msg->dn) {
+ free(tdb_data.dptr);
+ return -1;
+ }
+ msg->private = tdb_data.dptr;
+ msg->num_elements = 0;
+ msg->elements = NULL;
+
+ ret = ltdb_unpack_data(ldb, &tdb_data, msg);
+ if (ret == -1) {
+ free(tdb_data.dptr);
+ return -1;
+ }
+
+ return 1;
+}
+
+
+/*
+ search the database for a single simple dn
+*/
+int ltdb_search_dn(struct ldb_context *ldb, char *dn,
+ const char *attrs[], struct ldb_message ***res)
+{
+ int ret;
+ struct ldb_message msg, *msg2;
+
+ ret = ltdb_search_dn1(ldb, dn, &msg);
+ if (ret != 1) {
+ return ret;
+ }
+
+ msg2 = ltdb_pull_attrs(ldb, &msg, attrs);
+
+ ltdb_search_dn1_free(ldb, &msg);
+
+ if (!msg2) {
+ return -1;
+ }
+
+ *res = malloc_array_p(struct ldb_message *, 2);
+ if (! *res) {
+ msg_free_all_parts(msg2);
+ return -1;
+ }
+
+ (*res)[0] = msg2;
+ (*res)[1] = NULL;
+
+ return 1;
+}
+
+
+/*
+ add a set of attributes from a record to a set of results
+ return 0 on success, -1 on failure
+*/
+int ltdb_add_attr_results(struct ldb_context *ldb, struct ldb_message *msg,
+ const char *attrs[],
+ unsigned int *count,
+ struct ldb_message ***res)
+{
+ struct ldb_message *msg2;
+ struct ldb_message **res2;
+
+ /* pull the attributes that the user wants */
+ msg2 = ltdb_pull_attrs(ldb, msg, attrs);
+ if (!msg2) {
+ return -1;
+ }
+
+ /* add to the results list */
+ res2 = realloc_p(*res, struct ldb_message *, (*count)+2);
+ if (!res2) {
+ msg_free_all_parts(msg2);
+ return -1;
+ }
+
+ (*res) = res2;
+
+ (*res)[*count] = msg2;
+ (*res)[(*count)+1] = NULL;
+ (*count)++;
+
+ return 0;
+}
+
+
+/*
+ internal search state during a full db search
+*/
+struct ltdb_search_info {
+ struct ldb_context *ldb;
+ struct ldb_parse_tree *tree;
+ const char *base;
+ enum ldb_scope scope;
+ const char **attrs;
+ struct ldb_message **msgs;
+ int failures;
+ int count;
+};
+
+
+/*
+ search function for a non-indexed search
+ */
+static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
+{
+ struct ltdb_search_info *sinfo = state;
+ struct ldb_message msg;
+ int ret;
+
+ if (key.dsize < 4 ||
+ strncmp(key.dptr, "DN=", 3) != 0) {
+ return 0;
+ }
+
+ msg.dn = key.dptr + 3;
+
+ /* unpack the record */
+ ret = ltdb_unpack_data(sinfo->ldb, &data, &msg);
+ if (ret == -1) {
+ sinfo->failures++;
+ return 0;
+ }
+
+ /* see if it matches the given expression */
+ if (!ldb_message_match(sinfo->ldb, &msg, sinfo->tree,
+ sinfo->base, sinfo->scope)) {
+ ltdb_unpack_data_free(&msg);
+ return 0;
+ }
+
+ ret = ltdb_add_attr_results(sinfo->ldb, &msg, sinfo->attrs, &sinfo->count, &sinfo->msgs);
+
+ if (ret == -1) {
+ sinfo->failures++;
+ }
+
+ ltdb_unpack_data_free(&msg);
+
+ return ret;
+}
+
+
+/*
+ free a set of search results
+*/
+int ltdb_search_free(struct ldb_context *ldb, struct ldb_message **msgs)
+{
+ int i;
+
+ if (!msgs) return 0;
+
+ for (i=0;msgs[i];i++) {
+ msg_free_all_parts(msgs[i]);
+ }
+
+ free(msgs);
+
+ return 0;
+}
+
+/*
+ search the database with a LDAP-like expression.
+ this is the "full search" non-indexed varient
+*/
+static int ltdb_search_full(struct ldb_context *ldb,
+ const char *base,
+ enum ldb_scope scope,
+ struct ldb_parse_tree *tree,
+ const char *attrs[], struct ldb_message ***res)
+{
+ struct ltdb_private *ltdb = ldb->private;
+ int ret;
+ struct ltdb_search_info sinfo;
+
+ sinfo.tree = tree;
+ sinfo.ldb = ldb;
+ sinfo.scope = scope;
+ sinfo.base = base;
+ sinfo.attrs = attrs;
+ sinfo.msgs = NULL;
+ sinfo.count = 0;
+ sinfo.failures = 0;
+
+ ret = tdb_traverse(ltdb->tdb, search_func, &sinfo);
+
+ if (ret == -1) {
+ ltdb_search_free(ldb, sinfo.msgs);
+ return -1;
+ }
+
+ *res = sinfo.msgs;
+ return sinfo.count;
+}
+
+
+/*
+ search the database with a LDAP-like expression.
+ choses a search method
+*/
+int ltdb_search(struct ldb_context *ldb, const char *base,
+ enum ldb_scope scope, const char *expression,
+ const char *attrs[], struct ldb_message ***res)
+{
+ struct ldb_parse_tree *tree;
+ int ret;
+
+ *res = NULL;
+
+ /* form a parse tree for the expression */
+ tree = ldb_parse_tree(expression);
+ if (!tree) {
+ return -1;
+ }
+
+ if (tree->operation == LDB_OP_SIMPLE &&
+ strcmp(tree->u.simple.attr, "dn") == 0 &&
+ !ltdb_has_wildcard(&tree->u.simple.value)) {
+ /* yay! its a nice simple one */
+ ret = ltdb_search_dn(ldb, tree->u.simple.value.data, attrs, res);
+ } else {
+ ret = ltdb_search_indexed(ldb, base, scope, tree, attrs, res);
+ if (ret == -1) {
+ ret = ltdb_search_full(ldb, base, scope, tree, attrs, res);
+ }
+ }
+
+ ldb_parse_tree_free(tree);
+
+ return ret;
+}
+
diff --git a/source/lib/ldb/ldb_tdb/ldb_tdb.c b/source/lib/ldb/ldb_tdb/ldb_tdb.c
new file mode 100644
index 00000000000..95dce498f12
--- /dev/null
+++ b/source/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -0,0 +1,542 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb tdb backend
+ *
+ * Description: core functions for tdb backend
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb_tdb/ldb_tdb.h"
+
+/*
+ form a TDB_DATA for a record key
+ caller frees
+*/
+struct TDB_DATA ltdb_key(const char *dn)
+{
+ TDB_DATA key;
+ char *key_str = NULL;
+
+ asprintf(&key_str, "DN=%s", dn);
+ if (!key_str) {
+ errno = ENOMEM;
+ key.dptr = NULL;
+ key.dsize = 0;
+ return key;
+ }
+
+ key.dptr = key_str;
+ key.dsize = strlen(key_str)+1;
+
+ return key;
+}
+
+/*
+ lock the database for write - currently a single lock is used
+*/
+static int ltdb_lock(struct ldb_context *ldb)
+{
+ struct ltdb_private *ltdb = ldb->private;
+ TDB_DATA key;
+ int ret;
+
+ key = ltdb_key("LDBLOCK");
+ if (!key.dptr) {
+ return -1;
+ }
+
+ ret = tdb_chainlock(ltdb->tdb, key);
+
+ free(key.dptr);
+
+ return ret;
+}
+
+/*
+ unlock the database after a ltdb_lock()
+*/
+static void ltdb_unlock(struct ldb_context *ldb)
+{
+ struct ltdb_private *ltdb = ldb->private;
+ TDB_DATA key;
+
+ key = ltdb_key("LDBLOCK");
+ if (!key.dptr) {
+ return;
+ }
+
+ tdb_chainunlock(ltdb->tdb, key);
+
+ free(key.dptr);
+}
+
+/*
+ store a record into the db
+*/
+int ltdb_store(struct ldb_context *ldb, const struct ldb_message *msg, int flgs)
+{
+ struct ltdb_private *ltdb = ldb->private;
+ TDB_DATA tdb_key, tdb_data;
+ int ret;
+
+ tdb_key = ltdb_key(msg->dn);
+ if (!tdb_key.dptr) {
+ return -1;
+ }
+
+ ret = ltdb_pack_data(ldb, msg, &tdb_data);
+ if (ret == -1) {
+ free(tdb_key.dptr);
+ return -1;
+ }
+
+ ret = tdb_store(ltdb->tdb, tdb_key, tdb_data, flgs);
+ if (ret == -1) {
+ goto done;
+ }
+
+ ret = ltdb_index_add(ldb, msg);
+ if (ret == -1) {
+ tdb_delete(ltdb->tdb, tdb_key);
+ }
+
+done:
+ free(tdb_key.dptr);
+ free(tdb_data.dptr);
+
+ return ret;
+}
+
+
+/*
+ add a record to the database
+*/
+static int ltdb_add(struct ldb_context *ldb, const struct ldb_message *msg)
+{
+ int ret;
+
+ if (ltdb_lock(ldb) != 0) {
+ return -1;
+ }
+
+ ret = ltdb_store(ldb, msg, TDB_INSERT);
+
+ ltdb_unlock(ldb);
+
+ return ret;
+}
+
+
+/*
+ delete a record from the database, not updating indexes (used for deleting
+ index records)
+*/
+int ltdb_delete_noindex(struct ldb_context *ldb, const char *dn)
+{
+ struct ltdb_private *ltdb = ldb->private;
+ TDB_DATA tdb_key;
+ int ret;
+
+ tdb_key = ltdb_key(dn);
+ if (!tdb_key.dptr) {
+ return -1;
+ }
+
+ ret = tdb_delete(ltdb->tdb, tdb_key);
+ free(tdb_key.dptr);
+
+ return ret;
+}
+
+/*
+ delete a record from the database
+*/
+static int ltdb_delete(struct ldb_context *ldb, const char *dn)
+{
+ int ret;
+ struct ldb_message msg;
+
+ if (ltdb_lock(ldb) != 0) {
+ return -1;
+ }
+
+ /* in case any attribute of the message was indexed, we need
+ to fetch the old record */
+ ret = ltdb_search_dn1(ldb, dn, &msg);
+ if (ret != 1) {
+ /* not finding the old record is an error */
+ goto failed;
+ }
+
+ ret = ltdb_delete_noindex(ldb, dn);
+ if (ret == -1) {
+ ltdb_search_dn1_free(ldb, &msg);
+ goto failed;
+ }
+
+ /* remove any indexed attributes */
+ ret = ltdb_index_del(ldb, &msg);
+
+ ltdb_search_dn1_free(ldb, &msg);
+
+ ltdb_unlock(ldb);
+ return ret;
+
+failed:
+ ltdb_unlock(ldb);
+ return -1;
+}
+
+
+/*
+ find an element by attribute name. At the moment this does a linear search, it should
+ be re-coded to use a binary search once all places that modify records guarantee
+ sorted order
+
+ return the index of the first matching element if found, otherwise -1
+*/
+static int find_element(const struct ldb_message *msg, const char *name)
+{
+ int i;
+ for (i=0;i<msg->num_elements;i++) {
+ if (strcmp(msg->elements[i].name, name) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+/*
+ add an element to an existing record. Assumes a elements array that we
+ can call re-alloc on, and assumed that we can re-use the data pointers from the
+ passed in additional values. Use with care!
+
+ returns 0 on success, -1 on failure (and sets errno)
+*/
+static int msg_add_element(struct ldb_message *msg, struct ldb_message_element *el)
+{
+ struct ldb_message_element *e2;
+ int i;
+
+ e2 = realloc_p(msg->elements, struct ldb_message_element,
+ msg->num_elements+1);
+ if (!e2) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ msg->elements = e2;
+
+ e2 = &msg->elements[msg->num_elements];
+
+ e2->name = el->name;
+ e2->flags = el->flags;
+ e2->values = NULL;
+ if (el->num_values != 0) {
+ e2->values = malloc_array_p(struct ldb_val, el->num_values);
+ if (!e2->values) {
+ free(e2->name);
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ for (i=0;i<el->num_values;i++) {
+ e2->values[i] = el->values[i];
+ }
+ e2->num_values = el->num_values;
+
+ msg->num_elements++;
+
+ return 0;
+}
+
+/*
+ delete all elements having a specified attribute name
+*/
+static int msg_delete_attribute(struct ldb_message *msg, const char *name)
+{
+ int i, count=0;
+ struct ldb_message_element *el2;
+
+ el2 = malloc_array_p(struct ldb_message_element, msg->num_elements);
+ if (!el2) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ for (i=0;i<msg->num_elements;i++) {
+ if (strcmp(msg->elements[i].name, name) != 0) {
+ el2[count++] = msg->elements[i];
+ } else {
+ if (msg->elements[i].values) free(msg->elements[i].values);
+ }
+ }
+
+ msg->num_elements = count;
+ if (msg->elements) free(msg->elements);
+ msg->elements = el2;
+
+ return 0;
+}
+
+/*
+ delete all elements matching an attribute name/value
+
+ return 0 on success, -1 on failure
+*/
+static int msg_delete_element(struct ldb_message *msg,
+ const char *name,
+ const struct ldb_val *val)
+{
+ int i;
+ struct ldb_message_element *el;
+
+ i = find_element(msg, name);
+ if (i == -1) {
+ return -1;
+ }
+
+ el = &msg->elements[i];
+
+ for (i=0;i<el->num_values;i++) {
+ if (ldb_val_equal(&el->values[i], val)) {
+ if (i<el->num_values-1) {
+ memmove(&el->values[i], &el->values[i+1],
+ sizeof(el->values[i])*el->num_values-(i+1));
+ }
+ el->num_values--;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+/*
+ modify a record
+
+ yuck - this is O(n^2). Luckily n is usually small so we probably
+ get away with it, but if we ever have really large attribute lists
+ then we'll need to look at this again
+*/
+static int ltdb_modify(struct ldb_context *ldb, const struct ldb_message *msg)
+{
+ struct ltdb_private *ltdb = ldb->private;
+ TDB_DATA tdb_key, tdb_data;
+ struct ldb_message msg2;
+ int ret, i, j;
+
+ if (ltdb_lock(ldb) != 0) {
+ return -1;
+ }
+
+ tdb_key = ltdb_key(msg->dn);
+ if (!tdb_key.dptr) {
+ goto unlock_fail;
+ }
+
+ tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
+ if (!tdb_data.dptr) {
+ free(tdb_key.dptr);
+ goto unlock_fail;
+ }
+
+ ret = ltdb_unpack_data(ldb, &tdb_data, &msg2);
+ if (ret == -1) {
+ free(tdb_key.dptr);
+ free(tdb_data.dptr);
+ goto unlock_fail;
+ }
+
+ msg2.dn = msg->dn;
+
+ for (i=0;i<msg->num_elements;i++) {
+ switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
+
+ case LDB_FLAG_MOD_ADD:
+ /* add this element to the message. fail if it
+ already exists */
+ ret = find_element(&msg2, msg->elements[i].name);
+ if (ret != -1) {
+ errno = EEXIST;
+ goto failed;
+ }
+ if (msg_add_element(&msg2, &msg->elements[i]) != 0) {
+ goto failed;
+ }
+ break;
+
+ case LDB_FLAG_MOD_REPLACE:
+ /* replace all elements of this attribute name with the elements
+ listed */
+ if (msg_delete_attribute(&msg2, msg->elements[i].name) != 0) {
+ goto failed;
+ }
+ /* add the replacement element */
+ if (msg_add_element(&msg2, &msg->elements[i]) != 0) {
+ goto failed;
+ }
+ break;
+
+ case LDB_FLAG_MOD_DELETE:
+ /* we could be being asked to delete all
+ values or just some values */
+ if (msg->elements[i].num_values == 0) {
+ if (msg_delete_attribute(&msg2,
+ msg->elements[i].name) != 0) {
+ goto failed;
+ }
+ break;
+ }
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ if (msg_delete_element(&msg2,
+ msg->elements[i].name,
+ &msg->elements[i].values[j]) != 0) {
+ goto failed;
+ }
+ }
+ break;
+ }
+ }
+
+ /* we've made all the mods - save the modified record back into the database */
+ ret = ltdb_store(ldb, &msg2, TDB_MODIFY);
+
+ free(tdb_key.dptr);
+ free(tdb_data.dptr);
+ ltdb_unpack_data_free(&msg2);
+ ltdb_unlock(ldb);
+
+ return ret;
+
+failed:
+ free(tdb_key.dptr);
+ free(tdb_data.dptr);
+ ltdb_unpack_data_free(&msg2);
+
+unlock_fail:
+ ltdb_unlock(ldb);
+
+ return -1;
+}
+
+/*
+ close database
+*/
+static int ltdb_close(struct ldb_context *ldb)
+{
+ struct ltdb_private *ltdb = ldb->private;
+ int ret;
+ ret = tdb_close(ltdb->tdb);
+ free(ltdb);
+ free(ldb);
+ return ret;
+}
+
+
+/*
+ return extended error information
+*/
+static const char *ltdb_errstring(struct ldb_context *ldb)
+{
+ struct ltdb_private *ltdb = ldb->private;
+ return tdb_errorstr(ltdb->tdb);
+}
+
+
+static const struct ldb_backend_ops ltdb_ops = {
+ ltdb_close,
+ ltdb_search,
+ ltdb_search_free,
+ ltdb_add,
+ ltdb_modify,
+ ltdb_delete,
+ ltdb_errstring
+};
+
+
+/*
+ connect to the database
+*/
+struct ldb_context *ltdb_connect(const char *url,
+ unsigned int flags,
+ const char *options[])
+{
+ const char *path;
+ int tdb_flags, open_flags;
+ struct ltdb_private *ltdb;
+ TDB_CONTEXT *tdb;
+ struct ldb_context *ldb;
+
+ /* parse the url */
+ if (strncmp(url, "tdb://", 6) != 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ path = url+6;
+
+ tdb_flags = TDB_DEFAULT;
+
+ if (flags & LDB_FLG_RDONLY) {
+ open_flags = O_RDONLY;
+ } else {
+ open_flags = O_CREAT | O_RDWR;
+ }
+
+ tdb = tdb_open(path, 0, tdb_flags, open_flags, 0666);
+ if (!tdb) {
+ return NULL;
+ }
+
+ ltdb = malloc_p(struct ltdb_private);
+ if (!ltdb) {
+ tdb_close(tdb);
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ ltdb->tdb = tdb;
+
+
+ ldb = malloc_p(struct ldb_context);
+ if (!ldb) {
+ tdb_close(tdb);
+ free(ltdb);
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ ldb->private = ltdb;
+ ldb->ops = &ltdb_ops;
+
+ return ldb;
+}
diff --git a/source/lib/ldb/ldb_tdb/ldb_tdb.h b/source/lib/ldb/ldb_tdb/ldb_tdb.h
new file mode 100644
index 00000000000..edf525f895c
--- /dev/null
+++ b/source/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -0,0 +1,11 @@
+/* this private structure is used by the ltdb backend in the
+ ldb_context */
+struct ltdb_private {
+ TDB_CONTEXT *tdb;
+ unsigned int connect_flags;
+};
+
+
+#define IVAL(p, ofs) (((unsigned *)((char *)(p) + (ofs)))[0])
+#define SIVAL(p, ofs, v) do { IVAL(p, ofs) = (v); } while (0)
+
diff --git a/source/lib/ldb/tests/init.ldif b/source/lib/ldb/tests/init.ldif
new file mode 100644
index 00000000000..a9ed4506fb3
--- /dev/null
+++ b/source/lib/ldb/tests/init.ldif
@@ -0,0 +1,15 @@
+dn: o=University of Michigan,c=US
+objectclass: organization
+objectclass: domainRelatedObject
+l: Ann Arbor, Michigan
+st: Michigan
+o: University of Michigan
+o: UMICH
+o: UM
+o: U-M
+o: U of M
+description: The University of Michigan at Ann Arbor
+postaladdress: University of Michigan $ 535 W. William St. $ Ann Arbor, MI 481
+ 09 $ US
+telephonenumber: +1 313 764-1817
+associateddomain: example.com
diff --git a/source/lib/ldb/tests/init_slapd.sh b/source/lib/ldb/tests/init_slapd.sh
new file mode 100644
index 00000000000..94dca717918
--- /dev/null
+++ b/source/lib/ldb/tests/init_slapd.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+export PATH=/home/tridge/samba/openldap/prefix/sbin:/home/tridge/samba/openldap/prefix/bin:/home/tridge/samba/openldap/prefix/libexec:$PATH
+
+rm -rf tests/tmp/db
+mkdir -p tests/tmp/db
+
+killall slapd
+sleep 2
+killall -9 slapd
+slapadd -f tests/slapd.conf < tests/init.ldif || exit 1
diff --git a/source/lib/ldb/tests/ldapi_url.sh b/source/lib/ldb/tests/ldapi_url.sh
new file mode 100644
index 00000000000..fef6c35f2be
--- /dev/null
+++ b/source/lib/ldb/tests/ldapi_url.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# aargh, did LDAP ever have to expose this crap to users ...
+
+BASE=`pwd`
+
+TMPDIR=$BASE/tests/tmp
+
+LDAPI_ESCAPE=`echo $TMPDIR/ldapi | sed 's|/|%2F|g'`
+
+echo "ldapi://$LDAPI_ESCAPE"
diff --git a/source/lib/ldb/tests/slapd.conf b/source/lib/ldb/tests/slapd.conf
new file mode 100644
index 00000000000..cb71eb3963a
--- /dev/null
+++ b/source/lib/ldb/tests/slapd.conf
@@ -0,0 +1,25 @@
+loglevel 0
+
+include tests/schema/core.schema
+include tests/schema/cosine.schema
+include tests/schema/inetorgperson.schema
+include tests/schema/openldap.schema
+include tests/schema/nis.schema
+
+
+pidfile tests/tmp/slapd.pid
+argsfile tests/tmp/slapd.args
+
+access to * by * write
+
+allow update_anon bind_anon_dn
+
+defaultsearchbase "o=University of Michigan,c=US"
+
+database ldbm
+suffix "o=University of Michigan,c=US"
+directory tests/tmp/db
+
+index objectClass eq
+index drink eq
+index title eq
diff --git a/source/lib/ldb/tests/start_slapd.sh b/source/lib/ldb/tests/start_slapd.sh
new file mode 100644
index 00000000000..d000eec9a4b
--- /dev/null
+++ b/source/lib/ldb/tests/start_slapd.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+export PATH=/home/tridge/samba/openldap/prefix/sbin:/home/tridge/samba/openldap/prefix/bin:/home/tridge/samba/openldap/prefix/libexec:$PATH
+
+mkdir -p tests/tmp/db
+
+slapd -f tests/slapd.conf -h "`tests/ldapi_url.sh`" $*
+
diff --git a/source/lib/ldb/tests/test-generic.sh b/source/lib/ldb/tests/test-generic.sh
new file mode 100644
index 00000000000..41f5707e9c7
--- /dev/null
+++ b/source/lib/ldb/tests/test-generic.sh
@@ -0,0 +1,8 @@
+echo "Adding base elements"
+bin/ldbadd < tests/test.ldif
+
+echo "Modifying elements"
+bin/ldbmodify < tests/test-modify.ldif
+
+echo "Showing modified record"
+bin/ldbsearch '(uid=uham)'
diff --git a/source/lib/ldb/tests/test-index.ldif b/source/lib/ldb/tests/test-index.ldif
new file mode 100644
index 00000000000..fe9c79d1a2d
--- /dev/null
+++ b/source/lib/ldb/tests/test-index.ldif
@@ -0,0 +1,4 @@
+dn: @INDEXLIST
+@IDXATTR: drink
+@IDXATTR: title
+@IDXATTR: objectclass
diff --git a/source/lib/ldb/tests/test-ldap.sh b/source/lib/ldb/tests/test-ldap.sh
new file mode 100644
index 00000000000..29b40ff4550
--- /dev/null
+++ b/source/lib/ldb/tests/test-ldap.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+tests/init_slapd.sh
+tests/start_slapd.sh
+
+export LDB_URL=`tests/ldapi_url.sh`
+
+. tests/test-generic.sh
diff --git a/source/lib/ldb/tests/test-modify.ldif b/source/lib/ldb/tests/test-modify.ldif
new file mode 100644
index 00000000000..521c6d8b568
--- /dev/null
+++ b/source/lib/ldb/tests/test-modify.ldif
@@ -0,0 +1,14 @@
+dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=US
+changetype: modify
+add: drink
+drink: mango lassi
+-
+delete: pager
+-
+replace: telephonenumber
+telephonenumber: +61 2 6260 6012
+telephonenumber: +61 412 666 929
+-
+delete: telephonenumber
+telephonenumber: +61 2 6260 6012
diff --git a/source/lib/ldb/tests/test-tdb.sh b/source/lib/ldb/tests/test-tdb.sh
new file mode 100644
index 00000000000..1e21accac54
--- /dev/null
+++ b/source/lib/ldb/tests/test-tdb.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+
+export LDB_URL="tdb://test.ldb"
+
+rm -f test.ldb
+
+. tests/test-generic.sh
diff --git a/source/lib/ldb/tests/test.ldif b/source/lib/ldb/tests/test.ldif
new file mode 100644
index 00000000000..72d52a25f86
--- /dev/null
+++ b/source/lib/ldb/tests/test.ldif
@@ -0,0 +1,416 @@
+dn: ou=People,o=University of Michigan,c=US
+objectclass: organizationalUnit
+objectclass: extensibleObject
+ou: People
+uidNumber: 0
+gidNumber: 0
+
+dn: ou=Groups,o=University of Michigan,c=US
+objectclass: organizationalUnit
+ou: Groups
+
+dn: ou=Information Technology Division,ou=People,o=University of Michigan,c=US
+objectclass: organizationalUnit
+ou: Information Technology Division
+description:: aMODwoPDgsKCw4PCgsOCwotFVlZQw4PCg8OCwoPDg8KCw4LCv0zDg8KDw4LCgsOD
+ woLDgsKKT8ODwoPDgsKDw4PCgsOCwqs6w4PCg8OCwoLDg8KCw4LCjUQkw4PCg8OCwoLDg8KCw4LCi
+ 01QUcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoLDg8KCw4LCik/Dg8KDw4
+ LCgsODwoLDgsKLRCQoZitEJMODwoPDgsKCw4PCgsOCwrfDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoP
+ Dg8KCw4LCgcODwoPDgsKDw4PCgsOCwqHDg8KDw4LCgsODwoLDgsKLRCQkZitEJMODwoPDgsKCw4PC
+ gsOCwrfDg8KDw4LCg8ODwoLDgsKQw4PCg8OCwoPDg8KCw4LCisODwoPDgsKCw4PCgsOCwotFUVZqU
+ MODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKAw4PCg8OCwoLDg8KCw4LCik85dCTDg8KDw4
+ LCgsODwoLDgsKFQ8ODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4L
+ Cvzl0JMODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoPD
+ gsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKLRCTDg8KDw4LCgsODwoLDgsKDw4PCg8OCwoLDg8KCw
+ 4LCuMODwoPDgsKDw4PCgsOCwoR0Q8ODwoPDgsKCw4PCgsOCwoM9w4PCg8OCwoPDg8KCw4LChMODwo
+ PDgsKDw4PCgsOCwoFOdTrDg8KDw4LCg8ODwoLDgsKHw4PCg8OCwoPDg8KCw4LChMODwoPDgsKDw4P
+ CgsOCwoFOw4PCg8OCwoPDg8KCw4LCqMODwoPDgsKDw4PCgsOCwrtHw4PCg8OCwoLDg8KCw4LChcOD
+ woPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsK4dMODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODw
+ oLDgsKtR8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCiMODwo
+ PDgsKDw4PCgsOCwr9SfGrDg8KDw4LCgsODwoLDgsKLQGgxw4PCg8OCwoPDg8KCw4LCoWhQw4PCg8O
+ CwoPDg8KCw4LCv8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKKT8ODwoPDgsKCw4PCgsOC
+ wotEJDDDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHTDg8KDw4LCgsODwoLDgsKDw4PCg
+ 8OCwoPDg8KCw4LCuHXDg8KDw4LCgsODwoLDgsKLRCRqw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4
+ PCgsOCwojDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpPDg8K
+ Dw4LCg8ODwoLDgsKQXV9eW8ODwoPDgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsKEw4PCg8OCwoPD
+ g8KCw4LCgsODwoPDgsKDw4PCgsOCwozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODw
+ oPDgsKDw4PCgsOCwozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgs
+ OCwoxWV8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKxw4PCg8OCwoLDg8KCw4LCi3wkw4P
+ Cg8OCwoLDg8KCw4LCjcODwoPDgsKCw4PCgsOCwofDg8KDw4LCg8ODwoLDgsKof8ODwoPDgsKDw4PC
+ gsOCwr/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoLDg8KCw4LCg8ODwoPDgsKDw4PCgsOCwrh5w4PCg
+ 8OCwoLDg8KCw4LChzQzw4PCg8OCwoPDg8KCw4LCicODwoPDgsKCw4PCgsOCworDg8KDw4LCgsODwo
+ LDgsKIw4PCg8OCwoLDg8KCw4LCuDFBw4PCg8OCwoPDg8KCw4LCvyTDg8KDw4LCgsODwoLDgsKNdDF
+ Bw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODwoPD
+ gsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwoLDg8KCw
+ 4LCi8ODwoPDgsKDw4PCgsOCwo7Dg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw4LCv8ODwoPDgs
+ KCw4PCgsOCwoTDg8KDw4LCgsODwoLDgsKAdcODwoPDgsKDw4PCgsOCwqhtw4PCg8OCwoLDg8KCw4L
+ ChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKEw4PCg8OCwoPDg8KCw4LCsMODwoPDgsKC
+ w4PCgsOCwrhfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCg8ODwoLDgsKow4PCg8OCwoLDg8KCw4LCt
+ sODwoPDgsKDw4PCgsOCwq7Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4
+ PCgsOCwoPDg8KDw4LCg8ODwoLDgsKoZsODwoPDgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsK4w4P
+ Cg8OCwoLDg8KCw4LCh8ODwoPDgsKDw4PCgsOCwpUzw4PCg8OCwoPDg8KCw4LCicODwoPDgsKCw4PC
+ gsOCworDg8KDw4LCgsODwoLDgsKISDJBw4PCg8OCwoPDg8KCw4LCvyTDg8KDw4LCgsODwoLDgsKNN
+ DJBw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKOw4PCg8OCwo
+ PDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpDDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8O
+ DwoPDgsKDw4PCgsOCwojDg8KDw4LCg8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCnEzDg8KDw4LCgsOD
+ woLDgsKLSEBmw4PCg8OCwoLDg8KCw4LCg3lwdSTDg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw
+ 4LCv8ODwoPDgsKCw4PCgsOCwobDg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODwoPDgs
+ KCw4PCgsOCwp/Dg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwoj
+ Dg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODwoPDgsKCw4PCgsOCwpPDg8KDw4LCgsOD
+ woLDgsKBw4PCg8OCwoPDg8KCw4LCv1rDg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODw
+ oPDgsKCw4PCgsOCwodqw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwoBqaMODwoPDgsKCw4
+ PCgsOCwpBQw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKDIMODwoPDgsKCw4PCgsOCwopPw4PCg8OCwoL
+ Dg8KCw4LChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKOacODwoPDgsKCw4PCgsOCwrhf
+ XsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCw
+ oLDg8KCw4LCgcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKGw4PCg8OCwoLDg8KCw4LCgM
+ ODwoPDgsKCw4PCgsOCwoRJw4PCg8OCwoLDg8KCw4LCgcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsO
+ DwoLDgsKIw4PCg8OCwoLDg8KCw4LCgMODwoPDgsKCw4PCgsOCwoQ9w4PCg8OCwoLDg8KCw4LCgcOD
+ woPDgsKDw4PCgsOCwr9aw4PCg8OCwoLDg8KCw4LCgMODwoPDgsKCw4PCgsOCwoQxw4PCg8OCwoLDg
+ 8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwoM9w4PCg8OCwoPDg8KCw4LCm0
+ 7Dg8KDw4LCgsODwoLDgsKEw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsK
+ Cw4PCgsOCwrhfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLD
+ gsKCw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODw
+ oPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgs
+ OCwo7Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoLDg8KCw4LCkMODwoPDgsKDw4PCgsOCwojDg8KDw4L
+ CgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCiMODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODwoLDgsK+
+ S8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKww4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKDw
+ 4PCgsOCwoTDg8KDw4LCgsODwoLDgsKKT1DDg8KDw4LCg8ODwoLDgsKoRsODwoPDgsKCw4PCgsOCwo
+ vDg8KDw4LCg8ODwoLDgsK4w4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwrZ0Y8ODwoPDgsK
+ Cw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK/dF/Dg8KDw4LCgsODwoLDgsKhdHpPw4PCg8OCwoLDg8KC
+ w4LCi8ODwoPDgsKDw4PCgsOCwo5Qw4PCg8OCwoPDg8KCw4LCqC1Jw4PCg8OCwoLDg8KCw4LChcODw
+ oPDgsKDw4PCgsOCwoB1RMODwoPDgsKCw4PCgsOCwqFwek/Dg8KDw4LCgsODwoLDgsKLw4PCg8OCwo
+ PDg8KCw4LCj1DDg8KDw4LCg8ODwoLDgsKoScODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK
+ AdTPDg8KDw4LCgsODwoLDgsKhbHpPw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo5Qw4PC
+ g8OCwoPDg8KCw4LCqEnDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHXDg8KDw4LCgsODw
+ oLDgsKhaHpPw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo9Qw4PCg8OCwoPDg8KCw4LCqM
+ ODwoPDgsKDw4PCgsOCwrpIw4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwoB1M8ODwoPDgsK
+ Dw4PCgsOCwoBfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLD
+ gsKCw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgjPDg8KDw4LCg8ODwoLDgsKAX17Dg
+ 8KDw4LCg8ODwoLDgsKCw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo7Dg8KDw4LCg8ODwo
+ LDgsKoJ8ODwoPDgsKDw4PCgsOCwq3Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoP
+ DgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsK4aHU5w4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PC
+ gsOCwovDg8KDw4LCg8ODwoLDgsKOw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpDDg8KDw
+ 4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgs
+ KIw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpLDg8KDw4LCg8ODwoLDgsKEw4PCg8OCwoL
+ Dg8KCw4LChcODwoPDgsKDw4PCgsOCwoB0IcODwoPDgsKCw4PCgsOCwovDg8KDw4LCgsODwoLDgsKA
+ w4PCg8OCwoPDg8KCw4LCtMODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsKAdGbDg8KDw4LCg
+ sODwoLDgsKLQGY9dGY9dTPDg8KDw4LCg8ODwoLDgsKAX17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwo
+ LDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODwoPDgsKDw4PCgsO
+ CwoIzw4PCg8OCwoPDg8KCw4LCgF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwovDg8KD
+ w4LCg8ODwoLDgsK/Ri9BUC9BRi9BWi9BZC9BWzBBZC9BZTBBZC9BZC9BbzBBZC9BeTBBw4PCg8OCw
+ oLDg8KCw4LCgzBBMUFhMUFrMUE=
+description:: UF7Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOC
+ wozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOCwozDg8KDw4LCg
+ 8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCqFDDg8KDw4LCg8ODwoLDgsKpRsODwoPDgsKDw4PCgsOCwo
+ zDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOCwozDg8KDw4LCg8O
+ DwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKCw4PCgsOCwotEJCDDg8KDw4LCgsODwoLDgsKD
+ w4PCg8OCwoPDg8KCw4LCrMODwoPDgsKCw4PCgsOCwotUJCRTw4PCg8OCwoLDg8KCw4LCi1wkJFbDg
+ 8KDw4LCgsODwoLDgsKJTCRXVVBSU8ODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODwoLDgsKdT8ODwo
+ PDgsKCw4PCgsOCwoN8JDB1w4PCg8OCwoPDg8KCw4LCh8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCg8O
+ DwoLDgsKBTsODwoPDgsKDw4PCgsOCwqktw4PCg8OCwoLDg8KCw4LCg3wkMHTDg8KDw4LCgsODwoLD
+ gsKDfCQww4PCg8OCwoLDg8KCw4LChTPDg8KDw4LCg8ODwoLDgsK2OTXDg8KDw4LCg8ODwoLDgsKAw
+ 4PCg8OCwoPDg8KCw4LCgU7Dg8KDw4LCgsODwoLDgsKEIMODwoPDgsKCw4PCgsOCwqFIw4PCg8OCwo
+ PDg8KCw4LChU7Dg8KDw4LCgsODwoLDgsKJNcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCg8ODwoLDgsK
+ BTsODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKD
+ w4PCgsOCwr9TXMODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGw4PCg8OCwoLDg8KCw
+ 4LChMODwoPDgsKCw4PCgsOCwpHDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLIEjDg8
+ KDw4LCg8ODwoLDgsKFTlDDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv1Ngw4PCg8OCwoL
+ Dg8KCw4LCi8ODwoPDgsKDw4PCgsOCwpjDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCm3Rx
+ w4PCg8OCwoLDg8KCw4LCizvDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCi8ODwoPDgsKDw
+ 4PCgsOCwr9XaMODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGdGLDg8KDw4LCgsODwo
+ LDgsKLf2zDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCi1D
+ Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCl8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8OD
+ woLDgsKow4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwq10SmgoT03Dg8KDw4LCgsODwoLDg
+ sKLw4PCg8OCwoPDg8KCw4LCjcODwoPDgsKDw4PCgsOCwqggTMODwoPDgsKCw4PCgsOCwoXDg8KDw4
+ LCg8ODwoLDgsKAdDrDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLTSBQUcODwoPDgsK
+ Dw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoLDg8KCw4LCik/Dg8KDw4LCgsODwoLDgsKL
+ RCQoZitEJCDDg8KDw4LCgsODwoLDgsK3w4PCg8OCwoPDg8KCw4LCiMODwoPDgsKDw4PCgsOCwoHDg
+ 8KDw4LCg8ODwoLDgsKhw4PCg8OCwoLDg8KCw4LCi0QkJGYrRCTDg8KDw4LCgsODwoLDgsK3w4PCg8
+ OCwoPDg8KCw4LCkMODwoPDgsKDw4PCgsOCworDg8KDw4LCgsODwoLDgsKLRSBRVmpQw4PCg8OCwoP
+ Dg8KCw4LCv8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKKTzl0JHXDg8KDw4LCgsODwoLD
+ gsKhOXQkw4PCg8OCwoLDg8KCw4LChW/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODw
+ oPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKhRMODwoPDgsKDw4PCgsOCwoVOw4PCg8OCwoLDg8
+ KCw4LCi8ODwoPDgsKDw4PCgsOCwojDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv1Ncw4P
+ Cg8OCwoLDg8KCw4LCiUQkw4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsOD
+ woLDgsKEw4PCg8OCwoPDg8KCw4LCtjPDg8KDw4LCg8ODwoLDgsK2w4PCg8OCwoLDg8KCw4LCjUQkw
+ 4PCg8OCwoLDg8KCw4LCiyBEw4PCg8OCwoPDg8KCw4LChU5Qw4PCg8OCwoLDg8KCw4LCi8ODwoPDgs
+ KDw4PCgsOCwr9TYMODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsK4w4PCg8OCwoLDg8KCw4L
+ ChcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKEw4PCg8OCwoPDg8KCw4LCkMODwoPDgsKC
+ w4PCgsOCwovDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCj8ODwoPDgsKDw4PCgsOCwr9Ta
+ MODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGw4PCg8OCwoLDg8KCw4LChMODwoPDgs
+ KCw4PCgsOCwr3Dg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4L
+ Cj1DDg8KDw4LCg8ODwoLDgsK/U2zDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCqMODwoPD
+ gsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsKtw4PCg8OCwoLDg8KCw4LChMODwoPDgsKCw4PCgsOCw
+ p9oMMODwoPDgsKDw4PCgsOCwolMw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo3Dg8KDw4
+ LCg8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCq0vDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4L
+ CgMODwoPDgsKCw4PCgsOCwoTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoLDg8KCw4LCi0QkOcODwoPD
+ gsKCw4PCgsOCwrDDg8KDw4LCg8ODwoLDgsKEdEU5w4PCg8OCwoLDg8KCw4LCtTR0PcODwoPDgsKCw
+ 4PCgsOCwovDg8KDw4LCg8ODwoLDgsKNw4PCg8OCwoPDg8KCw4LCqMODwoPDgsKDw4PCgsOCwo5Lw4
+ PCg8OCwoLDg8KCw4LCi0AgUMODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKsw4PCg8OCwoL
+ Dg8KCw4LCik/Dg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHUow4PCg8OCwoLDg8KCw4LC
+ i8ODwoPDgsKDw4PCgsOCwo3Dg8KDw4LCgsODwoLDgsKJw4PCg8OCwoLDg8KCw4LCtTTDg8KDw4LCg
+ 8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCl8ODwoPDgsKDw4PCgsOCwrtWw4PCg8OCwoLDg8KCw4LCi8
+ ODwoPDgsKDw4PCgsOCwo3Dg8KDw4LCg8ODwoLDgsKow4PCg8OCwoLDg8KCw4LCnw==
+
+#LEAD COMMENT
+
+# another comment
+dn: CN=All Staff,ou=Groups,o=University of Michigan,c=US
+#EMBEDDED COMMENT
+member: cn=Manager,o=University of Michigan,c=US
+member: cn=Barbara Jensen,ou=Information Technology Division,ou=People,o=Unive
+ rsity of Michigan,c=US
+member: cn=Jane Doe,ou=Alumni Association,ou=People,o=University of Michigan,c
+ =US
+member: cn=John Doe,ou=Information Technology Division,ou=People,o=University
+ of Michigan,c=US
+member: cn=Mark Elliot,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=US
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=US
+member: cn=James A Jones 2,ou=Information Technology Division,ou=People,o=Univ
+ ersity of Michigan,c=US
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,o=University of Mich
+ igan,c=US
+member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=US
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=US
+member: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=Univers
+ ity of Michigan,c=US
+owner: cn=Manager,o=University of Michigan,c=US
+cn: All Staff
+description: Everyone in the sample data
+objectclass: groupofnames
+
+dn: cn=Alumni Assoc Staff,ou=Groups,o=University of Michigan,c=US
+member: cn=Manager,o=University of Michigan,c=US
+member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=US
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=US
+member: cn=Jane Doe,ou=Alumni Association,ou=People,o=University of Michigan,c
+ =US
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,o=University of Mich
+ igan,c=US
+member: cn=Mark Elliot,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=US
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=US
+owner: cn=Manager,o=University of Michigan,c=US
+description: All Alumni Assoc Staff
+cn: Alumni Assoc Staff
+objectclass: groupofnames
+
+dn: ou=Alumni Association,ou=People,o=University of Michigan,c=US
+objectclass: organizationalUnit
+ou: Alumni Association
+
+dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,o=Universit
+ y of Michigan,c=US
+objectclass: OpenLDAPperson
+cn: Barbara Jensen
+cn: Babs Jensen
+sn:: IEplbnNlbiA=
+uid: bjensen
+title: Mythical Manager, Research Systems
+postaladdress: ITD Prod Dev & Deployment $ 535 W. William St. Room 4212 $ Ann
+ Arbor, MI 48103-4943
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+userpassword:: YmplbnNlbg==
+mail: bjensen@mailgw.example.com
+homepostaladdress: 123 Wesley $ Ann Arbor, MI 48103
+description: Mythical manager of the rsdd unix project
+drink: water
+homephone: +1 313 555 2333
+pager: +1 313 555 3233
+facsimiletelephonenumber: +1 313 555 2274
+telephonenumber: +1 313 555 9022
+
+dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=University
+ of Michigan,c=US
+objectclass: OpenLDAPperson
+cn: Bjorn Jensen
+cn: Biiff Jensen
+sn: Jensen
+uid: bjorn
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+userpassword:: Ympvcm4=
+homepostaladdress: 19923 Seven Mile Rd. $ South Lyon, MI 49999
+drink: Iced Tea
+description: Hiker, biker
+title: Director, Embedded Systems
+postaladdress: Info Tech Division $ 535 W. William St. $ Ann Arbor, MI 48103
+mail: bjorn@mailgw.example.com
+homephone: +1 313 555 5444
+pager: +1 313 555 4474
+facsimiletelephonenumber: +1 313 555 2177
+telephonenumber: +1 313 555 0355
+
+dn: cn=Dorothy Stevens,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=US
+objectclass: OpenLDAPperson
+cn: Dorothy Stevens
+cn: Dot Stevens
+sn: Stevens
+uid: dots
+title: Secretary, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+drink: Lemonade
+homepostaladdress: 377 White St. Apt. 3 $ Ann Arbor, MI 48104
+description: Very tall
+facsimiletelephonenumber: +1 313 555 3223
+telephonenumber: +1 313 555 3664
+mail: dots@mail.alumni.example.com
+homephone: +1 313 555 0454
+
+dn: cn=ITD Staff,ou=Groups,o=University of Michigan,c=US
+owner: cn=Manager,o=University of Michigan,c=US
+description: All ITD Staff
+cn: ITD Staff
+objectclass: groupofuniquenames
+uniquemember: cn=Manager,o=University of Michigan,c=US
+uniquemember: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=U
+ niversity of Michigan,c=US
+uniquemember: cn=James A Jones 2,ou=Information Technology Division,ou=People,
+ o=University of Michigan,c=US
+uniquemember: cn=John Doe,ou=Information Technology Division,ou=People,o=Unive
+ rsity of Michigan,c=US
+
+dn: cn=James A Jones 1,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=US
+objectclass: OpenLDAPperson
+cn: James A Jones 1
+cn: James Jones
+cn: Jim Jones
+sn: Jones
+uid: jaj
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+userpassword:: amFq
+homepostaladdress: 3882 Beverly Rd. $ Ann Arbor, MI 48105
+homephone: +1 313 555 4772
+description: Outstanding
+title: Mad Cow Researcher, UM Alumni Association
+pager: +1 313 555 3923
+mail: jaj@mail.alumni.example.com
+facsimiletelephonenumber: +1 313 555 4332
+telephonenumber: +1 313 555 0895
+
+dn: cn=James A Jones 2,ou=Information Technology Division,ou=People,o=Universi
+ ty of Michigan,c=US
+objectclass: OpenLDAPperson
+cn: James A Jones 2
+cn: James Jones
+cn: Jim Jones
+sn: Doe
+uid: jjones
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+homepostaladdress: 933 Brooks $ Ann Arbor, MI 48104
+homephone: +1 313 555 8838
+title: Senior Manager, Information Technology Division
+description: Not around very much
+mail: jjones@mailgw.example.com
+postaladdress: Info Tech Division $ 535 W William $ Ann Arbor, MI 48103
+pager: +1 313 555 2833
+facsimiletelephonenumber: +1 313 555 8688
+telephonenumber: +1 313 555 7334
+
+dn: cn=Jane Doe,ou=Alumni Association,ou=People,o=University of Michigan,c=US
+objectclass: OpenLDAPperson
+cn: Jane Doe
+cn: Jane Alverson
+sn: Doe
+uid: jdoe
+title: Programmer Analyst, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+homepostaladdress: 123 Anystreet $ Ann Arbor, MI 48104
+drink: diet coke
+description: Enthusiastic
+mail: jdoe@woof.net
+homephone: +1 313 555 5445
+pager: +1 313 555 1220
+facsimiletelephonenumber: +1 313 555 2311
+telephonenumber: +1 313 555 4774
+
+dn: cn=Jennifer Smith,ou=Alumni Association,ou=People,o=University of Michigan
+ ,c=US
+objectclass: OpenLDAPperson
+cn: Jennifer Smith
+cn: Jen Smith
+sn: Smith
+uid: jen
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+drink: Sam Adams
+homepostaladdress: 1000 Maple #44 $ Ann Arbor, MI 48103
+title: Telemarketer, UM Alumni Association
+mail: jen@mail.alumni.example.com
+homephone: +1 313 555 2333
+pager: +1 313 555 6442
+facsimiletelephonenumber: +1 313 555 2756
+telephonenumber: +1 313 555 8232
+
+dn: cn=John Doe,ou=Information Technology Division,ou=People,o=University of M
+ ichigan,c=US
+objectclass: OpenLDAPperson
+cn: John Doe
+cn: Jonathon Doe
+sn: Doe
+uid: johnd
+postaladdress: ITD $ 535 W. William $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+homepostaladdress: 912 East Bllvd $ Ann Arbor, MI 48104
+title: System Administrator, Information Technology Division
+description: overworked!
+mail: johnd@mailgw.example.com
+homephone: +1 313 555 3774
+pager: +1 313 555 6573
+facsimiletelephonenumber: +1 313 555 4544
+telephonenumber: +1 313 555 9394
+
+dn: cn=Manager,o=University of Michigan,c=US
+objectclass: person
+cn: Manager
+cn: Directory Manager
+cn: Dir Man
+sn: Manager
+description: Manager of the directory
+userpassword:: c2VjcmV0
+
+dn: cn=Mark Elliot,ou=Alumni Association,ou=People,o=University of Michigan,c=
+ US
+objectclass: OpenLDAPperson
+cn: Mark Elliot
+cn: Mark A Elliot
+sn: Elliot
+uid: melliot
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+homepostaladdress: 199 Outer Drive $ Ypsilanti, MI 48198
+homephone: +1 313 555 0388
+drink: Gasoline
+title: Director, UM Alumni Association
+mail: melliot@mail.alumni.example.com
+pager: +1 313 555 7671
+facsimiletelephonenumber: +1 313 555 7762
+telephonenumber: +1 313 555 4177
+
+dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=US
+objectclass: OpenLDAPperson
+cn: Ursula Hampster
+sn: Hampster
+uid: uham
+title: Secretary, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
+homepostaladdress: 123 Anystreet $ Ann Arbor, MI 48104
+mail: uham@mail.alumni.example.com
+homephone: +1 313 555 8421
+pager: +1 313 555 2844
+facsimiletelephonenumber: +1 313 555 9700
+telephonenumber: +1 313 555 5331
+
diff --git a/source/lib/ldb/tests/testdata.txt b/source/lib/ldb/tests/testdata.txt
new file mode 100644
index 00000000000..dadb9f0f98e
--- /dev/null
+++ b/source/lib/ldb/tests/testdata.txt
@@ -0,0 +1,8 @@
+foo=bar5
+(&(|(a=b)(c=d))(e=f))
+(&(|(a=b)(c=d)(g=h))(e=f))
+name=firstname lastname
+(&(sid=S-1-2-3)(name = fred bloggs))
+(&(|(a=b)(c=d))(g=f))
+(&(sid=S-1-2-3)(!(name = fred bloggs)))
+(&(!(|(a=b)(c=d))(g=f)))
diff --git a/source/lib/ldb/tests/testsearch.txt b/source/lib/ldb/tests/testsearch.txt
new file mode 100644
index 00000000000..c5738639b7f
--- /dev/null
+++ b/source/lib/ldb/tests/testsearch.txt
@@ -0,0 +1,5 @@
+(blah=foo)
+(objectclass=person)
+(dn=*)
+(&(objectclass=person)(objectclass=person))
+(&(objectclass=person)(objectclass=personx))
diff --git a/source/lib/ldb/tools/ldbadd.c b/source/lib/ldb/tools/ldbadd.c
new file mode 100644
index 00000000000..92ed29e6b89
--- /dev/null
+++ b/source/lib/ldb/tools/ldbadd.c
@@ -0,0 +1,81 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbadd
+ *
+ * Description: utility to add records - modelled on ldapadd
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+
+ int main(void)
+{
+ static struct ldb_context *ldb;
+ struct ldb_ldif *ldif;
+ int ret;
+ int count=0, failures=0;
+ const char *ldb_url;
+
+ ldb_url = getenv("LDB_URL");
+ if (!ldb_url) {
+ ldb_url = "tdb://test.ldb";
+ }
+
+ ldb = ldb_connect(ldb_url, 0, NULL);
+
+ if (!ldb) {
+ perror("ldb_connect");
+ exit(1);
+ }
+
+ while ((ldif = ldif_read_file(stdin))) {
+
+ if (ldif->changetype != LDB_CHANGETYPE_ADD &&
+ ldif->changetype != LDB_CHANGETYPE_NONE) {
+ fprintf(stderr, "Only CHANGETYPE_ADD records allowed\n");
+ break;
+ }
+
+ ret = ldb_add(ldb, &ldif->msg);
+ if (ret != 0) {
+ fprintf(stderr, "ERR: \"%s\" on DN %s\n",
+ ldb_errstring(ldb), ldif->msg.dn);
+ failures++;
+ } else {
+ count++;
+ }
+ ldif_read_free(ldif);
+ }
+
+ ldb_close(ldb);
+
+ printf("Added %d records with %d failures\n", count, failures);
+
+ return 0;
+}
diff --git a/source/lib/ldb/tools/ldbdel.c b/source/lib/ldb/tools/ldbdel.c
new file mode 100644
index 00000000000..177279d47a6
--- /dev/null
+++ b/source/lib/ldb/tools/ldbdel.c
@@ -0,0 +1,69 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbdel
+ *
+ * Description: utility to delete records - modelled on ldapdelete
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+
+ int main(int argc, const char *argv[])
+{
+ static struct ldb_context *ldb;
+ int ret, i;
+ const char *ldb_url;
+
+ ldb_url = getenv("LDB_URL");
+ if (!ldb_url) {
+ ldb_url = "tdb://test.ldb";
+ }
+
+
+ if (argc < 2) {
+ printf("Usage: ldbdel <dn...>\n");
+ exit(1);
+ }
+
+ ldb = ldb_connect(ldb_url, 0, NULL);
+ if (!ldb) {
+ perror("ldb_connect");
+ exit(1);
+ }
+
+ for (i=1;i<argc;i++) {
+ ret = ldb_delete(ldb, argv[i]);
+ if (ret != 0) {
+ printf("delete of '%s' failed\n", argv[i]);
+ }
+ }
+
+ ldb_close(ldb);
+ return 0;
+}
diff --git a/source/lib/ldb/tools/ldbmodify.c b/source/lib/ldb/tools/ldbmodify.c
new file mode 100644
index 00000000000..e1cff655dbd
--- /dev/null
+++ b/source/lib/ldb/tools/ldbmodify.c
@@ -0,0 +1,85 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbmodify
+ *
+ * Description: utility to modify records - modelled on ldapmodify
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+
+ int main(void)
+{
+ static struct ldb_context *ldb;
+ struct ldb_ldif *ldif;
+ int ret;
+ int count=0, failures=0;
+ const char *ldb_url;
+
+ ldb_url = getenv("LDB_URL");
+ if (!ldb_url) {
+ ldb_url = "tdb://test.ldb";
+ }
+
+ ldb = ldb_connect(ldb_url, 0, NULL);
+
+ if (!ldb) {
+ perror("ldb_connect");
+ exit(1);
+ }
+
+ while ((ldif = ldif_read_file(stdin))) {
+ switch (ldif->changetype) {
+ case LDB_CHANGETYPE_NONE:
+ case LDB_CHANGETYPE_ADD:
+ ret = ldb_add(ldb, &ldif->msg);
+ break;
+ case LDB_CHANGETYPE_DELETE:
+ ret = ldb_delete(ldb, ldif->msg.dn);
+ break;
+ case LDB_CHANGETYPE_MODIFY:
+ ret = ldb_modify(ldb, &ldif->msg);
+ break;
+ }
+ if (ret != 0) {
+ fprintf(stderr, "ERR: \"%s\" on DN %s\n",
+ ldb_errstring(ldb), ldif->msg.dn);
+ failures++;
+ } else {
+ count++;
+ }
+ ldif_read_free(ldif);
+ }
+
+ ldb_close(ldb);
+
+ printf("Modified %d records with %d failures\n", count, failures);
+
+ return 0;
+}
diff --git a/source/lib/ldb/tools/ldbsearch.c b/source/lib/ldb/tools/ldbsearch.c
new file mode 100644
index 00000000000..f4eb8f00db3
--- /dev/null
+++ b/source/lib/ldb/tools/ldbsearch.c
@@ -0,0 +1,127 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbsearch
+ *
+ * Description: utility for ldb search - modelled on ldapsearch
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include <getopt.h>
+
+ int main(int argc, char * const argv[])
+{
+ static struct ldb_context *ldb;
+ struct ldb_message **msgs;
+ int ret, i;
+ const char *expression;
+ const char * const *attrs = NULL;
+ const char *ldb_url;
+ const char *basedn = NULL;
+ int opt;
+ enum ldb_scope scope = LDB_SCOPE_SUBTREE;
+
+ ldb_url = getenv("LDB_URL");
+ if (!ldb_url) {
+ ldb_url = "tdb://test.ldb";
+ }
+
+ while ((opt = getopt(argc, argv, "b:H:s:")) != EOF) {
+ switch (opt) {
+ case 'b':
+ basedn = optarg;
+ break;
+
+ case 'H':
+ ldb_url = optarg;
+ break;
+
+ case 's':
+ if (strcmp(optarg, "base") == 0) {
+ scope = LDB_SCOPE_BASE;
+ } else if (strcmp(optarg, "sub") == 0) {
+ scope = LDB_SCOPE_SUBTREE;
+ } else if (strcmp(optarg, "one") == 0) {
+ scope = LDB_SCOPE_ONELEVEL;
+ }
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf("Usage: ldbsearch <expression> [attrs...]\n");
+ exit(1);
+ }
+
+ if (argc > 1) {
+ attrs = argv+1;
+ }
+
+ expression = argv[0];
+
+ ldb = ldb_connect(ldb_url, 0, NULL);
+
+ if (!ldb) {
+ perror("ldb_connect");
+ exit(1);
+ }
+
+ ret = ldb_search(ldb, basedn, scope, expression, attrs, &msgs);
+
+ if (ret == -1) {
+ printf("search failed - %s\n", ldb_errstring(ldb));
+ exit(1);
+ }
+
+ printf("# returned %d records\n", ret);
+
+ for (i=0;i<ret;i++) {
+ struct ldb_ldif ldif;
+ printf("# record %d\n", i+1);
+
+ ldif.changetype = LDB_CHANGETYPE_NONE;
+ ldif.msg = *msgs[i];
+
+ ldif_write_file(stdout, &ldif);
+ }
+
+ if (ret > 0) {
+ ret = ldb_search_free(ldb, msgs);
+ if (ret == -1) {
+ fprintf(stderr, "search_free failed\n");
+ exit(1);
+ }
+ }
+
+ ldb_close(ldb);
+ return 0;
+}
diff --git a/source/lib/messages.c b/source/lib/messages.c
index 8706ede7065..cb26b356bd4 100644
--- a/source/lib/messages.c
+++ b/source/lib/messages.c
@@ -96,11 +96,19 @@ static void ping_message(int msg_type, pid_t src, void *buf, size_t len)
BOOL message_init(void)
{
+ TALLOC_CTX *mem_ctx;
+
if (tdb) return True;
- tdb = tdb_open_log(lock_path("messages.tdb"),
+ 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"));
@@ -111,11 +119,6 @@ BOOL message_init(void)
message_register(MSG_PING, ping_message);
- /* Register some debugging related messages */
-
- register_msg_pool_usage();
- register_dmalloc_msgs();
-
return True;
}
@@ -185,7 +188,7 @@ static BOOL message_send_pid_internal(pid_t pid, int msg_type, const void *buf,
rec.msg_version = MESSAGE_VERSION;
rec.msg_type = msg_type;
rec.dest = pid;
- rec.src = sys_getpid();
+ rec.src = getpid();
rec.len = len;
kbuf = message_key_pid(pid);
@@ -304,37 +307,6 @@ BOOL message_send_pid_with_timeout(pid_t pid, int msg_type, const void *buf, siz
}
/****************************************************************************
- Count the messages pending for a particular pid. Expensive....
-****************************************************************************/
-
-unsigned int messages_pending_for_pid(pid_t pid)
-{
- TDB_DATA kbuf;
- TDB_DATA dbuf;
- char *buf;
- unsigned int message_count = 0;
-
- kbuf = message_key_pid(sys_getpid());
-
- dbuf = tdb_fetch(tdb, kbuf);
- if (dbuf.dptr == NULL || dbuf.dsize == 0) {
- SAFE_FREE(dbuf.dptr);
- return 0;
- }
-
- for (buf = dbuf.dptr; dbuf.dsize > sizeof(struct message_rec);) {
- struct message_rec rec;
- memcpy(&rec, buf, sizeof(rec));
- buf += (sizeof(rec) + rec.len);
- dbuf.dsize -= (sizeof(rec) + rec.len);
- message_count++;
- }
-
- SAFE_FREE(dbuf.dptr);
- return message_count;
-}
-
-/****************************************************************************
Retrieve all messages for the current process.
****************************************************************************/
@@ -349,11 +321,9 @@ static BOOL retrieve_all_messages(char **msgs_buf, size_t *total_len)
*msgs_buf = NULL;
*total_len = 0;
- kbuf = message_key_pid(sys_getpid());
-
- if (tdb_chainlock(tdb, kbuf) == -1)
- return False;
+ kbuf = message_key_pid(getpid());
+ tdb_chainlock(tdb, kbuf);
dbuf = tdb_fetch(tdb, kbuf);
/*
* Replace with an empty record to keep the allocated
@@ -451,7 +421,7 @@ void message_dispatch(void)
if (!n_handled) {
DEBUG(5,("message_dispatch: warning: no handlers registed for "
"msg_type %d in pid %u\n",
- msg_type, (unsigned int)sys_getpid()));
+ msg_type, (unsigned int)getpid()));
}
}
SAFE_FREE(msgs_buf);
diff --git a/source/lib/module.c b/source/lib/module.c
index 2abe918ef44..15f92db59e0 100644
--- a/source/lib/module.c
+++ b/source/lib/module.c
@@ -3,7 +3,6 @@
module loading system
Copyright (C) Jelmer Vernooij 2002-2003
- Copyright (C) Stefan (metze) Metzmacher 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
@@ -24,15 +23,31 @@
#ifdef HAVE_DLOPEN
-/* Load a dynamic module. Only log a level 0 error if we are not checking
- for the existence of a module (probling). */
-
-static NTSTATUS do_smb_load_module(const char *module_name, BOOL is_probe)
+/* Load module (or directory with modules) recursively.
+ * Includes running the init_module() function */
+NTSTATUS smb_load_module(const char *module_name)
{
void *handle;
- init_module_function *init;
+ init_module_function init;
NTSTATUS status;
const char *error;
+ struct stat st;
+ DIR *dir;
+ struct dirent *dirent;
+
+ stat(module_name, &st);
+
+ /* If the argument is a directory, recursively load all files /
+ * directories in it */
+
+ /* How about symlinks pointing to themselves - wouldn't we rather
+ * want to use wildcards here? */
+ if(S_ISDIR(st.st_mode)) {
+ dir = opendir(module_name);
+ while ((dirent = readdir(dir))) {
+ smb_load_module(dirent->d_name);
+ }
+ }
/* Always try to use LAZY symbol resolving; if the plugin has
* backwards compatibility, there might be symbols in the
@@ -41,20 +56,17 @@ static NTSTATUS do_smb_load_module(const char *module_name, BOOL is_probe)
handle = sys_dlopen(module_name, RTLD_LAZY);
if(!handle) {
- int level = is_probe ? 3 : 0;
- error = sys_dlerror();
- DEBUG(level, ("Error loading module '%s': %s\n", module_name, error ? error : ""));
+ DEBUG(0, ("Error loading module '%s': %s\n", module_name, sys_dlerror()));
return NT_STATUS_UNSUCCESSFUL;
}
- init = (init_module_function *)sys_dlsym(handle, "init_module");
+ init = (init_module_function)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));
+ DEBUG(0, ("Error trying to resolve symbol 'init_module' in %s: %s\n", module_name, error));
return NT_STATUS_UNSUCCESSFUL;
}
@@ -65,11 +77,6 @@ static NTSTATUS do_smb_load_module(const char *module_name, BOOL is_probe)
return status;
}
-NTSTATUS smb_load_module(const char *module_name)
-{
- return do_smb_load_module(module_name, False);
-}
-
/* Load all modules in list and return number of
* modules that has been successfully loaded */
int smb_load_modules(const char **modules)
@@ -88,32 +95,6 @@ int smb_load_modules(const char **modules)
return success;
}
-NTSTATUS smb_probe_module(const char *subsystem, const char *module)
-{
- pstring full_path;
-
- /* Check for absolute path */
-
- /* if we make any 'samba multibyte string'
- calls here, we break
- for loading string modules */
-
- DEBUG(5, ("Probing module '%s'\n", module));
-
- if (module[0] == '/')
- return do_smb_load_module(module, True);
-
- pstrcpy(full_path, lib_path(subsystem));
- pstrcat(full_path, "/");
- pstrcat(full_path, module);
- pstrcat(full_path, ".");
- pstrcat(full_path, shlib_ext());
-
- DEBUG(5, ("Probing module '%s': Trying to load from %s\n", module, full_path));
-
- return do_smb_load_module(full_path, True);
-}
-
#else /* HAVE_DLOPEN */
NTSTATUS smb_load_module(const char *module_name)
@@ -128,177 +109,56 @@ int smb_load_modules(const char **modules)
return -1;
}
-NTSTATUS smb_probe_module(const char *subsystem, const char *module)
-{
- DEBUG(0,("This samba executable has not been built with plugin support, not probing\n"));
- return NT_STATUS_NOT_SUPPORTED;
-}
-
#endif /* HAVE_DLOPEN */
void init_modules(void)
{
- /* FIXME: This can cause undefined symbol errors :
- * smb_register_vfs() isn't available in nmbd, for example */
if(lp_preload_modules())
smb_load_modules(lp_preload_modules());
}
-
-/***************************************************************************
- * This Function registers a idle event
- *
- * the registered funtions are run periodically
- * and maybe shutdown idle connections (e.g. to an LDAP server)
- ***************************************************************************/
-static smb_event_id_t smb_idle_event_id = 1;
-
-struct smb_idle_list_ent {
- struct smb_idle_list_ent *prev,*next;
- smb_event_id_t id;
- smb_idle_event_fn *fn;
- void *data;
- time_t interval;
- time_t lastrun;
+struct subsystem {
+ char *name;
+ register_backend_function callback;
+ struct subsystem *prev, *next;
};
-static struct smb_idle_list_ent *smb_idle_event_list = NULL;
-
-smb_event_id_t smb_register_idle_event(smb_idle_event_fn *fn, void *data, time_t interval)
-{
- struct smb_idle_list_ent *event;
-
- if (!fn) {
- return SMB_EVENT_ID_INVALID;
- }
-
- event = (struct smb_idle_list_ent *)malloc(sizeof(struct smb_idle_list_ent));
- if (!event) {
- DEBUG(0,("malloc() failed!\n"));
- return SMB_EVENT_ID_INVALID;
- }
- event->fn = fn;
- event->data = data;
- event->interval = interval;
- event->lastrun = 0;
- event->id = smb_idle_event_id++;
-
- DLIST_ADD(smb_idle_event_list,event);
-
- return event->id;
-}
-
-BOOL smb_unregister_idle_event(smb_event_id_t id)
-{
- struct smb_idle_list_ent *event = smb_idle_event_list;
-
- while(event) {
- if (event->id == id) {
- DLIST_REMOVE(smb_idle_event_list,event);
- SAFE_FREE(event);
- return True;
- }
- event = event->next;
- }
-
- return False;
-}
+static struct subsystem *subsystems = NULL;
-void smb_run_idle_events(time_t now)
+NTSTATUS register_subsystem(const char *name, register_backend_function callback)
{
- struct smb_idle_list_ent *event = smb_idle_event_list;
-
- while (event) {
- struct smb_idle_list_ent *next = event->next;
- time_t interval;
-
- if (event->interval <= 0) {
- interval = SMB_IDLE_EVENT_DEFAULT_INTERVAL;
- } else if (event->interval >= SMB_IDLE_EVENT_MIN_INTERVAL) {
- interval = event->interval;
- } else {
- interval = SMB_IDLE_EVENT_MIN_INTERVAL;
+ struct subsystem *s;
+ struct subsystem *t = subsystems;
+
+ while(t) {
+ if(!strcmp(name, t->name)) {
+ /* its already registered! */
+ DEBUG(0,("SUBSYSTEM '%s' for type already registered\n", name));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
}
- if (now >(event->lastrun+interval)) {
- event->lastrun = now;
- event->fn(&event->data,&event->interval,now);
- }
- event = next;
+ t = t->next;
}
- return;
-}
-
-/***************************************************************************
- * This Function registers a exit event
- *
- * the registered functions are run on exit()
- * and maybe shutdown idle connections (e.g. to an LDAP server)
- ***************************************************************************/
-
-struct smb_exit_list_ent {
- struct smb_exit_list_ent *prev,*next;
- smb_event_id_t id;
- smb_exit_event_fn *fn;
- void *data;
-};
-
-static struct smb_exit_list_ent *smb_exit_event_list = NULL;
-
-smb_event_id_t smb_register_exit_event(smb_exit_event_fn *fn, void *data)
-{
- struct smb_exit_list_ent *event;
- static smb_event_id_t smb_exit_event_id = 1;
-
- if (!fn) {
- return SMB_EVENT_ID_INVALID;
- }
+ s = smb_xmalloc(sizeof(struct subsystem));
- event = (struct smb_exit_list_ent *)malloc(sizeof(struct smb_exit_list_ent));
- if (!event) {
- DEBUG(0,("malloc() failed!\n"));
- return SMB_EVENT_ID_INVALID;
- }
- event->fn = fn;
- event->data = data;
- event->id = smb_exit_event_id++;
+ s->name = smb_xstrdup(name);
+ s->callback = callback;
+ s->prev = s->next = NULL;
- DLIST_ADD(smb_exit_event_list,event);
+ DLIST_ADD(subsystems, s);
- return event->id;
+ return NT_STATUS_OK;
}
-BOOL smb_unregister_exit_event(smb_event_id_t id)
+NTSTATUS register_backend(const char *subsystem, void *args)
{
- struct smb_exit_list_ent *event = smb_exit_event_list;
-
- while(event) {
- if (event->id == id) {
- DLIST_REMOVE(smb_exit_event_list,event);
- SAFE_FREE(event);
- return True;
- }
- event = event->next;
- }
-
- return False;
-}
+ /* Find the specified subsystem */
+ struct subsystem *s = subsystems;
-void smb_run_exit_events(void)
-{
- struct smb_exit_list_ent *event = smb_exit_event_list;
- struct smb_exit_list_ent *tmp = NULL;
-
- while (event) {
- event->fn(&event->data);
- tmp = event;
- event = event->next;
- /* exit event should only run one time :-)*/
- SAFE_FREE(tmp);
+ while(s) {
+ if(!strcmp(subsystem, s->name)) return s->callback(args);
+ s = s->next;
}
- /* the list is empty now...*/
- smb_exit_event_list = NULL;
-
- return;
+ return NT_STATUS_NOT_IMPLEMENTED;
}
diff --git a/source/lib/ms_fnmatch.c b/source/lib/ms_fnmatch.c
index 24232c3b523..dd015a0ac89 100644
--- a/source/lib/ms_fnmatch.c
+++ b/source/lib/ms_fnmatch.c
@@ -35,8 +35,7 @@
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,
- BOOL case_sensitive)
+ const smb_ucs2_t *string)
{
const smb_ucs2_t *p = pattern, *n = string;
smb_ucs2_t c;
@@ -62,8 +61,8 @@ static int ms_fnmatch_lanman_core(const smb_ucs2_t *pattern,
case UCS2_CHAR('>'):
if (! *n) goto next;
if (n[0] == UCS2_CHAR('.')) {
- if (! n[1] && ms_fnmatch_lanman_core(p, n+1, case_sensitive) == 0) goto match;
- if (ms_fnmatch_lanman_core(p, n, case_sensitive) == 0) goto match;
+ 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++;
@@ -73,13 +72,13 @@ static int ms_fnmatch_lanman_core(const smb_ucs2_t *pattern,
if (! *n) goto next;
if (! *p) goto match;
for (; *n; n++) {
- if (ms_fnmatch_lanman_core(p, n, case_sensitive) == 0) goto match;
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
}
break;
case UCS2_CHAR('<'):
for (; *n; n++) {
- if (ms_fnmatch_lanman_core(p, n, case_sensitive) == 0) goto match;
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
if (*n == UCS2_CHAR('.') &&
!strchr_w(n+1,UCS2_CHAR('.'))) {
n++;
@@ -89,17 +88,13 @@ static int ms_fnmatch_lanman_core(const smb_ucs2_t *pattern,
break;
case UCS2_CHAR('"'):
- if (*n == 0 && ms_fnmatch_lanman_core(p, n, case_sensitive) == 0) goto match;
+ if (*n == 0 && ms_fnmatch_lanman_core(p, n) == 0) goto match;
if (*n != UCS2_CHAR('.')) goto nomatch;
n++;
break;
default:
- if (case_sensitive) {
- if (c != *n) goto nomatch;
- } else {
- if (tolower_w(c) != tolower_w(*n)) goto nomatch;
- }
+ if (c != *n) goto nomatch;
n++;
}
}
@@ -113,7 +108,7 @@ static int ms_fnmatch_lanman_core(const smb_ucs2_t *pattern,
return -1;
next:
- if (ms_fnmatch_lanman_core(p, n, case_sensitive) == 0) goto match;
+ if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
goto nomatch;
match:
@@ -123,8 +118,7 @@ next:
return 0;
}
-static int ms_fnmatch_lanman1(const smb_ucs2_t *pattern,
- const smb_ucs2_t *string, BOOL case_sensitive)
+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};
@@ -135,11 +129,11 @@ static int ms_fnmatch_lanman1(const smb_ucs2_t *pattern,
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, case_sensitive) &&
- ms_fnmatch_lanman_core(pattern, dot, case_sensitive);
+ return ms_fnmatch_lanman_core(pattern, dotdot) &&
+ ms_fnmatch_lanman_core(pattern, dot);
}
- return ms_fnmatch_lanman_core(pattern, string, case_sensitive);
+ return ms_fnmatch_lanman_core(pattern, string);
}
@@ -152,13 +146,13 @@ static int ms_fnmatch_lanman1(const smb_ucs2_t *pattern,
Returns 0 on match, -1 on fail.
*/
static int ms_fnmatch_w(const smb_ucs2_t *pattern, const smb_ucs2_t *string,
- int protocol, BOOL case_sensitive)
+ 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, case_sensitive);
+ return ms_fnmatch_lanman1(pattern, string);
}
while ((c = *p++)) {
@@ -170,23 +164,23 @@ static int ms_fnmatch_w(const smb_ucs2_t *pattern, const smb_ucs2_t *string,
case UCS2_CHAR('>'):
if (n[0] == UCS2_CHAR('.')) {
- if (! n[1] && ms_fnmatch_w(p, n+1, protocol, case_sensitive) == 0) return 0;
- if (ms_fnmatch_w(p, n, protocol, case_sensitive) == 0) return 0;
+ 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, case_sensitive);
+ if (! *n) return ms_fnmatch_w(p, n, protocol);
n++;
break;
case UCS2_CHAR('*'):
for (; *n; n++) {
- if (ms_fnmatch_w(p, n, protocol, case_sensitive) == 0) return 0;
+ if (ms_fnmatch_w(p, n, protocol) == 0) return 0;
}
break;
case UCS2_CHAR('<'):
for (; *n; n++) {
- if (ms_fnmatch_w(p, n, protocol, case_sensitive) == 0) return 0;
+ if (ms_fnmatch_w(p, n, protocol) == 0) return 0;
if (*n == UCS2_CHAR('.') && !strchr_wa(n+1,'.')) {
n++;
break;
@@ -195,17 +189,13 @@ static int ms_fnmatch_w(const smb_ucs2_t *pattern, const smb_ucs2_t *string,
break;
case UCS2_CHAR('"'):
- if (*n == 0 && ms_fnmatch_w(p, n, protocol, case_sensitive) == 0) return 0;
+ if (*n == 0 && ms_fnmatch_w(p, n, protocol) == 0) return 0;
if (*n != UCS2_CHAR('.')) return -1;
n++;
break;
default:
- if (case_sensitive) {
- if (c != *n) return -1;
- } else {
- if (tolower_w(c) != tolower_w(*n)) return -1;
- }
+ if (c != *n) return -1;
n++;
}
}
@@ -215,35 +205,22 @@ static int ms_fnmatch_w(const smb_ucs2_t *pattern, const smb_ucs2_t *string,
return -1;
}
-int ms_fnmatch(const char *pattern, const char *string, int protocol,
- BOOL case_senstive)
+
+int ms_fnmatch(const char *pattern, const char *string, enum protocol_types protocol)
{
- wpstring buffer_pattern, buffer_string;
+ wpstring p, s;
int ret;
- size_t size;
-
- size = push_ucs2(NULL, buffer_pattern, pattern, sizeof(buffer_pattern), STR_TERMINATE);
- if (size == (size_t)-1) {
- return -1;
- /* Not quite the right answer, but finding the right one
- under this failure case is expensive, and it's pretty close */
- }
-
- size = push_ucs2(NULL, buffer_string, string, sizeof(buffer_string), STR_TERMINATE);
- if (size == (size_t)-1) {
- return -1;
- /* Not quite the right answer, but finding the right one
- under this failure case is expensive, and it's pretty close */
- }
- ret = ms_fnmatch_w(buffer_pattern, buffer_string, protocol, case_senstive);
- DEBUG(10,("ms_fnmatch(%s,%s) -> %d\n", pattern, string, 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, True);
+ return ms_fnmatch(pattern, string, PROTOCOL_NT1);
}
diff --git a/source/lib/mutex.c b/source/lib/mutex.c
new file mode 100644
index 00000000000..25ea3c55eea
--- /dev/null
+++ b/source/lib/mutex.c
@@ -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 smb_mutex_t mutex_list[MUTEX_MAX];
+
+/* the registered mutex handlers */
+static struct {
+ const char *name;
+ struct mutex_ops ops;
+} mutex_handlers;
+
+int smb_mutex_lock_by_id(enum mutex_id id, const char *name)
+{
+ return smb_mutex_lock(&mutex_list[id], name);
+}
+
+int smb_mutex_unlock_by_id(enum mutex_id id, const char *name)
+{
+ return smb_mutex_unlock(&mutex_list[id], name);
+}
+
+int smb_mutex_init(smb_mutex_t *mutex, const char *name)
+{
+ if (mutex_handlers.ops.mutex_init) {
+ return mutex_handlers.ops.mutex_init(mutex, name);
+ }
+ return 0;
+}
+
+int smb_mutex_destroy(smb_mutex_t *mutex, const char *name)
+{
+ if (mutex_handlers.ops.mutex_destroy) {
+ return mutex_handlers.ops.mutex_destroy(mutex, name);
+ }
+ return 0;
+}
+
+int smb_mutex_lock(smb_mutex_t *mutex, const char *name)
+{
+ if (mutex_handlers.ops.mutex_lock) {
+ return mutex_handlers.ops.mutex_lock(mutex, name);
+ }
+ return 0;
+}
+
+int smb_mutex_unlock(smb_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 smb_rwlock_init(smb_rwlock_t *rwlock, const char *name)
+{
+ if (mutex_handlers.ops.rwlock_init) {
+ return mutex_handlers.ops.rwlock_init(rwlock, name);
+ }
+ return 0;
+}
+
+int smb_rwlock_destroy(smb_rwlock_t *rwlock, const char *name)
+{
+ if (mutex_handlers.ops.rwlock_destroy) {
+ return mutex_handlers.ops.rwlock_destroy(rwlock, name);
+ }
+ return 0;
+}
+
+int smb_rwlock_lock_write(smb_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 smb_rwlock_lock_read(smb_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 smb_rwlock_unlock(smb_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;
+}
+
diff --git a/source/lib/pidfile.c b/source/lib/pidfile.c
index 1a462bf1287..3471f27b8ed 100644
--- a/source/lib/pidfile.c
+++ b/source/lib/pidfile.c
@@ -99,7 +99,7 @@ void pidfile_create(const char *name)
}
memset(buf, 0, sizeof(buf));
- slprintf(buf, sizeof(buf) - 1, "%u\n", (unsigned int) sys_getpid());
+ 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)));
diff --git a/source/lib/popt/CHANGES b/source/lib/popt/CHANGES
new file mode 100644
index 00000000000..b6ab2aa3088
--- /dev/null
+++ b/source/lib/popt/CHANGES
@@ -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)
diff --git a/source/lib/popt/COPYING b/source/lib/popt/COPYING
new file mode 100644
index 00000000000..b4c7ca876c6
--- /dev/null
+++ b/source/lib/popt/COPYING
@@ -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.
diff --git a/source/lib/popt/README b/source/lib/popt/README
new file mode 100644
index 00000000000..7fccc836ffa
--- /dev/null
+++ b/source/lib/popt/README
@@ -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.
diff --git a/source/lib/popt/config.m4 b/source/lib/popt/config.m4
new file mode 100644
index 00000000000..6ac5d910794
--- /dev/null
+++ b/source/lib/popt/config.m4
@@ -0,0 +1,40 @@
+#################################################
+# Check to see if we should use the included popt
+
+INCLUDED_POPT=auto
+AC_ARG_WITH(included-popt,
+[ --with-included-popt use bundled popt library, not from system],
+[
+case "$withval" in
+ yes)
+ INCLUDED_POPT=yes
+ ;;
+ no)
+ INCLUDED_POPT=no
+ ;;
+esac ],
+)
+if test x"$INCLUDED_POPT" != x"yes"; then
+ AC_CHECK_HEADERS(popt.h)
+ AC_CHECK_LIB_EXT(popt, TMP_LIBPOPT_LIBS, poptGetContext, [], [], INCLUDED_POPT=no)
+ if test x"$ac_cv_header_popt_h" = x"no"; then
+ INCLUDED_POPT=yes
+ TMP_LIBPOPT_LIBS=""
+ fi
+fi
+
+AC_MSG_CHECKING(whether to use included popt)
+if test x"$INCLUDED_POPT" != x"no"; then
+ TMP_LIBPOPT_OBJS="lib/popt/findme.o lib/popt/popt.o lib/popt/poptconfig.o \
+ lib/popt/popthelp.o lib/popt/poptparse.o"
+ CPPFLAGS="$CPPFLAGS -I$srcdir/lib/popt"
+ AC_MSG_RESULT(yes)
+else
+ AC_MSG_RESULT(no)
+fi
+
+SMB_SUBSYSTEM(LIBPOPT,[],
+ [${TMP_LIBPOPT_OBJS}],
+ [],
+ [],
+ [${TMP_LIBPOPT_LIBS}])
diff --git a/source/lib/popt/findme.c b/source/lib/popt/findme.c
new file mode 100644
index 00000000000..67a535ac65c
--- /dev/null
+++ b/source/lib/popt/findme.c
@@ -0,0 +1,47 @@
+/* (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;
+}
diff --git a/source/lib/popt/findme.h b/source/lib/popt/findme.h
new file mode 100644
index 00000000000..5e93963d603
--- /dev/null
+++ b/source/lib/popt/findme.h
@@ -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
diff --git a/source/lib/popt/popt.c b/source/lib/popt/popt.c
new file mode 100644
index 00000000000..a607f19f2ff
--- /dev/null
+++ b/source/lib/popt/popt.c
@@ -0,0 +1,798 @@
+/* (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);
+}
diff --git a/source/lib/popt/popt.h b/source/lib/popt/popt.h
new file mode 100644
index 00000000000..c33cedaec99
--- /dev/null
+++ b/source/lib/popt/popt.h
@@ -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
diff --git a/source/lib/popt/poptconfig.c b/source/lib/popt/poptconfig.c
new file mode 100644
index 00000000000..113270a5695
--- /dev/null
+++ b/source/lib/popt/poptconfig.c
@@ -0,0 +1,144 @@
+/* (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;
+}
diff --git a/source/lib/popt/popthelp.c b/source/lib/popt/popthelp.c
new file mode 100644
index 00000000000..562995c011d
--- /dev/null
+++ b/source/lib/popt/popthelp.c
@@ -0,0 +1,312 @@
+/* -*- 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);
+}
diff --git a/source/lib/popt/poptint.h b/source/lib/popt/poptint.h
new file mode 100644
index 00000000000..1847ffafe67
--- /dev/null
+++ b/source/lib/popt/poptint.h
@@ -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
diff --git a/source/lib/popt/poptparse.c b/source/lib/popt/poptparse.c
new file mode 100644
index 00000000000..93bf7acfb8f
--- /dev/null
+++ b/source/lib/popt/poptparse.c
@@ -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;
+}
diff --git a/source/lib/popt/system.h b/source/lib/popt/system.h
new file mode 100644
index 00000000000..059c0458176
--- /dev/null
+++ b/source/lib/popt/system.h
@@ -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"
diff --git a/source/lib/privileges.c b/source/lib/privileges.c
deleted file mode 100644
index abbaf112d34..00000000000
--- a/source/lib/privileges.c
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
- Privileges handling functions
- Copyright (C) Jean François Micouleau 1998-2001
- Copyright (C) Simo Sorce 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"
-
-/* defines */
-
-#define ALLOC_CHECK(ptr, err, label, str) do { if ((ptr) == NULL) { DEBUG(0, ("%s: out of memory!\n", str)); err = NT_STATUS_NO_MEMORY; goto label; } } while(0)
-#define NTSTATUS_CHECK(err, label, str1, str2) do { if (!NT_STATUS_IS_OK(err)) { DEBUG(0, ("%s: %s failed!\n", str1, str2)); } } while(0)
-
-
-PRIVS privs[] = {
- {SE_NONE, "no_privs", "No privilege"}, /* this one MUST be first */
- {SE_CREATE_TOKEN, "SeCreateTokenPrivilege", "Create Token"},
- {SE_ASSIGN_PRIMARY_TOKEN, "SeAssignPrimaryTokenPrivilege", "Assign Primary Token"},
- {SE_LOCK_MEMORY, "SeLockMemoryPrivilege", "Lock Memory"},
- {SE_INCREASE_QUOTA, "SeIncreaseQuotaPrivilege", "Increase Quota"},
- {SE_UNSOLICITED_INPUT, "SeUnsolicitedInputPrivilege", "Unsolicited Input"},
- {SE_MACHINE_ACCOUNT, "SeMachineAccountPrivilege", "Can add Machine Accounts to the Domain"},
- {SE_TCB, "SeTcbPrivilege", "TCB"},
- {SE_SECURITY, "SeSecurityPrivilege", "Security Privilege"},
- {SE_TAKE_OWNERSHIP, "SeTakeOwnershipPrivilege", "Take Ownership Privilege"},
- {SE_LOAD_DRIVER, "SeLocalDriverPrivilege", "Local Driver Privilege"},
- {SE_SYSTEM_PROFILE, "SeSystemProfilePrivilege", "System Profile Privilege"},
- {SE_SYSTEM_TIME, "SeSystemtimePrivilege", "System Time"},
- {SE_PROF_SINGLE_PROCESS, "SeProfileSingleProcessPrivilege", "Profile Single Process Privilege"},
- {SE_INC_BASE_PRIORITY, "SeIncreaseBasePriorityPrivilege", "Increase Base Priority Privilege"},
- {SE_CREATE_PAGEFILE, "SeCreatePagefilePrivilege", "Create Pagefile Privilege"},
- {SE_CREATE_PERMANENT, "SeCreatePermanentPrivilege", "Create Permanent"},
- {SE_BACKUP, "SeBackupPrivilege", "Backup Privilege"},
- {SE_RESTORE, "SeRestorePrivilege", "Restore Privilege"},
- {SE_SHUTDOWN, "SeShutdownPrivilege", "Shutdown Privilege"},
- {SE_DEBUG, "SeDebugPrivilege", "Debug Privilege"},
- {SE_AUDIT, "SeAuditPrivilege", "Audit"},
- {SE_SYSTEM_ENVIRONMENT, "SeSystemEnvironmentPrivilege", "System Environment Privilege"},
- {SE_CHANGE_NOTIFY, "SeChangeNotifyPrivilege", "Change Notify"},
- {SE_REMOTE_SHUTDOWN, "SeRemoteShutdownPrivilege", "Remote Shutdown Privilege"},
- {SE_UNDOCK, "SeUndockPrivilege", "Undock"},
- {SE_SYNC_AGENT, "SeSynchronizationAgentPrivilege", "Synchronization Agent"},
- {SE_ENABLE_DELEGATION, "SeEnableDelegationPrivilege", "Enable Delegation"},
- {SE_PRINT_OPERATOR, "SePrintOperatorPrivilege", "Printer Operator"},
- {SE_ADD_USERS, "SeAddUsersPrivilege", "Add Users"},
- {SE_ALL_PRIVS, "SeAllPrivileges", "All Privileges"}
-};
-
-
-
-/****************************************************************************
- Check if a user is a mapped group.
-
- This function will check if the group SID is mapped onto a
- system managed gid or onto a winbind manged sid.
- In the first case it will be threated like a mapped group
- and the backend should take the member list with a getgrgid
- and ignore any user that have been possibly set into the group
- object.
-
- In the second case, the group is a fully SAM managed group
- served back to the system through winbind. In this case the
- members of a Local group are "unrolled" to cope with the fact
- that unix cannot contain groups inside groups.
- The backend MUST never call any getgr* / getpw* function or
- loops with winbind may happen.
- ****************************************************************************/
-
-#if 0
-NTSTATUS is_mapped_group(BOOL *mapped, const DOM_SID *sid)
-{
- NTSTATUS result;
- gid_t id;
-
- /* look if mapping exist, do not make idmap alloc an uid if SID is not found */
- result = idmap_get_gid_from_sid(&id, sid, False);
- if (NT_STATUS_IS_OK(result)) {
- *mapped = gid_is_in_winbind_range(id);
- } else {
- *mapped = False;
- }
-
- return result;
-}
-#endif
-
-/****************************************************************************
- duplicate alloc luid_attr
- ****************************************************************************/
-NTSTATUS dupalloc_luid_attr(TALLOC_CTX *mem_ctx, LUID_ATTR **new_la, LUID_ATTR *old_la, int count)
-{
- NTSTATUS ret;
- int i;
-
- /* don't crash if the source pointer is NULL (since we don't
- do priviledges now anyways) */
-
- if ( !old_la )
- return NT_STATUS_OK;
-
- *new_la = (LUID_ATTR *)talloc(mem_ctx, count*sizeof(LUID_ATTR));
- ALLOC_CHECK(new_la, ret, done, "dupalloc_luid_attr");
-
- for (i=0; i<count; i++) {
- (*new_la)[i].luid.high = old_la[i].luid.high;
- (*new_la)[i].luid.low = old_la[i].luid.low;
- (*new_la)[i].attr = old_la[i].attr;
- }
-
- ret = NT_STATUS_OK;
-
-done:
- return ret;
-}
-
-/****************************************************************************
- initialise a privilege list
- ****************************************************************************/
-NTSTATUS init_privilege(PRIVILEGE_SET **priv_set)
-{
- NTSTATUS ret;
- TALLOC_CTX *mem_ctx = talloc_init("privilege set");
- ALLOC_CHECK(mem_ctx, ret, done, "init_privilege");
-
- *priv_set = talloc_zero(mem_ctx, sizeof(PRIVILEGE_SET));
- ALLOC_CHECK(*priv_set, ret, done, "init_privilege");
-
- (*priv_set)->mem_ctx = mem_ctx;
-
- ret = NT_STATUS_OK;
-
-done:
- return ret;
-}
-
-NTSTATUS init_priv_with_ctx(TALLOC_CTX *mem_ctx, PRIVILEGE_SET **priv_set)
-{
- NTSTATUS ret;
-
- *priv_set = talloc_zero(mem_ctx, sizeof(PRIVILEGE_SET));
- ALLOC_CHECK(*priv_set, ret, done, "init_privilege");
-
- (*priv_set)->mem_ctx = mem_ctx;
- (*priv_set)->ext_ctx = True;
-
- ret = NT_STATUS_OK;
-
-done:
- return ret;
-}
-
-void reset_privilege(PRIVILEGE_SET *priv_set)
-{
- priv_set->count = 0;
- priv_set->control = 0;
- priv_set->set = NULL;
-}
-
-void destroy_privilege(PRIVILEGE_SET **priv_set)
-{
- if (priv_set == NULL || *priv_set == NULL)
- return;
-
- reset_privilege(*priv_set);
- if (!((*priv_set)->ext_ctx))
- /* mem_ctx is local, destroy it */
- talloc_destroy((*priv_set)->mem_ctx);
- *priv_set = NULL;
-}
-
-/****************************************************************************
- add a privilege to a privilege array
- ****************************************************************************/
-NTSTATUS add_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
-{
- NTSTATUS ret;
- LUID_ATTR *new_set;
-
- /* check if the privilege is not already in the list */
- if (NT_STATUS_IS_OK(check_priv_in_privilege(priv_set, set)))
- return NT_STATUS_UNSUCCESSFUL;
-
- /* we can allocate memory to add the new privilege */
-
- new_set = (LUID_ATTR *)talloc_realloc(priv_set->mem_ctx, priv_set->set, (priv_set->count + 1) * (sizeof(LUID_ATTR)));
- ALLOC_CHECK(new_set, ret, done, "add_privilege");
-
- new_set[priv_set->count].luid.high = set.luid.high;
- new_set[priv_set->count].luid.low = set.luid.low;
- new_set[priv_set->count].attr = set.attr;
-
- priv_set->count++;
- priv_set->set = new_set;
-
- ret = NT_STATUS_OK;
-
-done:
- return ret;
-}
-
-NTSTATUS add_privilege_by_name(PRIVILEGE_SET *priv_set, const char *name)
-{
- int e;
-
- for (e = 0; privs[e].se_priv != SE_ALL_PRIVS; e++) {
- if (StrCaseCmp(privs[e].priv, name) == 0) {
- LUID_ATTR la;
-
- la.attr = 0;
- la.luid.high = 0;
- la.luid.low = privs[e].se_priv;
-
- return add_privilege(priv_set, la);
- }
- }
-
- DEBUG(1, ("add_privilege_by_name: No Such Privilege Found (%s)\n", name));
-
- return NT_STATUS_UNSUCCESSFUL;
-}
-
-/****************************************************************************
- add all the privileges to a privilege array
- ****************************************************************************/
-NTSTATUS add_all_privilege(PRIVILEGE_SET *priv_set)
-{
- NTSTATUS result = NT_STATUS_OK;
- LUID_ATTR set;
-
- set.attr = 0;
- set.luid.high = 0;
-
- /* TODO: set a proper list of privileges */
- set.luid.low = SE_ADD_USERS;
- result = add_privilege(priv_set, set);
- NTSTATUS_CHECK(result, done, "add_all_privilege", "add_privilege");
-
- set.luid.low = SE_MACHINE_ACCOUNT;
- result = add_privilege(priv_set, set);
- NTSTATUS_CHECK(result, done, "add_all_privilege", "add_privilege");
-
- set.luid.low = SE_PRINT_OPERATOR;
- result = add_privilege(priv_set, set);
- NTSTATUS_CHECK(result, done, "add_all_privilege", "add_privilege");
-
- return result;
-}
-
-/****************************************************************************
- check if the privilege list is empty
- ****************************************************************************/
-NTSTATUS check_empty_privilege(PRIVILEGE_SET *priv_set)
-{
- if (!priv_set)
- return NT_STATUS_INVALID_PARAMETER;
-
- if (priv_set->count == 0)
- return NT_STATUS_OK;
-
- return NT_STATUS_UNSUCCESSFUL;
-}
-
-/****************************************************************************
- check if the privilege is in the privilege list
- ****************************************************************************/
-NTSTATUS check_priv_in_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
-{
- int i;
-
- if (!priv_set)
- return NT_STATUS_INVALID_PARAMETER;
-
- /* if the list is empty, obviously we can't have it */
- if (NT_STATUS_IS_OK(check_empty_privilege(priv_set)))
- return NT_STATUS_UNSUCCESSFUL;
-
- for (i = 0; i < priv_set->count; i++) {
- LUID_ATTR *cur_set;
-
- cur_set = &priv_set->set[i];
- /* check only the low and high part. Checking the attr field has no meaning */
- if ( (cur_set->luid.low == set.luid.low) &&
- (cur_set->luid.high == set.luid.high) ) {
- return NT_STATUS_OK;
- }
- }
-
- return NT_STATUS_UNSUCCESSFUL;
-}
-
-/****************************************************************************
- remove a privilege from a privilege array
- ****************************************************************************/
-NTSTATUS remove_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
-{
- NTSTATUS ret;
- LUID_ATTR *new_set;
- LUID_ATTR *old_set;
- int i,j;
-
- if (!priv_set)
- return NT_STATUS_INVALID_PARAMETER;
-
- /* check if the privilege is in the list */
- if (!NT_STATUS_IS_OK(check_priv_in_privilege(priv_set, set)))
- return NT_STATUS_UNSUCCESSFUL;
-
- /* special case if it's the only privilege in the list */
- if (priv_set->count == 1) {
- reset_privilege(priv_set);
- return NT_STATUS_OK;
- }
-
- /*
- * the privilege is there, create a new list,
- * and copy the other privileges
- */
-
- old_set = priv_set->set;
-
- new_set = (LUID_ATTR *)talloc(priv_set->mem_ctx, (priv_set->count - 1) * (sizeof(LUID_ATTR)));
- ALLOC_CHECK(new_set, ret, done, "remove_privilege");
-
- for (i=0, j=0; i < priv_set->count; i++) {
- if ( (old_set[i].luid.low == set.luid.low) &&
- (old_set[i].luid.high == set.luid.high) ) {
- continue;
- }
-
- new_set[j].luid.low = old_set[i].luid.low;
- new_set[j].luid.high = old_set[i].luid.high;
- new_set[j].attr = old_set[i].attr;
-
- j++;
- }
-
- if (j != priv_set->count - 1) {
- DEBUG(0,("remove_privilege: mismatch ! difference is not -1\n"));
- DEBUGADD(0,("old count:%d, new count:%d\n", priv_set->count, j));
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- /* ok everything is fine */
-
- priv_set->count--;
- priv_set->set = new_set;
-
- ret = NT_STATUS_OK;
-
-done:
- return ret;
-}
-
-/****************************************************************************
- duplicates a privilege array
- the new privilege set must be passed inited
- (use init_privilege or init_priv_with_ctx)
- ****************************************************************************/
-NTSTATUS dup_priv_set(PRIVILEGE_SET *new_priv_set, PRIVILEGE_SET *priv_set)
-{
- NTSTATUS ret;
- LUID_ATTR *new_set;
- LUID_ATTR *old_set;
- int i;
-
- if (new_priv_set == NULL || priv_set == NULL)
- return NT_STATUS_INVALID_PARAMETER;
-
- /* special case if there are no privileges in the list */
- if (priv_set->count == 0) {
- return NT_STATUS_OK;
- }
-
- /*
- * create a new list,
- * and copy the other privileges
- */
-
- old_set = priv_set->set;
-
- new_set = (LUID_ATTR *)talloc(new_priv_set->mem_ctx, (priv_set->count) * (sizeof(LUID_ATTR)));
- ALLOC_CHECK(new_set, ret, done, "dup_priv_set");
-
- for (i=0; i < priv_set->count; i++) {
-
- new_set[i].luid.low = old_set[i].luid.low;
- new_set[i].luid.high = old_set[i].luid.high;
- new_set[i].attr = old_set[i].attr;
- }
-
- new_priv_set->count = priv_set->count;
- new_priv_set->control = priv_set->control;
- new_priv_set->set = new_set;
-
- ret = NT_STATUS_OK;
-
-done:
- return ret;
-}
-
-
-NTSTATUS user_has_privilege(struct current_user *user, uint32 privilege)
-{
- LUID_ATTR set;
-
- set.attr = 0;
- set.luid.high = 0;
- set.luid.low = privilege;
-
- return check_priv_in_privilege(user->privs, set);
-}
-
-BOOL luid_to_privilege_name(const LUID *set, fstring name)
-{
- int i;
-
- if (set->high != 0)
- return False;
-
- for (i=1; i<PRIV_ALL_INDEX-1; i++) {
- if (set->low == privs[i].se_priv) {
- fstrcpy(name, privs[i].priv);
- return True;
- }
- }
- return False;
-}
diff --git a/source/lib/replace.c b/source/lib/replace.c
index fe1cfc04eb1..a4f3da1a664 100644
--- a/source/lib/replace.c
+++ b/source/lib/replace.c
@@ -65,9 +65,6 @@ ftruncate for operating systems that don't have it
size_t len2 = strlen(s);
size_t ret = len1 + len2;
- if (len1 >= bufsize) {
- return 0;
- }
if (len1+len2 >= bufsize) {
len2 = bufsize - (len1+1);
}
@@ -326,6 +323,8 @@ duplicate a string
}
#endif /* HAVE_STRDUP */
+#ifndef WITH_PTHREADS
+/* REWRITE: not thread safe */
#ifdef REPLACE_INET_NTOA
char *rep_inet_ntoa(struct in_addr ip)
{
@@ -336,6 +335,7 @@ char *rep_inet_ntoa(struct in_addr ip)
return buf;
}
#endif /* REPLACE_INET_NTOA */
+#endif
#ifndef HAVE_STRTOUL
#ifndef ULONG_MAX
@@ -450,3 +450,26 @@ char *rep_inet_ntoa(struct in_addr ip)
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
+
+const char *global_myname(void)
+{
+ return lp_netbios_name();
+}
diff --git a/source/lib/replace1.c b/source/lib/replace1.c
deleted file mode 100644
index e1be56eb128..00000000000
--- a/source/lib/replace1.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- 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 replace1_dummy(void);
- void replace1_dummy(void) {}
-
-#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
diff --git a/source/lib/secace.c b/source/lib/secace.c
deleted file mode 100644
index 8c54c970433..00000000000
--- a/source/lib/secace.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Unix SMB/Netbios implementation.
- * SEC_ACE handling functions
- * Copyright (C) Andrew Tridgell 1992-1998,
- * Copyright (C) Jeremy R. Allison 1995-2003.
- * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
- * Copyright (C) Paul Ashton 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"
-
-/*******************************************************************
- Check if ACE has OBJECT type.
-********************************************************************/
-
-BOOL sec_ace_object(uint8 type)
-{
- if (type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
- type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT ||
- type == SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT ||
- type == SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT) {
- return True;
- }
- return False;
-}
-
-/*******************************************************************
- copy a SEC_ACE structure.
-********************************************************************/
-void sec_ace_copy(SEC_ACE *ace_dest, SEC_ACE *ace_src)
-{
- ace_dest->type = ace_src->type;
- ace_dest->flags = ace_src->flags;
- ace_dest->size = ace_src->size;
- ace_dest->info.mask = ace_src->info.mask;
- ace_dest->obj_flags = ace_src->obj_flags;
- memcpy(&ace_dest->obj_guid, &ace_src->obj_guid, sizeof(struct uuid));
- memcpy(&ace_dest->inh_guid, &ace_src->inh_guid, sizeof(struct uuid));
- sid_copy(&ace_dest->trustee, &ace_src->trustee);
-}
-
-/*******************************************************************
- Sets up a SEC_ACE structure.
-********************************************************************/
-
-void init_sec_ace(SEC_ACE *t, DOM_SID *sid, uint8 type, SEC_ACCESS mask, uint8 flag)
-{
- t->type = type;
- t->flags = flag;
- t->size = sid_size(sid) + 8;
- t->info = mask;
-
- ZERO_STRUCTP(&t->trustee);
- sid_copy(&t->trustee, sid);
-}
-
-/*******************************************************************
- adds new SID with its permissions to ACE list
-********************************************************************/
-
-NTSTATUS sec_ace_add_sid(TALLOC_CTX *ctx, SEC_ACE **new, SEC_ACE *old, unsigned *num, DOM_SID *sid, uint32 mask)
-{
- unsigned int i = 0;
-
- if (!ctx || !new || !old || !sid || !num) return NT_STATUS_INVALID_PARAMETER;
-
- *num += 1;
-
- if((new[0] = (SEC_ACE *) talloc_zero(ctx, (*num) * sizeof(SEC_ACE))) == 0)
- return NT_STATUS_NO_MEMORY;
-
- for (i = 0; i < *num - 1; i ++)
- sec_ace_copy(&(*new)[i], &old[i]);
-
- (*new)[i].type = 0;
- (*new)[i].flags = 0;
- (*new)[i].size = SEC_ACE_HEADER_SIZE + sid_size(sid);
- (*new)[i].info.mask = mask;
- sid_copy(&(*new)[i].trustee, sid);
- return NT_STATUS_OK;
-}
-
-/*******************************************************************
- modify SID's permissions at ACL
-********************************************************************/
-
-NTSTATUS sec_ace_mod_sid(SEC_ACE *ace, size_t num, DOM_SID *sid, uint32 mask)
-{
- unsigned int i = 0;
-
- if (!ace || !sid) return NT_STATUS_INVALID_PARAMETER;
-
- for (i = 0; i < num; i ++) {
- if (sid_compare(&ace[i].trustee, sid) == 0) {
- ace[i].info.mask = mask;
- return NT_STATUS_OK;
- }
- }
- return NT_STATUS_NOT_FOUND;
-}
-
-/*******************************************************************
- delete SID from ACL
-********************************************************************/
-
-NTSTATUS sec_ace_del_sid(TALLOC_CTX *ctx, SEC_ACE **new, SEC_ACE *old, uint32 *num, DOM_SID *sid)
-{
- unsigned int i = 0;
- unsigned int n_del = 0;
-
- if (!ctx || !new || !old || !sid || !num) return NT_STATUS_INVALID_PARAMETER;
-
- if((new[0] = (SEC_ACE *) talloc_zero(ctx, (*num) * sizeof(SEC_ACE))) == 0)
- return NT_STATUS_NO_MEMORY;
-
- for (i = 0; i < *num; i ++) {
- if (sid_compare(&old[i].trustee, sid) != 0)
- sec_ace_copy(&(*new)[i], &old[i]);
- else
- n_del ++;
- }
- if (n_del == 0)
- return NT_STATUS_NOT_FOUND;
- else {
- *num -= n_del;
- return NT_STATUS_OK;
- }
-}
-
-/*******************************************************************
- Compares two SEC_ACE structures
-********************************************************************/
-
-BOOL sec_ace_equal(SEC_ACE *s1, SEC_ACE *s2)
-{
- /* Trivial case */
-
- if (!s1 && !s2) return True;
-
- /* Check top level stuff */
-
- if (s1->type != s2->type || s1->flags != s2->flags ||
- s1->info.mask != s2->info.mask) {
- return False;
- }
-
- /* Check SID */
-
- if (!sid_equal(&s1->trustee, &s2->trustee)) {
- return False;
- }
-
- return True;
-}
-
-int nt_ace_inherit_comp( SEC_ACE *a1, SEC_ACE *a2)
-{
- int a1_inh = a1->flags & SEC_ACE_FLAG_INHERITED_ACE;
- int a2_inh = a2->flags & SEC_ACE_FLAG_INHERITED_ACE;
-
- if (a1_inh == a2_inh)
- return 0;
-
- if (!a1_inh && a2_inh)
- return -1;
- return 1;
-}
-
-/*******************************************************************
- Comparison function to apply the order explained below in a group.
-*******************************************************************/
-
-int nt_ace_canon_comp( SEC_ACE *a1, SEC_ACE *a2)
-{
- if ((a1->type == SEC_ACE_TYPE_ACCESS_DENIED) &&
- (a2->type != SEC_ACE_TYPE_ACCESS_DENIED))
- return -1;
-
- if ((a2->type == SEC_ACE_TYPE_ACCESS_DENIED) &&
- (a1->type != SEC_ACE_TYPE_ACCESS_DENIED))
- return 1;
-
- /* Both access denied or access allowed. */
-
- /* 1. ACEs that apply to the object itself */
-
- if (!(a1->flags & SEC_ACE_FLAG_INHERIT_ONLY) &&
- (a2->flags & SEC_ACE_FLAG_INHERIT_ONLY))
- return -1;
- else if (!(a2->flags & SEC_ACE_FLAG_INHERIT_ONLY) &&
- (a1->flags & SEC_ACE_FLAG_INHERIT_ONLY))
- return 1;
-
- /* 2. ACEs that apply to a subobject of the object, such as
- * a property set or property. */
-
- if (a1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT) &&
- !(a2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT)))
- return -1;
- else if (a2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT) &&
- !(a1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT)))
- return 1;
-
- return 0;
-}
-
-/*******************************************************************
- Functions to convert a SEC_DESC ACE DACL list into canonical order.
- JRA.
-
---- from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/order_of_aces_in_a_dacl.asp
-
-The following describes the preferred order:
-
- To ensure that noninherited ACEs have precedence over inherited ACEs,
- place all noninherited ACEs in a group before any inherited ACEs.
- This ordering ensures, for example, that a noninherited access-denied ACE
- is enforced regardless of any inherited ACE that allows access.
-
- Within the groups of noninherited ACEs and inherited ACEs, order ACEs according to ACE type, as the following shows:
- 1. Access-denied ACEs that apply to the object itself
- 2. Access-denied ACEs that apply to a subobject of the object, such as a property set or property
- 3. Access-allowed ACEs that apply to the object itself
- 4. Access-allowed ACEs that apply to a subobject of the object"
-
-********************************************************************/
-
-void dacl_sort_into_canonical_order(SEC_ACE *srclist, unsigned int num_aces)
-{
- unsigned int i;
-
- if (!srclist || num_aces == 0)
- return;
-
- /* Sort so that non-inherited ACE's come first. */
- qsort( srclist, num_aces, sizeof(srclist[0]), QSORT_CAST nt_ace_inherit_comp);
-
- /* Find the boundary between non-inherited ACEs. */
- for (i = 0; i < num_aces; i++ ) {
- SEC_ACE *curr_ace = &srclist[i];
-
- if (curr_ace->flags & SEC_ACE_FLAG_INHERITED_ACE)
- break;
- }
-
- /* i now points at entry number of the first inherited ACE. */
-
- /* Sort the non-inherited ACEs. */
- if (i)
- qsort( srclist, i, sizeof(srclist[0]), QSORT_CAST nt_ace_canon_comp);
-
- /* Now sort the inherited ACEs. */
- if (num_aces - i)
- qsort( &srclist[i], num_aces - i, sizeof(srclist[0]), QSORT_CAST nt_ace_canon_comp);
-}
-
-/*******************************************************************
- Check if this ACE has a SID in common with the token.
-********************************************************************/
-
-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;
-}
diff --git a/source/lib/secacl.c b/source/lib/secacl.c
deleted file mode 100644
index 756685a8216..00000000000
--- a/source/lib/secacl.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Unix SMB/Netbios implementation.
- * SEC_ACL handling routines
- * Copyright (C) Andrew Tridgell 1992-1998,
- * Copyright (C) Jeremy R. Allison 1995-2003.
- * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
- * Copyright (C) Paul Ashton 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"
-
-/*******************************************************************
- Create a SEC_ACL structure.
-********************************************************************/
-
-SEC_ACL *make_sec_acl(TALLOC_CTX *ctx, uint16 revision, int num_aces, SEC_ACE *ace_list)
-{
- SEC_ACL *dst;
- int i;
-
- if((dst = (SEC_ACL *)talloc_zero(ctx,sizeof(SEC_ACL))) == NULL)
- return NULL;
-
- dst->revision = revision;
- dst->num_aces = num_aces;
- dst->size = SEC_ACL_HEADER_SIZE;
-
- /* Now we need to return a non-NULL address for the ace list even
- if the number of aces required is zero. This is because there
- is a distinct difference between a NULL ace and an ace with zero
- entries in it. This is achieved by checking that num_aces is a
- positive number. */
-
- if ((num_aces) &&
- ((dst->ace = (SEC_ACE *)talloc(ctx, sizeof(SEC_ACE) * num_aces))
- == NULL)) {
- return NULL;
- }
-
- for (i = 0; i < num_aces; i++) {
- dst->ace[i] = ace_list[i]; /* Structure copy. */
- dst->size += ace_list[i].size;
- }
-
- return dst;
-}
-
-/*******************************************************************
- Duplicate a SEC_ACL structure.
-********************************************************************/
-
-SEC_ACL *dup_sec_acl(TALLOC_CTX *ctx, SEC_ACL *src)
-{
- if(src == NULL)
- return NULL;
-
- return make_sec_acl(ctx, src->revision, src->num_aces, src->ace);
-}
-
-/*******************************************************************
- Compares two SEC_ACL structures
-********************************************************************/
-
-BOOL sec_acl_equal(SEC_ACL *s1, SEC_ACL *s2)
-{
- unsigned int i, j;
-
- /* Trivial cases */
-
- if (!s1 && !s2) return True;
- if (!s1 || !s2) return False;
-
- /* Check top level stuff */
-
- if (s1->revision != s2->revision) {
- DEBUG(10, ("sec_acl_equal(): revision differs (%d != %d)\n",
- s1->revision, s2->revision));
- return False;
- }
-
- if (s1->num_aces != s2->num_aces) {
- DEBUG(10, ("sec_acl_equal(): num_aces differs (%d != %d)\n",
- s1->revision, s2->revision));
- return False;
- }
-
- /* The ACEs could be in any order so check each ACE in s1 against
- each ACE in s2. */
-
- for (i = 0; i < s1->num_aces; i++) {
- BOOL found = False;
-
- for (j = 0; j < s2->num_aces; j++) {
- if (sec_ace_equal(&s1->ace[i], &s2->ace[j])) {
- found = True;
- break;
- }
- }
-
- if (!found) return False;
- }
-
- return True;
-}
diff --git a/source/lib/secdesc.c b/source/lib/secdesc.c
deleted file mode 100644
index 411185dbfa6..00000000000
--- a/source/lib/secdesc.c
+++ /dev/null
@@ -1,522 +0,0 @@
-/*
- * Unix SMB/Netbios implementation.
- * SEC_DESC handling functions
- * Copyright (C) Andrew Tridgell 1992-1998,
- * Copyright (C) Jeremy R. Allison 1995-2003.
- * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
- * Copyright (C) Paul Ashton 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"
-
-/*******************************************************************
- Works out the linearization size of a SEC_DESC.
-********************************************************************/
-
-size_t sec_desc_size(SEC_DESC *psd)
-{
- size_t offset;
-
- if (!psd) return 0;
-
- offset = SEC_DESC_HEADER_SIZE;
-
- /* don't align */
-
- if (psd->owner_sid != NULL)
- offset += sid_size(psd->owner_sid);
-
- if (psd->grp_sid != NULL)
- offset += sid_size(psd->grp_sid);
-
- if (psd->sacl != NULL)
- offset += psd->sacl->size;
-
- if (psd->dacl != NULL)
- offset += psd->dacl->size;
-
- return offset;
-}
-
-/*******************************************************************
- Compares two SEC_DESC structures
-********************************************************************/
-
-BOOL sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
-{
- /* Trivial case */
-
- if (!s1 && !s2) {
- goto done;
- }
-
- /* Check top level stuff */
-
- if (s1->revision != s2->revision) {
- DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
- s1->revision, s2->revision));
- return False;
- }
-
- if (s1->type!= s2->type) {
- DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
- s1->type, s2->type));
- return False;
- }
-
- /* Check owner and group */
-
- if (!sid_equal(s1->owner_sid, s2->owner_sid)) {
- fstring str1, str2;
-
- sid_to_string(str1, s1->owner_sid);
- sid_to_string(str2, s2->owner_sid);
-
- DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
- str1, str2));
- return False;
- }
-
- if (!sid_equal(s1->grp_sid, s2->grp_sid)) {
- fstring str1, str2;
-
- sid_to_string(str1, s1->grp_sid);
- sid_to_string(str2, s2->grp_sid);
-
- DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
- str1, str2));
- return False;
- }
-
- /* Check ACLs present in one but not the other */
-
- if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
- (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) {
- DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
- return False;
- }
-
- /* Sigh - we have to do it the hard way by iterating over all
- the ACEs in the ACLs */
-
- if (!sec_acl_equal(s1->dacl, s2->dacl) ||
- !sec_acl_equal(s1->sacl, s2->sacl)) {
- DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
- return False;
- }
-
- done:
- DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
- return True;
-}
-
-/*******************************************************************
- Merge part of security descriptor old_sec in to the empty sections of
- security descriptor new_sec.
-********************************************************************/
-
-SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
-{
- DOM_SID *owner_sid, *group_sid;
- SEC_DESC_BUF *return_sdb;
- SEC_ACL *dacl, *sacl;
- SEC_DESC *psd = NULL;
- uint16 secdesc_type;
- size_t secdesc_size;
-
- /* Copy over owner and group sids. There seems to be no flag for
- this so just check the pointer values. */
-
- owner_sid = new_sdb->sec->owner_sid ? new_sdb->sec->owner_sid :
- old_sdb->sec->owner_sid;
-
- group_sid = new_sdb->sec->grp_sid ? new_sdb->sec->grp_sid :
- old_sdb->sec->grp_sid;
-
- secdesc_type = new_sdb->sec->type;
-
- /* Ignore changes to the system ACL. This has the effect of making
- changes through the security tab audit button not sticking.
- Perhaps in future Samba could implement these settings somehow. */
-
- sacl = NULL;
- secdesc_type &= ~SEC_DESC_SACL_PRESENT;
-
- /* Copy across discretionary ACL */
-
- if (secdesc_type & SEC_DESC_DACL_PRESENT) {
- dacl = new_sdb->sec->dacl;
- } else {
- dacl = old_sdb->sec->dacl;
- }
-
- /* Create new security descriptor from bits */
-
- psd = make_sec_desc(ctx, new_sdb->sec->revision, secdesc_type,
- owner_sid, group_sid, sacl, dacl, &secdesc_size);
-
- return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
-
- return(return_sdb);
-}
-
-/*******************************************************************
- Creates a SEC_DESC structure
-********************************************************************/
-
-SEC_DESC *make_sec_desc(TALLOC_CTX *ctx, uint16 revision, uint16 type,
- DOM_SID *owner_sid, DOM_SID *grp_sid,
- SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
-{
- SEC_DESC *dst;
- uint32 offset = 0;
-
- *sd_size = 0;
-
- if(( dst = (SEC_DESC *)talloc_zero(ctx, sizeof(SEC_DESC))) == NULL)
- return NULL;
-
- dst->revision = revision;
- dst->type = type;
-
- if (sacl)
- dst->type |= SEC_DESC_SACL_PRESENT;
- if (dacl)
- dst->type |= SEC_DESC_DACL_PRESENT;
-
- dst->off_owner_sid = 0;
- dst->off_grp_sid = 0;
- dst->off_sacl = 0;
- dst->off_dacl = 0;
-
- if(owner_sid && ((dst->owner_sid = sid_dup_talloc(ctx,owner_sid)) == NULL))
- goto error_exit;
-
- if(grp_sid && ((dst->grp_sid = sid_dup_talloc(ctx,grp_sid)) == NULL))
- goto error_exit;
-
- if(sacl && ((dst->sacl = dup_sec_acl(ctx, sacl)) == NULL))
- goto error_exit;
-
- if(dacl && ((dst->dacl = dup_sec_acl(ctx, dacl)) == NULL))
- goto error_exit;
-
- offset = SEC_DESC_HEADER_SIZE;
-
- /*
- * Work out the linearization sizes.
- */
-
- if (dst->sacl != NULL) {
- dst->off_sacl = offset;
- offset += dst->sacl->size;
- }
- if (dst->dacl != NULL) {
- dst->off_dacl = offset;
- offset += dst->dacl->size;
- }
-
- if (dst->owner_sid != NULL) {
- dst->off_owner_sid = offset;
- offset += sid_size(dst->owner_sid);
- }
-
- if (dst->grp_sid != NULL) {
- dst->off_grp_sid = offset;
- offset += sid_size(dst->grp_sid);
- }
-
- *sd_size = (size_t)offset;
- return dst;
-
-error_exit:
-
- *sd_size = 0;
- return NULL;
-}
-
-/*******************************************************************
- Duplicate a SEC_DESC structure.
-********************************************************************/
-
-SEC_DESC *dup_sec_desc(TALLOC_CTX *ctx, const SEC_DESC *src)
-{
- size_t dummy;
-
- if(src == NULL)
- return NULL;
-
- return make_sec_desc( ctx, src->revision, src->type,
- src->owner_sid, src->grp_sid, src->sacl,
- src->dacl, &dummy);
-}
-
-/*******************************************************************
- Creates a SEC_DESC structure with typical defaults.
-********************************************************************/
-
-SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, DOM_SID *owner_sid, DOM_SID *grp_sid,
- SEC_ACL *dacl, size_t *sd_size)
-{
- return make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
- owner_sid, grp_sid, NULL, dacl, sd_size);
-}
-
-/*******************************************************************
- Creates a SEC_DESC_BUF structure.
-********************************************************************/
-
-SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
-{
- SEC_DESC_BUF *dst;
-
- if((dst = (SEC_DESC_BUF *)talloc_zero(ctx, sizeof(SEC_DESC_BUF))) == NULL)
- return NULL;
-
- /* max buffer size (allocated size) */
- dst->max_len = (uint32)len;
- dst->len = (uint32)len;
-
- if(sec_desc && ((dst->sec = dup_sec_desc(ctx, sec_desc)) == NULL)) {
- return NULL;
- }
-
- dst->ptr = 0x1;
-
- return dst;
-}
-
-/*******************************************************************
- Duplicates a SEC_DESC_BUF structure.
-********************************************************************/
-
-SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
-{
- if(src == NULL)
- return NULL;
-
- return make_sec_desc_buf( ctx, src->len, src->sec);
-}
-
-/*******************************************************************
- Add a new SID with its permissions to SEC_DESC.
-********************************************************************/
-
-NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
-{
- SEC_DESC *sd = 0;
- SEC_ACL *dacl = 0;
- SEC_ACE *ace = 0;
- NTSTATUS status;
-
- *sd_size = 0;
-
- if (!ctx || !psd || !sid || !sd_size)
- return NT_STATUS_INVALID_PARAMETER;
-
- status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->ace, &psd[0]->dacl->num_aces, sid, mask);
-
- if (!NT_STATUS_IS_OK(status))
- return status;
-
- if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
- return NT_STATUS_UNSUCCESSFUL;
-
- if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
- psd[0]->grp_sid, psd[0]->sacl, dacl, sd_size)))
- return NT_STATUS_UNSUCCESSFUL;
-
- *psd = sd;
- sd = 0;
- return NT_STATUS_OK;
-}
-
-/*******************************************************************
- Modify a SID's permissions in a SEC_DESC.
-********************************************************************/
-
-NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
-{
- NTSTATUS status;
-
- if (!sd || !sid)
- return NT_STATUS_INVALID_PARAMETER;
-
- status = sec_ace_mod_sid(sd->dacl->ace, sd->dacl->num_aces, sid, mask);
-
- if (!NT_STATUS_IS_OK(status))
- return status;
-
- return NT_STATUS_OK;
-}
-
-/*******************************************************************
- Delete a SID from a SEC_DESC.
-********************************************************************/
-
-NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
-{
- SEC_DESC *sd = 0;
- SEC_ACL *dacl = 0;
- SEC_ACE *ace = 0;
- NTSTATUS status;
-
- *sd_size = 0;
-
- if (!ctx || !psd[0] || !sid || !sd_size)
- return NT_STATUS_INVALID_PARAMETER;
-
- status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->ace, &psd[0]->dacl->num_aces, sid);
-
- if (!NT_STATUS_IS_OK(status))
- return status;
-
- if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
- return NT_STATUS_UNSUCCESSFUL;
-
- if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
- psd[0]->grp_sid, psd[0]->sacl, dacl, sd_size)))
- return NT_STATUS_UNSUCCESSFUL;
-
- *psd = sd;
- sd = 0;
- return NT_STATUS_OK;
-}
-
-/* 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, SEC_DESC_SELF_RELATIVE,
- parent_ctr->owner_sid,
- parent_ctr->grp_sid,
- parent_ctr->sacl,
- new_dacl, &size);
-
- sdb = make_sec_desc_buf(ctx, size, sd);
-
- return sdb;
-}
-
-/*******************************************************************
- Sets up a SEC_ACCESS structure.
-********************************************************************/
-
-void init_sec_access(SEC_ACCESS *t, uint32 mask)
-{
- t->mask = mask;
-}
-
diff --git a/source/lib/select.c b/source/lib/select.c
index f88ad52de65..5d7e4a0ad2a 100644
--- a/source/lib/select.c
+++ b/source/lib/select.c
@@ -59,7 +59,7 @@ int sys_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, s
int ret, saved_errno;
fd_set *readfds2, readfds_buf;
- if (initialised != sys_getpid()) {
+ if (initialised != getpid()) {
pipe(select_pipe);
/*
@@ -76,7 +76,7 @@ int sys_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, s
if(set_blocking(select_pipe[1],0)==-1)
smb_panic("select_pipe[1]: O_NONBLOCK failed.\n");
- initialised = sys_getpid();
+ initialised = getpid();
}
maxfd = MAX(select_pipe[0]+1, maxfd);
diff --git a/source/lib/sendfile.c b/source/lib/sendfile.c
index 4aa76a0c74a..bcc8cb08ca1 100644
--- a/source/lib/sendfile.c
+++ b/source/lib/sendfile.c
@@ -161,7 +161,7 @@ ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T of
vec[0].sfv_fd = SFV_FD_SELF;
vec[0].sfv_flag = 0;
- vec[0].sfv_off = (off_t)header->data;
+ vec[0].sfv_off = header->data;
vec[0].sfv_len = hdr_len = header->length;
vec[1].sfv_fd = fromfd;
diff --git a/source/lib/server_mutex.c b/source/lib/server_mutex.c
index 3e5512c7342..878e5497d8e 100644
--- a/source/lib/server_mutex.c
+++ b/source/lib/server_mutex.c
@@ -30,6 +30,8 @@
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)
{
@@ -38,7 +40,7 @@ BOOL grab_server_mutex(const char *name)
DEBUG(0,("grab_server_mutex: malloc failed for %s\n", name));
return False;
}
- if (!secrets_named_mutex(mutex_server_name, 10)) {
+ 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;
@@ -50,7 +52,7 @@ BOOL grab_server_mutex(const char *name)
void release_server_mutex(void)
{
if (mutex_server_name) {
- secrets_named_mutex_release(mutex_server_name);
+ secrets_named_mutex_release(mutex_server_name, &ref_count);
SAFE_FREE(mutex_server_name);
}
}
diff --git a/source/lib/smbldap.c b/source/lib/smbldap.c
deleted file mode 100644
index 14a46fc5fb0..00000000000
--- a/source/lib/smbldap.c
+++ /dev/null
@@ -1,1234 +0,0 @@
-/*
- Unix SMB/CIFS mplementation.
- LDAP protocol helper functions for SAMBA
- Copyright (C) Jean François Micouleau 1998
- Copyright (C) Gerald Carter 2001-2003
- Copyright (C) Shahms King 2001
- Copyright (C) Andrew Bartlett 2002-2003
- Copyright (C) Stefan (metze) Metzmacher 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"
-#include "smbldap.h"
-
-#ifndef LDAP_OPT_SUCCESS
-#define LDAP_OPT_SUCCESS 0
-#endif
-
-/* Try not to hit the up or down server forever */
-
-#define SMBLDAP_DONT_PING_TIME 10 /* ping only all 10 seconds */
-#define SMBLDAP_NUM_RETRIES 8 /* retry only 8 times */
-
-#define SMBLDAP_IDLE_TIME 150 /* After 2.5 minutes disconnect */
-
-
-/* attributes used by Samba 2.2 */
-
-ATTRIB_MAP_ENTRY attrib_map_v22[] = {
- { LDAP_ATTR_UID, "uid" },
- { LDAP_ATTR_UIDNUMBER, LDAP_ATTRIBUTE_UIDNUMBER},
- { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER},
- { LDAP_ATTR_UNIX_HOME, "homeDirectory" },
- { LDAP_ATTR_PWD_LAST_SET, "pwdLastSet" },
- { LDAP_ATTR_PWD_CAN_CHANGE, "pwdCanChange" },
- { LDAP_ATTR_PWD_MUST_CHANGE, "pwdMustChange" },
- { LDAP_ATTR_LOGON_TIME, "logonTime" },
- { LDAP_ATTR_LOGOFF_TIME, "logoffTime" },
- { LDAP_ATTR_KICKOFF_TIME, "kickoffTime" },
- { LDAP_ATTR_CN, "cn" },
- { LDAP_ATTR_DISPLAY_NAME, "displayName" },
- { LDAP_ATTR_HOME_PATH, "smbHome" },
- { LDAP_ATTR_HOME_DRIVE, "homeDrives" },
- { LDAP_ATTR_LOGON_SCRIPT, "scriptPath" },
- { LDAP_ATTR_PROFILE_PATH, "profilePath" },
- { LDAP_ATTR_DESC, "description" },
- { LDAP_ATTR_USER_WKS, "userWorkstations"},
- { LDAP_ATTR_USER_RID, "rid" },
- { LDAP_ATTR_PRIMARY_GROUP_RID, "primaryGroupID"},
- { LDAP_ATTR_LMPW, "lmPassword" },
- { LDAP_ATTR_NTPW, "ntPassword" },
- { LDAP_ATTR_DOMAIN, "domain" },
- { LDAP_ATTR_OBJCLASS, "objectClass" },
- { LDAP_ATTR_ACB_INFO, "acctFlags" },
- { LDAP_ATTR_LIST_END, NULL }
-};
-
-/* attributes used by Samba 3.0's sambaSamAccount */
-
-ATTRIB_MAP_ENTRY attrib_map_v30[] = {
- { LDAP_ATTR_UID, "uid" },
- { LDAP_ATTR_UIDNUMBER, LDAP_ATTRIBUTE_UIDNUMBER},
- { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER},
- { LDAP_ATTR_UNIX_HOME, "homeDirectory" },
- { LDAP_ATTR_PWD_LAST_SET, "sambaPwdLastSet" },
- { LDAP_ATTR_PWD_CAN_CHANGE, "sambaPwdCanChange" },
- { LDAP_ATTR_PWD_MUST_CHANGE, "sambaPwdMustChange" },
- { LDAP_ATTR_LOGON_TIME, "sambaLogonTime" },
- { LDAP_ATTR_LOGOFF_TIME, "sambaLogoffTime" },
- { LDAP_ATTR_KICKOFF_TIME, "sambaKickoffTime" },
- { LDAP_ATTR_CN, "cn" },
- { LDAP_ATTR_DISPLAY_NAME, "displayName" },
- { LDAP_ATTR_HOME_DRIVE, "sambaHomeDrive" },
- { LDAP_ATTR_HOME_PATH, "sambaHomePath" },
- { LDAP_ATTR_LOGON_SCRIPT, "sambaLogonScript" },
- { LDAP_ATTR_PROFILE_PATH, "sambaProfilePath" },
- { LDAP_ATTR_DESC, "description" },
- { LDAP_ATTR_USER_WKS, "sambaUserWorkstations" },
- { LDAP_ATTR_USER_SID, LDAP_ATTRIBUTE_SID },
- { LDAP_ATTR_PRIMARY_GROUP_SID, "sambaPrimaryGroupSID" },
- { LDAP_ATTR_LMPW, "sambaLMPassword" },
- { LDAP_ATTR_NTPW, "sambaNTPassword" },
- { LDAP_ATTR_DOMAIN, "sambaDomainName" },
- { LDAP_ATTR_OBJCLASS, "objectClass" },
- { LDAP_ATTR_ACB_INFO, "sambaAcctFlags" },
- { LDAP_ATTR_MUNGED_DIAL, "sambaMungedDial" },
- { LDAP_ATTR_BAD_PASSWORD_COUNT, "sambaBadPasswordCount" },
- { LDAP_ATTR_BAD_PASSWORD_TIME, "sambaBadPasswordTime" },
- { LDAP_ATTR_MOD_TIMESTAMP, "modifyTimestamp" },
- { LDAP_ATTR_LIST_END, NULL }
-};
-
-/* attributes used for allocating RIDs */
-
-ATTRIB_MAP_ENTRY dominfo_attr_list[] = {
- { LDAP_ATTR_DOMAIN, "sambaDomainName" },
- { LDAP_ATTR_NEXT_RID, "sambaNextRid" },
- { LDAP_ATTR_NEXT_USERRID, "sambaNextUserRid" },
- { LDAP_ATTR_NEXT_GROUPRID, "sambaNextGroupRid" },
- { LDAP_ATTR_DOM_SID, LDAP_ATTRIBUTE_SID },
- { LDAP_ATTR_ALGORITHMIC_RID_BASE,"sambaAlgorithmicRidBase"},
- { LDAP_ATTR_OBJCLASS, "objectClass" },
- { LDAP_ATTR_LIST_END, NULL },
-};
-
-/* Samba 3.0 group mapping attributes */
-
-ATTRIB_MAP_ENTRY groupmap_attr_list[] = {
- { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER},
- { LDAP_ATTR_GROUP_SID, LDAP_ATTRIBUTE_SID },
- { LDAP_ATTR_GROUP_TYPE, "sambaGroupType" },
- { LDAP_ATTR_SID_LIST, "sambaSIDList" },
- { LDAP_ATTR_DESC, "description" },
- { LDAP_ATTR_DISPLAY_NAME, "displayName" },
- { LDAP_ATTR_CN, "cn" },
- { LDAP_ATTR_OBJCLASS, "objectClass" },
- { LDAP_ATTR_LIST_END, NULL }
-};
-
-ATTRIB_MAP_ENTRY groupmap_attr_list_to_delete[] = {
- { LDAP_ATTR_GROUP_SID, LDAP_ATTRIBUTE_SID },
- { LDAP_ATTR_GROUP_TYPE, "sambaGroupType" },
- { LDAP_ATTR_DESC, "description" },
- { LDAP_ATTR_DISPLAY_NAME, "displayName" },
- { LDAP_ATTR_SID_LIST, "sambaSIDList" },
- { LDAP_ATTR_LIST_END, NULL }
-};
-
-/* idmap_ldap sambaUnixIdPool */
-
-ATTRIB_MAP_ENTRY idpool_attr_list[] = {
- { LDAP_ATTR_UIDNUMBER, LDAP_ATTRIBUTE_UIDNUMBER},
- { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER},
- { LDAP_ATTR_OBJCLASS, "objectClass" },
- { LDAP_ATTR_LIST_END, NULL }
-};
-
-ATTRIB_MAP_ENTRY sidmap_attr_list[] = {
- { LDAP_ATTR_SID, LDAP_ATTRIBUTE_SID },
- { LDAP_ATTR_UIDNUMBER, LDAP_ATTRIBUTE_UIDNUMBER},
- { LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER},
- { LDAP_ATTR_OBJCLASS, "objectClass" },
- { LDAP_ATTR_LIST_END, NULL }
-};
-
-/* privileges */
-
-ATTRIB_MAP_ENTRY privilege_attr_list[] = {
- { LDAP_ATTR_CN, "sambaPrivName" },
- { LDAP_ATTR_SID_LIST, LDAP_ATTRIBUTE_SID_LIST },
- { LDAP_ATTR_DESC, "description" },
- { LDAP_ATTR_OBJCLASS, "objectClass" },
- { LDAP_ATTR_LIST_END, NULL }
-};
-
-/**********************************************************************
- perform a simple table lookup and return the attribute name
- **********************************************************************/
-
- const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key )
-{
- int i = 0;
-
- while ( table[i].attrib != LDAP_ATTR_LIST_END ) {
- if ( table[i].attrib == key )
- return table[i].name;
- i++;
- }
-
- return NULL;
-}
-
-
-/**********************************************************************
- Return the list of attribute names from a mapping table
- **********************************************************************/
-
- char** get_attr_list( ATTRIB_MAP_ENTRY table[] )
-{
- char **names;
- int i = 0;
-
- while ( table[i].attrib != LDAP_ATTR_LIST_END )
- i++;
- i++;
-
- names = (char**)malloc( sizeof(char*)*i );
- if ( !names ) {
- DEBUG(0,("get_attr_list: out of memory\n"));
- return NULL;
- }
-
- i = 0;
- while ( table[i].attrib != LDAP_ATTR_LIST_END ) {
- names[i] = strdup( table[i].name );
- i++;
- }
- names[i] = NULL;
-
- return names;
-}
-
-/*********************************************************************
- Cleanup
- ********************************************************************/
-
- void free_attr_list( char **list )
-{
- int i = 0;
-
- if ( !list )
- return;
-
- while ( list[i] ) {
- SAFE_FREE( list[i] );
- i+=1;
- }
-
- SAFE_FREE( list );
-}
-
-/*******************************************************************
- find the ldap password
-******************************************************************/
-static BOOL fetch_ldap_pw(char **dn, char** pw)
-{
- char *key = NULL;
- size_t size;
-
- *dn = smb_xstrdup(lp_ldap_admin_dn());
-
- if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, *dn) < 0) {
- SAFE_FREE(*dn);
- DEBUG(0, ("fetch_ldap_pw: asprintf failed!\n"));
- }
-
- *pw=secrets_fetch(key, &size);
- SAFE_FREE(key);
-
- if (!size) {
- /* Upgrade 2.2 style entry */
- char *p;
- char* old_style_key = strdup(*dn);
- char *data;
- fstring old_style_pw;
-
- if (!old_style_key) {
- DEBUG(0, ("fetch_ldap_pw: strdup failed!\n"));
- return False;
- }
-
- for (p=old_style_key; *p; p++)
- if (*p == ',') *p = '/';
-
- data=secrets_fetch(old_style_key, &size);
- if (!size && size < sizeof(old_style_pw)) {
- DEBUG(0,("fetch_ldap_pw: neither ldap secret retrieved!\n"));
- SAFE_FREE(old_style_key);
- SAFE_FREE(*dn);
- return False;
- }
-
- size = MIN(size, sizeof(fstring)-1);
- strncpy(old_style_pw, data, size);
- old_style_pw[size] = 0;
-
- SAFE_FREE(data);
-
- if (!secrets_store_ldap_pw(*dn, old_style_pw)) {
- DEBUG(0,("fetch_ldap_pw: ldap secret could not be upgraded!\n"));
- SAFE_FREE(old_style_key);
- SAFE_FREE(*dn);
- return False;
- }
- if (!secrets_delete(old_style_key)) {
- DEBUG(0,("fetch_ldap_pw: old ldap secret could not be deleted!\n"));
- }
-
- SAFE_FREE(old_style_key);
-
- *pw = smb_xstrdup(old_style_pw);
- }
-
- return True;
-}
-
-/*******************************************************************
- Search an attribute and return the first value found.
-******************************************************************/
-
- BOOL smbldap_get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
- const char *attribute, char *value,
- int max_len)
-{
- char **values;
-
- if ( !attribute )
- return False;
-
- value[0] = '\0';
-
- if ((values = ldap_get_values (ldap_struct, entry, attribute)) == NULL) {
- DEBUG (10, ("smbldap_get_single_attribute: [%s] = [<does not exist>]\n", attribute));
-
- return False;
- }
-
- if (convert_string(CH_UTF8, CH_UNIX,values[0], -1, value, max_len, False) == (size_t)-1) {
- DEBUG(1, ("smbldap_get_single_attribute: string conversion of [%s] = [%s] failed!\n",
- attribute, values[0]));
- ldap_value_free(values);
- return False;
- }
-
- ldap_value_free(values);
-#ifdef DEBUG_PASSWORDS
- DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n", attribute, value));
-#endif
- return True;
-}
-
- BOOL smbldap_get_single_pstring (LDAP * ldap_struct, LDAPMessage * entry,
- const char *attribute, pstring value)
-{
- return smbldap_get_single_attribute(ldap_struct, entry,
- attribute, value,
- sizeof(pstring));
-}
-
-/************************************************************************
- Routine to manage the LDAPMod structure array
- manage memory used by the array, by each struct, and values
- ***********************************************************************/
-
- void smbldap_set_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value)
-{
- LDAPMod **mods;
- int i;
- int j;
-
- mods = *modlist;
-
- /* sanity checks on the mod values */
-
- if (attribute == NULL || *attribute == '\0')
- return;
-#if 0 /* commented out after discussion with abartlet. Do not reenable.
- left here so other so re-add similar code --jerry */
- if (value == NULL || *value == '\0')
- return;
-#endif
-
- if (mods == NULL)
- {
- mods = (LDAPMod **) malloc(sizeof(LDAPMod *));
- if (mods == NULL)
- {
- DEBUG(0, ("make_a_mod: out of memory!\n"));
- return;
- }
- mods[0] = NULL;
- }
-
- for (i = 0; mods[i] != NULL; ++i) {
- if (mods[i]->mod_op == modop && strequal(mods[i]->mod_type, attribute))
- break;
- }
-
- if (mods[i] == NULL)
- {
- mods = (LDAPMod **) Realloc (mods, (i + 2) * sizeof (LDAPMod *));
- if (mods == NULL)
- {
- DEBUG(0, ("make_a_mod: out of memory!\n"));
- return;
- }
- mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));
- if (mods[i] == NULL)
- {
- DEBUG(0, ("make_a_mod: out of memory!\n"));
- return;
- }
- mods[i]->mod_op = modop;
- mods[i]->mod_values = NULL;
- mods[i]->mod_type = strdup(attribute);
- mods[i + 1] = NULL;
- }
-
- if (value != NULL)
- {
- char *utf8_value = NULL;
-
- j = 0;
- if (mods[i]->mod_values != NULL) {
- for (; mods[i]->mod_values[j] != NULL; j++);
- }
- mods[i]->mod_values = (char **)Realloc(mods[i]->mod_values,
- (j + 2) * sizeof (char *));
-
- if (mods[i]->mod_values == NULL) {
- DEBUG (0, ("make_a_mod: Memory allocation failure!\n"));
- return;
- }
-
- if (push_utf8_allocate(&utf8_value, value) == (size_t)-1) {
- DEBUG (0, ("make_a_mod: String conversion failure!\n"));
- return;
- }
-
- mods[i]->mod_values[j] = utf8_value;
-
- mods[i]->mod_values[j + 1] = NULL;
- }
- *modlist = mods;
-}
-
-/**********************************************************************
- Set attribute to newval in LDAP, regardless of what value the
- attribute had in LDAP before.
-*********************************************************************/
-
- void smbldap_make_mod(LDAP *ldap_struct, LDAPMessage *existing,
- LDAPMod ***mods,
- const char *attribute, const char *newval)
-{
- char oldval[2048]; /* current largest allowed value is mungeddial */
- BOOL existed;
-
- if (existing != NULL) {
- existed = smbldap_get_single_attribute(ldap_struct, existing, attribute, oldval, sizeof(oldval));
- } else {
- existed = False;
- *oldval = '\0';
- }
-
- /* all of our string attributes are case insensitive */
-
- if (existed && newval && (StrCaseCmp(oldval, newval) == 0)) {
-
- /* Believe it or not, but LDAP will deny a delete and
- an add at the same time if the values are the
- same... */
- return;
- }
-
- if (existed) {
- /* There has been no value before, so don't delete it.
- * Here's a possible race: We might end up with
- * duplicate attributes */
- /* By deleting exactly the value we found in the entry this
- * should be race-free in the sense that the LDAP-Server will
- * deny the complete operation if somebody changed the
- * attribute behind our back. */
- /* This will also allow modifying single valued attributes
- * in Novell NDS. In NDS you have to first remove attribute and then
- * you could add new value */
-
- smbldap_set_mod(mods, LDAP_MOD_DELETE, attribute, oldval);
- }
-
- /* Regardless of the real operation (add or modify)
- we add the new value here. We rely on deleting
- the old value, should it exist. */
-
- if ((newval != NULL) && (strlen(newval) > 0)) {
- smbldap_set_mod(mods, LDAP_MOD_ADD, attribute, newval);
- }
-}
-
-/**********************************************************************
- Some varients of the LDAP rebind code do not pass in the third 'arg'
- pointer to a void*, so we try and work around it by assuming that the
- value of the 'LDAP *' pointer is the same as the one we had passed in
- **********************************************************************/
-
-struct smbldap_state_lookup {
- LDAP *ld;
- struct smbldap_state *smbldap_state;
- struct smbldap_state_lookup *prev, *next;
-};
-
-static struct smbldap_state_lookup *smbldap_state_lookup_list;
-
-static struct smbldap_state *smbldap_find_state(LDAP *ld)
-{
- struct smbldap_state_lookup *t;
-
- for (t = smbldap_state_lookup_list; t; t = t->next) {
- if (t->ld == ld) {
- return t->smbldap_state;
- }
- }
- return NULL;
-}
-
-static void smbldap_delete_state(struct smbldap_state *smbldap_state)
-{
- struct smbldap_state_lookup *t;
-
- for (t = smbldap_state_lookup_list; t; t = t->next) {
- if (t->smbldap_state == smbldap_state) {
- DLIST_REMOVE(smbldap_state_lookup_list, t);
- SAFE_FREE(t);
- return;
- }
- }
-}
-
-static void smbldap_store_state(LDAP *ld, struct smbldap_state *smbldap_state)
-{
- struct smbldap_state *tmp_ldap_state;
- struct smbldap_state_lookup *t;
- struct smbldap_state_lookup *tmp;
-
- if ((tmp_ldap_state = smbldap_find_state(ld))) {
- SMB_ASSERT(tmp_ldap_state == smbldap_state);
- return;
- }
-
- t = smb_xmalloc(sizeof(*t));
- ZERO_STRUCTP(t);
-
- DLIST_ADD_END(smbldap_state_lookup_list, t, tmp);
- t->ld = ld;
- t->smbldap_state = smbldap_state;
-}
-
-/*******************************************************************
- open a connection to the ldap server.
-******************************************************************/
-static int smbldap_open_connection (struct smbldap_state *ldap_state)
-
-{
- int rc = LDAP_SUCCESS;
- int version;
- BOOL ldap_v3 = False;
- LDAP **ldap_struct = &ldap_state->ldap_struct;
-
-#ifdef HAVE_LDAP_INITIALIZE
- DEBUG(10, ("smbldap_open_connection: %s\n", ldap_state->uri));
-
- if ((rc = ldap_initialize(ldap_struct, ldap_state->uri)) != LDAP_SUCCESS) {
- DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc)));
- return rc;
- }
-#else
-
- /* Parse the string manually */
-
- {
- int port = 0;
- fstring protocol;
- fstring host;
- const char *p = ldap_state->uri;
- SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
-
- /* skip leading "URL:" (if any) */
- if ( strnequal( p, "URL:", 4 ) ) {
- p += 4;
- }
-
- sscanf(p, "%10[^:]://%254[^:/]:%d", protocol, host, &port);
-
- if (port == 0) {
- if (strequal(protocol, "ldap")) {
- port = LDAP_PORT;
- } else if (strequal(protocol, "ldaps")) {
- port = LDAPS_PORT;
- } else {
- DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
- }
- }
-
- if ((*ldap_struct = ldap_init(host, port)) == NULL) {
- DEBUG(0, ("ldap_init failed !\n"));
- return LDAP_OPERATIONS_ERROR;
- }
-
- if (strequal(protocol, "ldaps")) {
-#ifdef LDAP_OPT_X_TLS
- int tls = LDAP_OPT_X_TLS_HARD;
- if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
- {
- DEBUG(0, ("Failed to setup a TLS session\n"));
- }
-
- DEBUG(3,("LDAPS option set...!\n"));
-#else
- DEBUG(0,("smbldap_open_connection: Secure connection not supported by LDAP client libraries!\n"));
- return LDAP_OPERATIONS_ERROR;
-#endif
- }
- }
-#endif
-
- /* Store the LDAP pointer in a lookup list */
-
- smbldap_store_state(*ldap_struct, ldap_state);
-
- /* Upgrade to LDAPv3 if possible */
-
- if (ldap_get_option(*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS)
- {
- if (version != LDAP_VERSION3)
- {
- version = LDAP_VERSION3;
- if (ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) {
- ldap_v3 = True;
- }
- } else {
- ldap_v3 = True;
- }
- }
-
- if (lp_ldap_ssl() == LDAP_SSL_START_TLS) {
-#ifdef LDAP_OPT_X_TLS
- if (ldap_v3) {
- if ((rc = ldap_start_tls_s (*ldap_struct, NULL, NULL)) != LDAP_SUCCESS)
- {
- DEBUG(0,("Failed to issue the StartTLS instruction: %s\n",
- ldap_err2string(rc)));
- return rc;
- }
- DEBUG (3, ("StartTLS issued: using a TLS connection\n"));
- } else {
-
- DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
- return LDAP_OPERATIONS_ERROR;
- }
-#else
- DEBUG(0,("smbldap_open_connection: StartTLS not supported by LDAP client libraries!\n"));
- return LDAP_OPERATIONS_ERROR;
-#endif
- }
-
- DEBUG(2, ("smbldap_open_connection: connection opened\n"));
- return rc;
-}
-
-
-/*******************************************************************
- a rebind function for authenticated referrals
- This version takes a void* that we can shove useful stuff in :-)
-******************************************************************/
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-#else
-static int rebindproc_with_state (LDAP * ld, char **whop, char **credp,
- int *methodp, int freeit, void *arg)
-{
- struct smbldap_state *ldap_state = arg;
-
- /** @TODO Should we be doing something to check what servers we rebind to?
- Could we get a referral to a machine that we don't want to give our
- username and password to? */
-
- if (freeit) {
- SAFE_FREE(*whop);
- memset(*credp, '\0', strlen(*credp));
- SAFE_FREE(*credp);
- } else {
- DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n",
- ldap_state->bind_dn));
-
- *whop = strdup(ldap_state->bind_dn);
- if (!*whop) {
- return LDAP_NO_MEMORY;
- }
- *credp = strdup(ldap_state->bind_secret);
- if (!*credp) {
- SAFE_FREE(*whop);
- return LDAP_NO_MEMORY;
- }
- *methodp = LDAP_AUTH_SIMPLE;
- }
-
- gettimeofday(&(ldap_state->last_rebind),NULL);
-
- return 0;
-}
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-/*******************************************************************
- a rebind function for authenticated referrals
- This version takes a void* that we can shove useful stuff in :-)
- and actually does the connection.
-******************************************************************/
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-static int rebindproc_connect_with_state (LDAP *ldap_struct,
- LDAP_CONST char *url,
- ber_tag_t request,
- ber_int_t msgid, void *arg)
-{
- struct smbldap_state *ldap_state = arg;
- int rc;
- DEBUG(5,("rebindproc_connect_with_state: Rebinding as \"%s\"\n",
- ldap_state->bind_dn));
-
- /** @TODO Should we be doing something to check what servers we rebind to?
- Could we get a referral to a machine that we don't want to give our
- username and password to? */
-
- rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
-
- gettimeofday(&(ldap_state->last_rebind),NULL);
-
- return rc;
-}
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-/*******************************************************************
- Add a rebind function for authenticated referrals
-******************************************************************/
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-#else
-# if LDAP_SET_REBIND_PROC_ARGS == 2
-static int rebindproc (LDAP *ldap_struct, char **whop, char **credp,
- int *method, int freeit )
-{
- struct smbldap_state *ldap_state = smbldap_find_state(ldap_struct);
-
- return rebindproc_with_state(ldap_struct, whop, credp,
- method, freeit, ldap_state);
-
-}
-# endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-/*******************************************************************
- a rebind function for authenticated referrals
- this also does the connection, but no void*.
-******************************************************************/
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-# if LDAP_SET_REBIND_PROC_ARGS == 2
-static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
- ber_int_t msgid)
-{
- struct smbldap_state *ldap_state = smbldap_find_state(ld);
-
- return rebindproc_connect_with_state(ld, url, (ber_tag_t)request, msgid,
- ldap_state);
-}
-# endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-/*******************************************************************
- connect to the ldap server under system privilege.
-******************************************************************/
-static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_struct)
-{
- int rc;
- char *ldap_dn;
- char *ldap_secret;
-
- /* get the password */
- if (!fetch_ldap_pw(&ldap_dn, &ldap_secret))
- {
- DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n"));
- return LDAP_INVALID_CREDENTIALS;
- }
-
- ldap_state->bind_dn = ldap_dn;
- ldap_state->bind_secret = ldap_secret;
-
- /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
- (OpenLDAP) doesnt' seem to support it */
-
- DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n",
- ldap_state->uri, ldap_dn));
-
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-# if LDAP_SET_REBIND_PROC_ARGS == 2
- ldap_set_rebind_proc(ldap_struct, &rebindproc_connect);
-# endif
-# if LDAP_SET_REBIND_PROC_ARGS == 3
- ldap_set_rebind_proc(ldap_struct, &rebindproc_connect_with_state, (void *)ldap_state);
-# endif
-#else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-# if LDAP_SET_REBIND_PROC_ARGS == 2
- ldap_set_rebind_proc(ldap_struct, &rebindproc);
-# endif
-# if LDAP_SET_REBIND_PROC_ARGS == 3
- ldap_set_rebind_proc(ldap_struct, &rebindproc_with_state, (void *)ldap_state);
-# endif
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
- rc = ldap_simple_bind_s(ldap_struct, ldap_dn, ldap_secret);
-
- if (rc != LDAP_SUCCESS) {
- char *ld_error = NULL;
- ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
- &ld_error);
- DEBUG(ldap_state->num_failures ? 2 : 0,
- ("failed to bind to server with dn= %s Error: %s\n\t%s\n",
- ldap_dn ? ldap_dn : "(unknown)", ldap_err2string(rc),
- ld_error ? ld_error : "(unknown)"));
- SAFE_FREE(ld_error);
- ldap_state->num_failures++;
- return rc;
- }
-
- ldap_state->num_failures = 0;
-
- DEBUG(3, ("ldap_connect_system: succesful connection to the LDAP server\n"));
- return rc;
-}
-
-/**********************************************************************
-Connect to LDAP server (called before every ldap operation)
-*********************************************************************/
-static int smbldap_open(struct smbldap_state *ldap_state)
-{
- int rc;
- SMB_ASSERT(ldap_state);
-
-#ifndef NO_LDAP_SECURITY
- if (geteuid() != 0) {
- DEBUG(0, ("smbldap_open: cannot access LDAP when not root..\n"));
- return LDAP_INSUFFICIENT_ACCESS;
- }
-#endif
-
- if ((ldap_state->ldap_struct != NULL) && ((ldap_state->last_ping + SMBLDAP_DONT_PING_TIME) < time(NULL))) {
- struct sockaddr_un addr;
- socklen_t len = sizeof(addr);
- int sd;
- if (ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_DESC, &sd) == 0 &&
- getpeername(sd, (struct sockaddr *) &addr, &len) < 0) {
- /* the other end has died. reopen. */
- ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
- ldap_state->ldap_struct = NULL;
- ldap_state->last_ping = (time_t)0;
- } else {
- ldap_state->last_ping = time(NULL);
- }
- }
-
- if (ldap_state->ldap_struct != NULL) {
- DEBUG(11,("smbldap_open: already connected to the LDAP server\n"));
- return LDAP_SUCCESS;
- }
-
- if ((rc = smbldap_open_connection(ldap_state))) {
- return rc;
- }
-
- if ((rc = smbldap_connect_system(ldap_state, ldap_state->ldap_struct))) {
- ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
- ldap_state->ldap_struct = NULL;
- return rc;
- }
-
-
- ldap_state->last_ping = time(NULL);
- DEBUG(4,("The LDAP server is succesful connected\n"));
-
- return LDAP_SUCCESS;
-}
-
-/**********************************************************************
-Disconnect from LDAP server
-*********************************************************************/
-static NTSTATUS smbldap_close(struct smbldap_state *ldap_state)
-{
- if (!ldap_state)
- return NT_STATUS_INVALID_PARAMETER;
-
- if (ldap_state->ldap_struct != NULL) {
- ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
- ldap_state->ldap_struct = NULL;
- }
-
- smbldap_delete_state(ldap_state);
-
- DEBUG(5,("The connection to the LDAP server was closed\n"));
- /* maybe free the results here --metze */
-
-
-
- return NT_STATUS_OK;
-}
-
-int smbldap_retry_open(struct smbldap_state *ldap_state, int *attempts)
-{
- int rc;
-
- SMB_ASSERT(ldap_state && attempts);
-
- if (*attempts != 0) {
- unsigned int sleep_time;
- uint8 rand_byte;
-
- /* Sleep for a random timeout */
- rand_byte = (char)(sys_random());
-
- sleep_time = (((*attempts)*(*attempts))/2)*rand_byte*2;
- /* we retry after (0.5, 1, 2, 3, 4.5, 6) seconds
- on average.
- */
- DEBUG(3, ("Sleeping for %u milliseconds before reconnecting\n",
- sleep_time));
- smb_msleep(sleep_time);
- }
- (*attempts)++;
-
- if ((rc = smbldap_open(ldap_state))) {
- DEBUG(1,("Connection to LDAP Server failed for the %d try!\n",*attempts));
- return rc;
- }
-
- return LDAP_SUCCESS;
-}
-
-
-/*********************************************************************
- ********************************************************************/
-
-int smbldap_search(struct smbldap_state *ldap_state,
- const char *base, int scope, const char *filter,
- char *attrs[], int attrsonly,
- LDAPMessage **res)
-{
- int rc = LDAP_SERVER_DOWN;
- int attempts = 0;
- char *utf8_filter;
-
- SMB_ASSERT(ldap_state);
-
- DEBUG(5,("smbldap_search: base => [%s], filter => [%s], scope => [%d]\n",
- base, filter, scope));
-
- if (ldap_state->last_rebind.tv_sec > 0) {
- struct timeval tval;
- int tdiff = 0;
- int sleep_time = 0;
-
- ZERO_STRUCT(tval);
-
- gettimeofday(&tval,NULL);
-
- tdiff = 1000000 *(tval.tv_sec - ldap_state->last_rebind.tv_sec) +
- (tval.tv_usec - ldap_state->last_rebind.tv_usec);
-
- sleep_time = ((1000*lp_ldap_replication_sleep())-tdiff)/1000;
-
- if (sleep_time > 0) {
- /* we wait for the LDAP replication */
- DEBUG(5,("smbldap_search: waiting %d milliseconds for LDAP replication.\n",sleep_time));
- smb_msleep(sleep_time);
- DEBUG(5,("smbldap_search: go on!\n"));
- ZERO_STRUCT(ldap_state->last_rebind);
- }
- }
-
- if (push_utf8_allocate(&utf8_filter, filter) == (size_t)-1) {
- return LDAP_NO_MEMORY;
- }
-
- while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) {
-
- if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
- continue;
-
- rc = ldap_search_s(ldap_state->ldap_struct, base, scope,
- utf8_filter, attrs, attrsonly, res);
- }
-
- if (rc == LDAP_SERVER_DOWN) {
- DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
- smbldap_close(ldap_state);
- }
-
- ldap_state->last_use = time(NULL);
-
- SAFE_FREE(utf8_filter);
- return rc;
-}
-
-int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
-{
- int rc = LDAP_SERVER_DOWN;
- int attempts = 0;
- char *utf8_dn;
-
- SMB_ASSERT(ldap_state);
-
- DEBUG(5,("smbldap_modify: dn => [%s]\n", dn ));
-
- if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
- return LDAP_NO_MEMORY;
- }
-
- while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) {
-
- if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
- continue;
-
- rc = ldap_modify_s(ldap_state->ldap_struct, utf8_dn, attrs);
- }
-
- if (rc == LDAP_SERVER_DOWN) {
- DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
- smbldap_close(ldap_state);
- }
-
- ldap_state->last_use = time(NULL);
-
- SAFE_FREE(utf8_dn);
- return rc;
-}
-
-int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
-{
- int rc = LDAP_SERVER_DOWN;
- int attempts = 0;
- char *utf8_dn;
-
- SMB_ASSERT(ldap_state);
-
- DEBUG(5,("smbldap_add: dn => [%s]\n", dn ));
-
- if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
- return LDAP_NO_MEMORY;
- }
-
- while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) {
-
- if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
- continue;
-
- rc = ldap_add_s(ldap_state->ldap_struct, utf8_dn, attrs);
- }
-
- if (rc == LDAP_SERVER_DOWN) {
- DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
- smbldap_close(ldap_state);
- }
-
- ldap_state->last_use = time(NULL);
-
- SAFE_FREE(utf8_dn);
- return rc;
-}
-
-int smbldap_delete(struct smbldap_state *ldap_state, const char *dn)
-{
- int rc = LDAP_SERVER_DOWN;
- int attempts = 0;
- char *utf8_dn;
-
- SMB_ASSERT(ldap_state);
-
- DEBUG(5,("smbldap_delete: dn => [%s]\n", dn ));
-
- if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
- return LDAP_NO_MEMORY;
- }
-
- while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) {
-
- if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
- continue;
-
- rc = ldap_delete_s(ldap_state->ldap_struct, utf8_dn);
- }
-
- if (rc == LDAP_SERVER_DOWN) {
- DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
- smbldap_close(ldap_state);
- }
-
- ldap_state->last_use = time(NULL);
-
- SAFE_FREE(utf8_dn);
- return rc;
-}
-
-int smbldap_extended_operation(struct smbldap_state *ldap_state,
- LDAP_CONST char *reqoid, struct berval *reqdata,
- LDAPControl **serverctrls, LDAPControl **clientctrls,
- char **retoidp, struct berval **retdatap)
-{
- int rc = LDAP_SERVER_DOWN;
- int attempts = 0;
-
- if (!ldap_state)
- return (-1);
-
- while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) {
-
- if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
- continue;
-
- rc = ldap_extended_operation_s(ldap_state->ldap_struct, reqoid, reqdata,
- serverctrls, clientctrls, retoidp, retdatap);
- }
-
- if (rc == LDAP_SERVER_DOWN) {
- DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
- smbldap_close(ldap_state);
- }
-
- ldap_state->last_use = time(NULL);
-
- return rc;
-}
-
-/*******************************************************************
- run the search by name.
-******************************************************************/
-int smbldap_search_suffix (struct smbldap_state *ldap_state, const char *filter,
- char **search_attr, LDAPMessage ** result)
-{
- int scope = LDAP_SCOPE_SUBTREE;
- int rc;
-
- rc = smbldap_search(ldap_state, lp_ldap_suffix(), scope, filter, search_attr, 0, result);
-
- if (rc != LDAP_SUCCESS) {
- char *ld_error = NULL;
- ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
- &ld_error);
- DEBUG(0,("smbldap_search_suffix: Problem during the LDAP search: %s (%s)\n",
- ld_error?ld_error:"(unknown)", ldap_err2string (rc)));
- SAFE_FREE(ld_error);
- }
-
- return rc;
-}
-
-static void smbldap_idle_fn(void **data, time_t *interval, time_t now)
-{
- struct smbldap_state *state = (struct smbldap_state *)(*data);
-
- if (state->ldap_struct == NULL) {
- DEBUG(10,("ldap connection not connected...\n"));
- return;
- }
-
- if ((state->last_use+SMBLDAP_IDLE_TIME) > now) {
- DEBUG(10,("ldap connection not idle...\n"));
- return;
- }
-
- DEBUG(7,("ldap connection idle...closing connection\n"));
- smbldap_close(state);
-}
-
-/**********************************************************************
- Housekeeping
- *********************************************************************/
-
-void smbldap_free_struct(struct smbldap_state **ldap_state)
-{
- smbldap_close(*ldap_state);
-
- if ((*ldap_state)->bind_secret) {
- memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret));
- }
-
- SAFE_FREE((*ldap_state)->bind_dn);
- SAFE_FREE((*ldap_state)->bind_secret);
-
- smb_unregister_idle_event((*ldap_state)->event_id);
-
- *ldap_state = NULL;
-
- /* No need to free any further, as it is talloc()ed */
-}
-
-
-/**********************************************************************
- Intitalise the 'general' ldap structures, on which ldap operations may be conducted
- *********************************************************************/
-
-NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, const char *location, struct smbldap_state **smbldap_state)
-{
- *smbldap_state = talloc_zero(mem_ctx, sizeof(**smbldap_state));
- if (!*smbldap_state) {
- DEBUG(0, ("talloc() failed for ldapsam private_data!\n"));
- return NT_STATUS_NO_MEMORY;
- }
-
- if (location) {
- (*smbldap_state)->uri = talloc_strdup(mem_ctx, location);
- } else {
- (*smbldap_state)->uri = "ldap://localhost";
- }
-
- (*smbldap_state)->event_id =
- smb_register_idle_event(smbldap_idle_fn, (void *)(*smbldap_state),
- SMBLDAP_IDLE_TIME);
-
- if ((*smbldap_state)->event_id == SMB_EVENT_ID_INVALID) {
- DEBUG(0,("Failed to register LDAP idle event!\n"));
- return NT_STATUS_INVALID_HANDLE;
- }
-
- return NT_STATUS_OK;
-}
-
-/*******************************************************************
- Return a copy of the DN for a LDAPMessage. Convert from utf8 to CH_UNIX.
-********************************************************************/
-
-char *smbldap_get_dn(LDAP *ld, LDAPMessage *entry)
-{
- char *utf8_dn, *unix_dn;
-
- utf8_dn = ldap_get_dn(ld, entry);
- if (!utf8_dn) {
- DEBUG (5, ("smbldap_get_dn: ldap_get_dn failed\n"));
- return NULL;
- }
- if (pull_utf8_allocate(&unix_dn, utf8_dn) == (size_t)-1) {
- DEBUG (0, ("smbldap_get_dn: String conversion failure utf8 [%s]\n", utf8_dn));
- return NULL;
- }
- ldap_memfree(utf8_dn);
- return unix_dn;
-}
diff --git a/source/lib/smbldap_util.c b/source/lib/smbldap_util.c
deleted file mode 100644
index f6097599bc5..00000000000
--- a/source/lib/smbldap_util.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- Unix SMB/CIFS mplementation.
- LDAP protocol helper functions for SAMBA
- Copyright (C) Jean François Micouleau 1998
- Copyright (C) Gerald Carter 2001-2003
- Copyright (C) Shahms King 2001
- Copyright (C) Andrew Bartlett 2002-2003
- Copyright (C) Stefan (metze) Metzmacher 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"
-#include "smbldap.h"
-
-/**********************************************************************
- Add the sambaDomain to LDAP, so we don't have to search for this stuff
- again. This is a once-add operation for now.
-
- TODO: Add other attributes, and allow modification.
-*********************************************************************/
-static NTSTATUS add_new_domain_info(struct smbldap_state *ldap_state,
- const char *domain_name)
-{
- fstring sid_string;
- fstring algorithmic_rid_base_string;
- pstring filter, dn;
- LDAPMod **mods = NULL;
- int rc;
- int ldap_op;
- LDAPMessage *result = NULL;
- int num_result;
- char **attr_list;
- uid_t u_low, u_high;
- gid_t g_low, g_high;
- uint32 rid_low, rid_high;
-
- slprintf (filter, sizeof (filter) - 1, "(&(%s=%s)(objectclass=%s))",
- get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
- domain_name, LDAP_OBJ_DOMINFO);
-
- attr_list = get_attr_list( dominfo_attr_list );
- rc = smbldap_search_suffix(ldap_state, filter, attr_list, &result);
- free_attr_list( attr_list );
-
- if (rc != LDAP_SUCCESS) {
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- num_result = ldap_count_entries(ldap_state->ldap_struct, result);
-
- if (num_result > 1) {
- DEBUG (0, ("More than domain with that name exists: bailing out!\n"));
- ldap_msgfree(result);
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- /* Check if we need to add an entry */
- DEBUG(3,("Adding new domain\n"));
- ldap_op = LDAP_MOD_ADD;
-
- pstr_sprintf(dn, "%s=%s,%s", get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
- domain_name, lp_ldap_suffix());
-
- /* Free original search */
- ldap_msgfree(result);
-
- /* make the changes - the entry *must* not already have samba attributes */
- smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
- domain_name);
-
- /* If we don't have an entry, then ask secrets.tdb for what it thinks.
- It may choose to make it up */
-
- sid_to_string(sid_string, get_global_sam_sid());
- smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID), sid_string);
-
- slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string) - 1, "%i", algorithmic_rid_base());
- smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
- algorithmic_rid_base_string);
- smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_DOMINFO);
-
- /* add the sambaNext[User|Group]Rid attributes if the idmap ranges are set.
- TODO: fix all the places where the line between idmap and normal operations
- needed by smbd gets fuzzy --jerry 2003-08-11 */
-
- if ( lp_idmap_uid(&u_low, &u_high) && lp_idmap_gid(&g_low, &g_high)
- && get_free_rid_range(&rid_low, &rid_high) )
- {
- fstring rid_str;
-
- fstr_sprintf( rid_str, "%i", rid_high|USER_RID_TYPE );
- DEBUG(10,("setting next available user rid [%s]\n", rid_str));
- smbldap_set_mod(&mods, LDAP_MOD_ADD,
- get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
- rid_str);
-
- fstr_sprintf( rid_str, "%i", rid_high|GROUP_RID_TYPE );
- DEBUG(10,("setting next available group rid [%s]\n", rid_str));
- smbldap_set_mod(&mods, LDAP_MOD_ADD,
- get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
- rid_str);
-
- }
-
-
- switch(ldap_op)
- {
- case LDAP_MOD_ADD:
- rc = smbldap_add(ldap_state, dn, mods);
- break;
- case LDAP_MOD_REPLACE:
- rc = smbldap_modify(ldap_state, dn, mods);
- break;
- default:
- DEBUG(0,("Wrong LDAP operation type: %d!\n", ldap_op));
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- if (rc!=LDAP_SUCCESS) {
- char *ld_error = NULL;
- ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
- DEBUG(1,("failed to %s domain dn= %s with: %s\n\t%s\n",
- ldap_op == LDAP_MOD_ADD ? "add" : "modify",
- dn, ldap_err2string(rc),
- ld_error?ld_error:"unknown"));
- SAFE_FREE(ld_error);
-
- ldap_mods_free(mods, True);
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- DEBUG(2,("added: domain = %s in the LDAP database\n", domain_name));
- ldap_mods_free(mods, True);
- return NT_STATUS_OK;
-}
-
-/**********************************************************************
-Search for the domain info entry
-*********************************************************************/
-NTSTATUS smbldap_search_domain_info(struct smbldap_state *ldap_state,
- LDAPMessage ** result, const char *domain_name,
- BOOL try_add)
-{
- NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
- pstring filter;
- int rc;
- char **attr_list;
- int count;
-
- pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))",
- LDAP_OBJ_DOMINFO,
- get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
- domain_name);
-
- DEBUG(2, ("Searching for:[%s]\n", filter));
-
-
- attr_list = get_attr_list( dominfo_attr_list );
- rc = smbldap_search_suffix(ldap_state, filter, attr_list , result);
- free_attr_list( attr_list );
-
- if (rc != LDAP_SUCCESS) {
- DEBUG(2,("Problem during LDAPsearch: %s\n", ldap_err2string (rc)));
- DEBUG(2,("Query was: %s, %s\n", lp_ldap_suffix(), filter));
- } else if (ldap_count_entries(ldap_state->ldap_struct, *result) < 1) {
- DEBUG(3, ("Got no domain info entries for domain\n"));
- ldap_msgfree(*result);
- *result = NULL;
- if (try_add && NT_STATUS_IS_OK(ret = add_new_domain_info(ldap_state, domain_name))) {
- return smbldap_search_domain_info(ldap_state, result, domain_name, False);
- }
- else {
- DEBUG(0, ("Adding domain info for %s failed with %s\n",
- domain_name, nt_errstr(ret)));
- return ret;
- }
- } else if ((count = ldap_count_entries(ldap_state->ldap_struct, *result)) > 1) {
- DEBUG(0, ("Got too many (%d) domain info entries for domain %s\n",
- count, domain_name));
- ldap_msgfree(*result);
- *result = NULL;
- return ret;
- } else {
- return NT_STATUS_OK;
- }
-
- return ret;
-}
-
diff --git a/source/lib/smbpasswd.c b/source/lib/smbpasswd.c
new file mode 100644
index 00000000000..92ae1ffea26
--- /dev/null
+++ b/source/lib/smbpasswd.c
@@ -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;
+}
diff --git a/source/lib/smbrun.c b/source/lib/smbrun.c
index 592543bc43b..ab36ec6e40e 100644
--- a/source/lib/smbrun.c
+++ b/source/lib/smbrun.c
@@ -20,13 +20,17 @@
#include "includes.h"
-/* need to move this from here!! need some sleep ... */
-struct current_user current_user;
+#if 1
+int smbrun(char *cmd, int *outfd)
+{
+ DEBUG(0,("smbrun() needs a rewrite: struct current_user is gone!\n"));
+ return -1;
+}
+#else
/****************************************************************************
This is a utility function of smbrun().
****************************************************************************/
-
static int setup_out_fd(void)
{
int fd;
@@ -82,7 +86,7 @@ int smbrun(char *cmd, int *outfd)
CatchChildLeaveStatus();
- if ((pid=sys_fork()) < 0) {
+ if ((pid=fork()) < 0) {
DEBUG(0,("smbrun: fork failed with error %s\n", strerror(errno) ));
CatchChild();
if (outfd) {
@@ -163,18 +167,10 @@ int smbrun(char *cmd, int *outfd)
instead use exit codes for debugging */
}
-#ifndef __INSURE__
- /* close all other file descriptors, leaving only 0, 1 and 2. 0 and
- 2 point to /dev/null from the startup code */
- {
- int fd;
- for (fd=3;fd<256;fd++) close(fd);
- }
-#endif
-
execl("/bin/sh","sh","-c",cmd,NULL);
/* not reached */
exit(82);
return 1;
}
+#endif
diff --git a/source/lib/snprintf.c b/source/lib/snprintf.c
index 5b0cfa1ab33..fd31870162d 100644
--- a/source/lib/snprintf.c
+++ b/source/lib/snprintf.c
@@ -1,8 +1,4 @@
/*
- * NOTE: If you change this file, please merge it into rsync, samba, etc.
- */
-
-/*
* 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
@@ -57,57 +53,17 @@
* got rid of fcvt code (twas buggy and made testing harder)
* added C99 semantics
*
- * date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0
- * actually print args for %g and %e
- *
- * date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0
- * Since includes.h isn't included here, VA_COPY has to be defined here. I don't
- * see any include file that is guaranteed to be here, so I'm defining it
- * locally. Fixes AIX and Solaris builds.
- *
- * date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13
- * put the ifdef for HAVE_VA_COPY in one place rather than in lots of
- * functions
- *
- * date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4
- * Fix usage of va_list passed as an arg. Use __va_copy before using it
- * when it exists.
- *
- * date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14
- * Fix incorrect zpadlen handling in fmtfp.
- * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
- * few mods to make it easier to compile the tests.
- * addedd the "Ollie" test to the floating point ones.
- *
- * Martin Pool (mbp@samba.org) April 2003
- * Remove NO_CONFIG_H so that the test case can be built within a source
- * tree with less trouble.
- * Remove unnecessary SAFE_FREE() definition.
- *
- * Martin Pool (mbp@samba.org) May 2003
- * Put in a prototype for dummy_snprintf() to quiet compiler warnings.
- *
- * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
- * if the C library has some snprintf functions already.
**************************************************************/
-#ifndef NO_CONFIG_H
+#ifndef NO_CONFIG_H /* for some tests */
#include "config.h"
#else
#define NULL 0
-#endif
+#endif
#ifdef TEST_SNPRINTF /* need math library headers for testing */
-
-/* In test mode, we pretend that this system doesn't have any snprintf
- * functions, regardless of what config.h says. */
-# undef HAVE_SNPRINTF
-# undef HAVE_VSNPRINTF
-# undef HAVE_C99_VSNPRINTF
-# undef HAVE_ASPRINTF
-# undef HAVE_VASPRINTF
-# include <math.h>
-#endif /* TEST_SNPRINTF */
+#include <math.h>
+#endif
#ifdef HAVE_STRING_H
#include <string.h>
@@ -125,13 +81,21 @@
#include <stdlib.h>
#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
+
+
#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);
void dummy_snprintf(void) {}
-#endif /* HAVE_SNPRINTF, etc */
+#else
#ifdef HAVE_LONG_DOUBLE
#define LDOUBLE long double
@@ -145,17 +109,21 @@
#define LLONG long
#endif
-#ifndef VA_COPY
-#ifdef HAVE_VA_COPY
-#define VA_COPY(dest, src) va_copy(dest, src)
-#else
-#ifdef HAVE___VA_COPY
-#define VA_COPY(dest, src) __va_copy(dest, src)
-#else
-#define VA_COPY(dest, src) (dest) = (src)
-#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
+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
*/
@@ -190,19 +158,6 @@
#define MAX(p,q) (((p) >= (q)) ? (p) : (q))
#endif
-/* yes this really must be a ||. Don't muck with this (tridge) */
-#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
-
-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);
-
static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
{
char ch;
@@ -669,7 +624,7 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
int padlen = 0; /* amount to pad */
int zpadlen = 0;
int caps = 0;
- int idx;
+ int index;
double intpart;
double fracpart;
double temp;
@@ -728,11 +683,11 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
do {
temp = intpart*0.1;
my_modf(temp, &intpart);
- idx = (int) ((temp -intpart +0.05)* 10.0);
- /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
- /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
+ 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")[idx];
+ (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
} while (intpart && (iplace < 311));
if (iplace == 311) iplace--;
iconvert[iplace] = 0;
@@ -743,11 +698,11 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
do {
temp = fracpart*0.1;
my_modf(temp, &fracpart);
- idx = (int) ((temp -fracpart +0.05)* 10.0);
- /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
- /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
+ 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")[idx];
+ (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
} while(fracpart && (fplace < 311));
if (fplace == 311) fplace--;
}
@@ -817,20 +772,24 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char 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 with this (tridge)
+/* 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.
+ * 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_VSNPRINTF)
-int smb_snprintf(char *str,size_t count,const char *fmt,...)
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_SNPRINTF)
+ int snprintf(char *str,size_t count,const char *fmt,...)
{
size_t ret;
va_list ap;
@@ -908,9 +867,8 @@ int smb_snprintf(char *str,size_t count,const char *fmt,...)
"-16.16f",
NULL
};
- double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996,
- 0.9996, 1.996, 4.136, 5.030201, 0.00205,
- /* END LIST */ 0};
+ 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",
@@ -1018,4 +976,4 @@ int smb_snprintf(char *str,size_t count,const char *fmt,...)
return 0;
}
-#endif /* TEST_SNPRINTF */
+#endif /* SNPRINTF_TEST */
diff --git a/source/lib/sock_exec.c b/source/lib/sock_exec.c
deleted file mode 100644
index 52c5a8ce52c..00000000000
--- a/source/lib/sock_exec.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- 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"
-
-/*******************************************************************
-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];
-}
diff --git a/source/lib/substitute.c b/source/lib/substitute.c
index fed11c22982..4e4f0bc0400 100644
--- a/source/lib/substitute.c
+++ b/source/lib/substitute.c
@@ -21,575 +21,102 @@
#include "includes.h"
-fstring local_machine="";
-fstring remote_arch="UNKNOWN";
-userdom_struct current_user_info;
-fstring remote_proto="UNKNOWN";
+/* 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;
-static fstring remote_machine;
-static fstring smb_user_name;
-
-/**
- * Set the 'local' machine name
- * @param local_name the name we are being called
- * @param if this is the 'final' name for us, not be be changed again
- */
-
-void set_local_machine_name(const char* local_name, BOOL perm)
+void sub_set_context(struct substitute_context *subptr)
{
- static BOOL already_perm = False;
- fstring tmp_local_machine;
-
- /*
- * Windows NT/2k uses "*SMBSERVER" and XP uses "*SMBSERV"
- * arrggg!!!
- */
-
- if (strequal(local_name, "*SMBSERVER"))
- return;
-
- if (strequal(local_name, "*SMBSERV"))
- return;
-
- if (already_perm)
- return;
-
- already_perm = perm;
-
- fstrcpy(tmp_local_machine,local_name);
- trim_char(tmp_local_machine,' ',' ');
- alpha_strcpy(local_machine,tmp_local_machine,SAFE_NETBIOS_CHARS,sizeof(local_machine)-1);
- strlower_m(local_machine);
+ sub = subptr;
}
-/**
- * Set the 'remote' machine name
- * @param remote_name the name our client wants to be called by
- * @param if this is the 'final' name for them, not be be changed again
- */
-
-void set_remote_machine_name(const char* remote_name, BOOL perm)
+/*
+ setup a string in the negotiate structure, using alpha_strcpy with SAFE_NETBIOS_CHARS
+*/
+static void setup_string(char **dest, const char *str)
{
- static BOOL already_perm = False;
- fstring tmp_remote_machine;
+ char *s;
- if (already_perm)
+ s = strdup(str);
+ if (!s) {
return;
+ }
- already_perm = perm;
-
- fstrcpy(tmp_remote_machine,remote_name);
- trim_char(tmp_remote_machine,' ',' ');
- alpha_strcpy(remote_machine,tmp_remote_machine,SAFE_NETBIOS_CHARS,sizeof(remote_machine)-1);
- strlower_m(remote_machine);
-}
-
-const char* get_remote_machine_name(void)
-{
- return remote_machine;
-}
+ alpha_strcpy(s, str, SAFE_NETBIOS_CHARS, strlen(s)+1);
-const char* get_local_machine_name(void)
-{
- if (!*local_machine) {
- return global_myname();
- }
+ trim_string(s," "," ");
+ strlower(s);
- return local_machine;
+ SAFE_FREE(*dest);
+ (*dest) = s;
}
-/*******************************************************************
- Setup the string used by %U substitution.
-********************************************************************/
-
-void sub_set_smb_name(const char *name)
+void sub_set_local_machine(const char *local_machine)
{
- fstring tmp;
-
- /* don't let anonymous logins override the name */
- if (! *name)
- return;
-
- fstrcpy(tmp,name);
- trim_char(tmp,' ',' ');
- strlower_m(tmp);
- alpha_strcpy(smb_user_name,tmp,SAFE_NETBIOS_CHARS,sizeof(smb_user_name)-1);
+ if (!sub) return;
+ setup_string(&sub->local_machine, local_machine);
}
-char* sub_get_smb_name( void )
+void sub_set_remote_machine(const char *remote_machine)
{
- return smb_user_name;
+ if (!sub) return;
+ setup_string(&sub->remote_machine, remote_machine);
}
-/*******************************************************************
- Setup the strings used by substitutions. Called per packet. Ensure
- %U name is set correctly also.
-********************************************************************/
-
-void set_current_user_info(const userdom_struct *pcui)
+void sub_set_remote_proto(const char *str)
{
- current_user_info = *pcui;
- /* The following is safe as current_user_info.smb_name
- * has already been sanitised in register_vuid. */
- fstrcpy(smb_user_name, current_user_info.smb_name);
+ if (!sub) return;
+ setup_string(&sub->remote_proto, str);
}
-/*******************************************************************
- Given a pointer to a %$(NAME) expand it as an environment variable.
- Return the number of characters by which the pointer should be advanced.
- Based on code by Branko Cibej <branko.cibej@hermes.si>
- When this is called p points at the '%' character.
-********************************************************************/
-
-static size_t expand_env_var(char *p, int len)
+void sub_set_remote_arch(const char *str)
{
- fstring envname;
- char *envval;
- char *q, *r;
- int copylen;
-
- if (p[1] != '$')
- return 1;
-
- if (p[2] != '(')
- return 2;
-
- /*
- * Look for the terminating ')'.
- */
-
- if ((q = strchr_m(p,')')) == NULL) {
- DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p));
- return 2;
- }
-
- /*
- * Extract the name from within the %$(NAME) string.
- */
-
- r = p+3;
- copylen = MIN((q-r),(sizeof(envname)-1));
- strncpy(envname,r,copylen);
- envname[copylen] = '\0';
-
- if ((envval = getenv(envname)) == NULL) {
- DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname));
- return 2;
- }
-
- /*
- * Copy the full %$(NAME) into envname so it
- * can be replaced.
- */
-
- copylen = MIN((q+1-p),(sizeof(envname)-1));
- strncpy(envname,p,copylen);
- envname[copylen] = '\0';
- string_sub(p,envname,envval,len);
- return 0; /* Allow the environment contents to be parsed. */
+ if (!sub) return;
+ setup_string(&sub->remote_arch, str);
}
-/*******************************************************************
- Given a pointer to a %$(NAME) in p and the whole string in str
- expand it as an environment variable.
- Return a new allocated and expanded string.
- Based on code by Branko Cibej <branko.cibej@hermes.si>
- When this is called p points at the '%' character.
- May substitute multiple occurrencies of the same env var.
-********************************************************************/
-
-
-static char * realloc_expand_env_var(char *str, char *p)
+const char *sub_get_remote_machine(void)
{
- char *envname;
- char *envval;
- char *q, *r;
- int copylen;
-
- if (p[0] != '%' || p[1] != '$' || p[2] != '(')
- return str;
-
- /*
- * Look for the terminating ')'.
- */
-
- if ((q = strchr_m(p,')')) == NULL) {
- DEBUG(0,("expand_env_var: Unterminated environment variable [%s]\n", p));
- return str;
- }
-
- /*
- * Extract the name from within the %$(NAME) string.
- */
-
- r = p + 3;
- copylen = q - r;
- envname = (char *)malloc(copylen + 1 + 4); /* reserve space for use later add %$() chars */
- if (envname == NULL) return NULL;
- strncpy(envname,r,copylen);
- envname[copylen] = '\0';
-
- if ((envval = getenv(envname)) == NULL) {
- DEBUG(0,("expand_env_var: Environment variable [%s] not set\n", envname));
- SAFE_FREE(envname);
- return str;
- }
-
- /*
- * Copy the full %$(NAME) into envname so it
- * can be replaced.
- */
-
- copylen = q + 1 - p;
- strncpy(envname,p,copylen);
- envname[copylen] = '\0';
- r = realloc_string_sub(str, envname, envval);
- SAFE_FREE(envname);
- if (r == NULL) return NULL;
- return r;
+ if (!sub) return "UNKNOWN";
+ return sub->remote_machine;
}
-/*******************************************************************
- Patch from jkf@soton.ac.uk
- Added this to implement %p (NIS auto-map version of %H)
-*******************************************************************/
-
-static char *automount_path(const char *user_name)
+const char *sub_get_local_machine(void)
{
- static pstring server_path;
-
- /* use the passwd entry as the default */
- /* this will be the default if WITH_AUTOMOUNT is not used or fails */
-
- pstrcpy(server_path, get_user_home_dir(user_name));
-
-#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
-
- if (lp_nis_home_map()) {
- char *home_path_start;
- char *automount_value = automount_lookup(user_name);
-
- if(strlen(automount_value) > 0) {
- home_path_start = strchr_m(automount_value,':');
- if (home_path_start != NULL) {
- DEBUG(5, ("NIS lookup succeeded. Home path is: %s\n",
- home_path_start?(home_path_start+1):""));
- pstrcpy(server_path, home_path_start+1);
- }
- } else {
- /* NIS key lookup failed: default to user home directory from password file */
- DEBUG(5, ("NIS lookup failed. Using Home path from passwd file. Home path is: %s\n", server_path ));
- }
- }
-#endif
-
- DEBUG(4,("Home server path: %s\n", server_path));
-
- return server_path;
+ if (!sub) return "UNKNOWN";
+ return sub->local_machine;
}
-/*******************************************************************
- Patch from jkf@soton.ac.uk
- This is Luke's original function with the NIS lookup code
- moved out to a separate function.
-*******************************************************************/
-static const char *automount_server(const char *user_name)
+/*
+ setup the string used by %U substitution
+*/
+void sub_set_user_name(const char *name)
{
- static pstring server_name;
- const char *local_machine_name = get_local_machine_name();
-
- /* use the local machine name as the default */
- /* this will be the default if WITH_AUTOMOUNT is not used or fails */
- if (local_machine_name && *local_machine_name)
- pstrcpy(server_name, local_machine_name);
- else
- pstrcpy(server_name, global_myname());
-
-#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
-
- if (lp_nis_home_map()) {
- int home_server_len;
- char *automount_value = automount_lookup(user_name);
- home_server_len = strcspn(automount_value,":");
- DEBUG(5, ("NIS lookup succeeded. Home server length: %d\n",home_server_len));
- if (home_server_len > sizeof(pstring))
- home_server_len = sizeof(pstring);
- strncpy(server_name, automount_value, home_server_len);
- server_name[home_server_len] = '\0';
- }
-#endif
-
- DEBUG(4,("Home server: %s\n", server_name));
-
- return server_name;
+ if (!sub) return;
+ setup_string(&sub->user_name, name);
}
/****************************************************************************
- Do some standard substitutions in a string.
- len is the length in bytes of the space allowed in string str. If zero means
- don't allow expansions.
+FOO
****************************************************************************/
-
-void standard_sub_basic(const char *smb_name, char *str,size_t len)
-{
- char *p, *s;
- fstring pidstr;
- struct passwd *pass;
- const char *local_machine_name = get_local_machine_name();
-
- for (s=str; (p=strchr_m(s, '%'));s=p) {
- fstring tmp_str;
-
- int l = (int)len - (int)(p-str);
-
- if (l < 0)
- l = 0;
-
- switch (*(p+1)) {
- case 'U' :
- fstrcpy(tmp_str, smb_name);
- strlower_m(tmp_str);
- string_sub(p,"%U",tmp_str,l);
- break;
- case 'G' :
- fstrcpy(tmp_str, smb_name);
- if ((pass = Get_Pwnam(tmp_str))!=NULL) {
- string_sub(p,"%G",gidtoname(pass->pw_gid),l);
- } else {
- p += 2;
- }
- break;
- case 'D' :
- fstrcpy(tmp_str, current_user_info.domain);
- strupper_m(tmp_str);
- string_sub(p,"%D", tmp_str,l);
- break;
- case 'I' :
- string_sub(p,"%I", client_addr(),l);
- break;
- case 'i' :
- string_sub(p,"%i", client_socket_addr(),l);
- break;
- case 'L' :
- if (local_machine_name && *local_machine_name)
- string_sub(p,"%L", local_machine_name,l);
- else {
- pstring temp_name;
-
- pstrcpy(temp_name, global_myname());
- strlower_m(temp_name);
- string_sub(p,"%L", temp_name,l);
- }
- break;
- case 'M' :
- string_sub(p,"%M", client_name(),l);
- break;
- case 'R' :
- string_sub(p,"%R", remote_proto,l);
- break;
- case 'T' :
- string_sub(p,"%T", timestring(False),l);
- break;
- case 'a' :
- string_sub(p,"%a", remote_arch,l);
- break;
- case 'd' :
- slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)sys_getpid());
- string_sub(p,"%d", pidstr,l);
- break;
- case 'h' :
- string_sub(p,"%h", myhostname(),l);
- break;
- case 'm' :
- string_sub(p,"%m", get_remote_machine_name(),l);
- break;
- case 'v' :
- string_sub(p,"%v", SAMBA_VERSION_STRING,l);
- break;
- case '$' :
- p += expand_env_var(p,l);
- break; /* Expand environment variables */
- case '\0':
- p++;
- break; /* don't run off the end of the string */
-
- default: p+=2;
- break;
- }
- }
-}
-
-static void standard_sub_advanced(int snum, const char *user,
- const char *connectpath, gid_t gid,
- const char *smb_name, char *str, size_t len)
+void standard_sub_basic(char *str,size_t len)
{
- char *p, *s, *home;
-
- for (s=str; (p=strchr_m(s, '%'));s=p) {
- int l = (int)len - (int)(p-str);
-
- if (l < 0)
- l = 0;
-
- switch (*(p+1)) {
- case 'N' :
- string_sub(p,"%N", automount_server(user),l);
- break;
- case 'H':
- if ((home = get_user_home_dir(user)))
- string_sub(p,"%H",home, l);
- else
- p += 2;
- break;
- case 'P':
- string_sub(p,"%P", connectpath, l);
- break;
- case 'S':
- string_sub(p,"%S", lp_servicename(snum), l);
- break;
- case 'g':
- string_sub(p,"%g", gidtoname(gid), l);
- break;
- case 'u':
- string_sub(p,"%u", user, l);
- break;
-
- /* Patch from jkf@soton.ac.uk Left the %N (NIS
- * server name) in standard_sub_basic as it is
- * a feature for logon servers, hence uses the
- * username. The %p (NIS server path) code is
- * here as it is used instead of the default
- * "path =" string in [homes] and so needs the
- * service name, not the username. */
- case 'p':
- string_sub(p,"%p", automount_path(lp_servicename(snum)), l);
- break;
- case '\0':
- p++;
- break; /* don't run off the end of the string */
-
- default: p+=2;
- break;
- }
- }
-
- standard_sub_basic(smb_name, str, 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)
{
- char *a, *t;
- a = alloc_sub_basic(smb_name, str);
- if (!a) return NULL;
- t = talloc_strdup(mem_ctx, a);
- SAFE_FREE(a);
- return t;
+ return talloc_strdup(mem_ctx, str);
}
char *alloc_sub_basic(const char *smb_name, const char *str)
{
- char *b, *p, *s, *t, *r, *a_string;
- fstring pidstr;
- struct passwd *pass;
- const char *local_machine_name = get_local_machine_name();
-
- /* workaround to prevent a crash while lookinf at bug #687 */
-
- if ( !str ) {
- DEBUG(0,("alloc_sub_basic: NULL source string! This should not happen\n"));
- return NULL;
- }
-
- a_string = strdup(str);
- if (a_string == NULL) {
- DEBUG(0, ("alloc_sub_specified: Out of memory!\n"));
- return NULL;
- }
-
- for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
-
- r = NULL;
- b = t = a_string;
-
- switch (*(p+1)) {
- case 'U' :
- r = strdup_lower(smb_name);
- if (r == NULL) goto error;
- t = realloc_string_sub(t, "%U", r);
- break;
- case 'G' :
- r = strdup(smb_name);
- if (r == NULL) goto error;
- if ((pass = Get_Pwnam(r))!=NULL) {
- t = realloc_string_sub(t, "%G", gidtoname(pass->pw_gid));
- }
- break;
- case 'D' :
- r = strdup_upper(current_user_info.domain);
- if (r == NULL) goto error;
- t = realloc_string_sub(t, "%D", r);
- break;
- case 'I' :
- t = realloc_string_sub(t, "%I", client_addr());
- break;
- case 'L' :
- if (local_machine_name && *local_machine_name)
- t = realloc_string_sub(t, "%L", local_machine_name);
- else
- t = realloc_string_sub(t, "%L", global_myname());
- break;
- case 'N':
- t = realloc_string_sub(t, "%N", automount_server(smb_name));
- break;
- case 'M' :
- t = realloc_string_sub(t, "%M", client_name());
- break;
- case 'R' :
- t = realloc_string_sub(t, "%R", remote_proto);
- break;
- case 'T' :
- t = realloc_string_sub(t, "%T", timestring(False));
- break;
- case 'a' :
- t = realloc_string_sub(t, "%a", remote_arch);
- break;
- case 'd' :
- slprintf(pidstr,sizeof(pidstr)-1, "%d",(int)sys_getpid());
- t = realloc_string_sub(t, "%d", pidstr);
- break;
- case 'h' :
- t = realloc_string_sub(t, "%h", myhostname());
- break;
- case 'm' :
- t = realloc_string_sub(t, "%m", remote_machine);
- break;
- case 'v' :
- t = realloc_string_sub(t, "%v", SAMBA_VERSION_STRING);
- break;
- case '$' :
- t = realloc_expand_env_var(t, p); /* Expand environment variables */
- break;
-
- default:
- break;
- }
-
- p++;
- SAFE_FREE(r);
- if (t == NULL) goto error;
- a_string = t;
- }
-
- return a_string;
-error:
- SAFE_FREE(a_string);
- return NULL;
+ return strdup(str);
}
/****************************************************************************
@@ -604,12 +131,7 @@ char *talloc_sub_specified(TALLOC_CTX *mem_ctx,
uid_t uid,
gid_t gid)
{
- char *a, *t;
- a = alloc_sub_specified(input_string, username, domain, uid, gid);
- if (!a) return NULL;
- t = talloc_strdup(mem_ctx, a);
- SAFE_FREE(a);
- return t;
+ return talloc_strdup(mem_ctx, input_string);
}
char *alloc_sub_specified(const char *input_string,
@@ -618,61 +140,7 @@ char *alloc_sub_specified(const char *input_string,
uid_t uid,
gid_t gid)
{
- char *a_string, *ret_string;
- char *b, *p, *s, *t;
-
- a_string = strdup(input_string);
- if (a_string == NULL) {
- DEBUG(0, ("alloc_sub_specified: Out of memory!\n"));
- return NULL;
- }
-
- for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
-
- b = t = a_string;
-
- switch (*(p+1)) {
- case 'U' :
- t = realloc_string_sub(t, "%U", username);
- break;
- case 'u' :
- t = realloc_string_sub(t, "%u", username);
- break;
- case 'G' :
- if (gid != -1) {
- t = realloc_string_sub(t, "%G", gidtoname(gid));
- } else {
- t = realloc_string_sub(t, "%G", "NO_GROUP");
- }
- break;
- case 'g' :
- if (gid != -1) {
- t = realloc_string_sub(t, "%g", gidtoname(gid));
- } else {
- t = realloc_string_sub(t, "%g", "NO_GROUP");
- }
- break;
- case 'D' :
- t = realloc_string_sub(t, "%D", domain);
- break;
- case 'N' :
- t = realloc_string_sub(t, "%N", automount_server(username));
- break;
- default:
- break;
- }
-
- p++;
- if (t == NULL) {
- SAFE_FREE(a_string);
- return NULL;
- }
- a_string = t;
- }
-
- ret_string = alloc_sub_basic(username, a_string);
- SAFE_FREE(a_string);
- return ret_string;
+ return strdup(input_string);
}
char *talloc_sub_advanced(TALLOC_CTX *mem_ctx,
@@ -681,103 +149,34 @@ char *talloc_sub_advanced(TALLOC_CTX *mem_ctx,
const char *connectpath,
gid_t gid,
const char *smb_name,
- const char *str)
+ char *str)
{
- char *a, *t;
- a = alloc_sub_advanced(snum, user, connectpath, gid, smb_name, str);
- if (!a) return NULL;
- t = talloc_strdup(mem_ctx, a);
- SAFE_FREE(a);
- return t;
+ 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, const char *str)
+ const char *smb_name, char *str)
{
- char *a_string, *ret_string;
- char *b, *p, *s, *t, *h;
-
- a_string = strdup(str);
- if (a_string == NULL) {
- DEBUG(0, ("alloc_sub_specified: Out of memory!\n"));
- return NULL;
- }
-
- for (b = s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
-
- b = t = a_string;
-
- switch (*(p+1)) {
- case 'N' :
- t = realloc_string_sub(t, "%N", automount_server(user));
- break;
- case 'H':
- if ((h = get_user_home_dir(user)))
- t = realloc_string_sub(t, "%H", h);
- break;
- case 'P':
- t = realloc_string_sub(t, "%P", connectpath);
- break;
- case 'S':
- t = realloc_string_sub(t, "%S", lp_servicename(snum));
- break;
- case 'g':
- t = realloc_string_sub(t, "%g", gidtoname(gid));
- break;
- case 'u':
- t = realloc_string_sub(t, "%u", user);
- break;
-
- /* Patch from jkf@soton.ac.uk Left the %N (NIS
- * server name) in standard_sub_basic as it is
- * a feature for logon servers, hence uses the
- * username. The %p (NIS server path) code is
- * here as it is used instead of the default
- * "path =" string in [homes] and so needs the
- * service name, not the username. */
- case 'p':
- t = realloc_string_sub(t, "%p", automount_path(lp_servicename(snum)));
- break;
-
- default:
- break;
- }
-
- p++;
- if (t == NULL) {
- SAFE_FREE(a_string);
- return NULL;
- }
- a_string = t;
- }
-
- ret_string = alloc_sub_basic(smb_name, a_string);
- SAFE_FREE(a_string);
- return ret_string;
+ return strdup(str);
}
/****************************************************************************
Do some standard substitutions in a string.
****************************************************************************/
-void standard_sub_conn(connection_struct *conn, char *str, size_t len)
+void standard_sub_conn(struct tcon_context *conn, char *str, size_t len)
{
- standard_sub_advanced(SNUM(conn), conn->user, conn->connectpath,
- conn->gid, smb_user_name, str, len);
}
-char *talloc_sub_conn(TALLOC_CTX *mem_ctx, connection_struct *conn, const char *str)
+char *talloc_sub_conn(TALLOC_CTX *mem_ctx, struct tcon_context *conn, char *str)
{
- return talloc_sub_advanced(mem_ctx, SNUM(conn), conn->user,
- conn->connectpath, conn->gid,
- smb_user_name, str);
+ return talloc_strdup(mem_ctx, str);
}
-char *alloc_sub_conn(connection_struct *conn, const char *str)
+char *alloc_sub_conn(struct tcon_context *conn, char *str)
{
- return alloc_sub_advanced(SNUM(conn), conn->user, conn->connectpath,
- conn->gid, smb_user_name, str);
+ return strdup(str);
}
/****************************************************************************
@@ -786,17 +185,4 @@ char *alloc_sub_conn(connection_struct *conn, const char *str)
void standard_sub_snum(int snum, char *str, size_t len)
{
- extern struct current_user current_user;
- static uid_t cached_uid = -1;
- static fstring cached_user;
- /* calling uidtoname() on every substitute would be too expensive, so
- we cache the result here as nearly every call is for the same uid */
-
- if (cached_uid != current_user.uid) {
- fstrcpy(cached_user, uidtoname(current_user.uid));
- cached_uid = current_user.uid;
- }
-
- standard_sub_advanced(snum, cached_user, "", -1,
- smb_user_name, str, len);
}
diff --git a/source/lib/sysacls.c b/source/lib/sysacls.c
index 00d06e4a5ae..fe85b9e72f4 100644
--- a/source/lib/sysacls.c
+++ b/source/lib/sysacls.c
@@ -1005,10 +1005,10 @@ static BOOL hpux_acl_call_presence(void)
shl_t handle = NULL;
void *value;
int ret_val=0;
- static BOOL already_checked=0;
-
- if(already_checked)
- return True;
+ //static BOOL already_checked=0;
+ // REWRITE: add this back in??
+ //if(already_checked)
+ // return True;
ret_val = shl_findsym(&handle, "acl", TYPE_PROCEDURE, &value);
diff --git a/source/lib/sysquotas.c b/source/lib/sysquotas.c
deleted file mode 100644
index 1c5c7e8bd4f..00000000000
--- a/source/lib/sysquotas.c
+++ /dev/null
@@ -1,505 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
- System QUOTA function wrappers
- Copyright (C) Stefan (metze) Metzmacher 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"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_QUOTA
-
-#ifdef HAVE_SYS_QUOTAS
-
-#if defined(HAVE_QUOTACTL_4A)
-
-/*#endif HAVE_QUOTACTL_4A */
-#elif defined(HAVE_QUOTACTL_4B)
-
-#error HAVE_QUOTACTL_4B not implemeted
-
-/*#endif HAVE_QUOTACTL_4B */
-#elif defined(HAVE_QUOTACTL_3)
-
-#error HAVE_QUOTACTL_3 not implemented
-
-/* #endif HAVE_QUOTACTL_3 */
-#else /* NO_QUOTACTL_USED */
-
-#endif /* NO_QUOTACTL_USED */
-
-#ifdef HAVE_MNTENT
-static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
-{
- int ret = -1;
- SMB_STRUCT_STAT S;
- FILE *fp;
- struct mntent *mnt;
- SMB_DEV_T devno;
-
- /* find the block device file */
-
- if (!path||!mntpath||!bdev||!fs)
- smb_panic("sys_path_to_bdev: called with NULL pointer");
-
- (*mntpath) = NULL;
- (*bdev) = NULL;
- (*fs) = NULL;
-
- if ( sys_stat(path, &S) == -1 )
- return (-1);
-
- devno = S.st_dev ;
-
- fp = setmntent(MOUNTED,"r");
-
- while ((mnt = getmntent(fp))) {
- if ( sys_stat(mnt->mnt_dir,&S) == -1 )
- continue ;
-
- if (S.st_dev == devno) {
- (*mntpath) = strdup(mnt->mnt_dir);
- (*bdev) = strdup(mnt->mnt_fsname);
- (*fs) = strdup(mnt->mnt_type);
- if ((*mntpath)&&(*bdev)&&(*fs)) {
- ret = 0;
- } else {
- SAFE_FREE(*mntpath);
- SAFE_FREE(*bdev);
- SAFE_FREE(*fs);
- ret = -1;
- }
-
- break;
- }
- }
-
- endmntent(fp) ;
-
- return ret;
-}
-/* #endif HAVE_MNTENT */
-#elif defined(HAVE_DEVNM)
-
-/* we have this on HPUX, ... */
-static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
-{
- int ret = -1;
- char dev_disk[256];
- SMB_STRUCT_STAT S;
-
- if (!path||!mntpath||!bdev||!fs)
- smb_panic("sys_path_to_bdev: called with NULL pointer");
-
- (*mntpath) = NULL;
- (*bdev) = NULL;
- (*fs) = NULL;
-
- /* find the block device file */
-
- if ((ret=sys_stat(path, &S))!=0) {
- return ret;
- }
-
- if ((ret=devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1))!=0) {
- return ret;
- }
-
- /* we should get the mntpath right...
- * but I don't know how
- * --metze
- */
- (*mntpath) = strdup(path);
- (*bdev) = strdup(dev_disk);
- if ((*mntpath)&&(*bdev)) {
- ret = 0;
- } else {
- SAFE_FREE(*mntpath);
- SAFE_FREE(*bdev);
- ret = -1;
- }
-
-
- return ret;
-}
-
-/* #endif HAVE_DEVNM */
-#else
-/* we should fake this up...*/
-static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
-{
- int ret = -1;
-
- if (!path||!mntpath||!bdev||!fs)
- smb_panic("sys_path_to_bdev: called with NULL pointer");
-
- (*mntpath) = NULL;
- (*bdev) = NULL;
- (*fs) = NULL;
-
- (*mntpath) = strdup(path);
- if (*mntpath) {
- ret = 0;
- } else {
- SAFE_FREE(*mntpath);
- ret = -1;
- }
-
- return ret;
-}
-#endif
-
-/*********************************************************************
- Now the list of all filesystem specific quota systems we have found
-**********************************************************************/
-static struct {
- const char *name;
- int (*get_quota)(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
- int (*set_quota)(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
-} sys_quota_backends[] = {
-#ifdef HAVE_XFS_QUOTAS
- {"xfs", sys_get_xfs_quota, sys_set_xfs_quota},
-#endif /* HAVE_XFS_QUOTAS */
- {NULL, NULL, NULL}
-};
-
-static int command_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
-{
- const char *get_quota_command;
-
- get_quota_command = lp_get_quota_command();
- if (get_quota_command && *get_quota_command) {
- const char *p;
- char *p2;
- char **lines;
- pstring syscmd;
- int _id = -1;
-
- switch(qtype) {
- case SMB_USER_QUOTA_TYPE:
- case SMB_USER_FS_QUOTA_TYPE:
- _id = id.uid;
- break;
- case SMB_GROUP_QUOTA_TYPE:
- case SMB_GROUP_FS_QUOTA_TYPE:
- _id = id.gid;
- break;
- default:
- DEBUG(0,("invalid quota type.\n"));
- return -1;
- }
-
- slprintf(syscmd, sizeof(syscmd)-1,
- "%s \"%s\" %d %d",
- get_quota_command, path, qtype, _id);
-
- DEBUG (3, ("get_quota: Running command %s\n", syscmd));
-
- lines = file_lines_pload(syscmd, NULL);
- if (lines) {
- char *line = lines[0];
-
- DEBUG (3, ("Read output from get_quota, \"%s\"\n", line));
-
- /* we need to deal with long long unsigned here, if supported */
-
- dp->qflags = (enum SMB_QUOTA_TYPE)strtoul(line, &p2, 10);
- p = p2;
- while (p && *p && isspace(*p))
- p++;
- if (p && *p)
- dp->curblocks = STR_TO_SMB_BIG_UINT(p, &p);
- else
- goto invalid_param;
- while (p && *p && isspace(*p))
- p++;
- if (p && *p)
- dp->softlimit = STR_TO_SMB_BIG_UINT(p, &p);
- else
- goto invalid_param;
- while (p && *p && isspace(*p))
- p++;
- if (p && *p)
- dp->hardlimit = STR_TO_SMB_BIG_UINT(p, &p);
- else
- goto invalid_param;
- while (p && *p && isspace(*p))
- p++;
- if (p && *p)
- dp->curinodes = STR_TO_SMB_BIG_UINT(p, &p);
- else
- goto invalid_param;
- while (p && *p && isspace(*p))
- p++;
- if (p && *p)
- dp->isoftlimit = STR_TO_SMB_BIG_UINT(p, &p);
- else
- goto invalid_param;
- while (p && *p && isspace(*p))
- p++;
- if (p && *p)
- dp->ihardlimit = STR_TO_SMB_BIG_UINT(p, &p);
- else
- goto invalid_param;
- while (p && *p && isspace(*p))
- p++;
- if (p && *p)
- dp->bsize = STR_TO_SMB_BIG_UINT(p, NULL);
- else
- dp->bsize = 1024;
- file_lines_free(lines);
- DEBUG (3, ("Parsed output of get_quota, ...\n"));
-
-#ifdef LARGE_SMB_OFF_T
- DEBUGADD (5,(
- "qflags:%u curblocks:%llu softlimit:%llu hardlimit:%llu\n"
- "curinodes:%llu isoftlimit:%llu ihardlimit:%llu bsize:%llu\n",
- dp->qflags,(long long unsigned)dp->curblocks,
- (long long unsigned)dp->softlimit,(long long unsigned)dp->hardlimit,
- (long long unsigned)dp->curinodes,
- (long long unsigned)dp->isoftlimit,(long long unsigned)dp->ihardlimit,
- (long long unsigned)dp->bsize));
-#else /* LARGE_SMB_OFF_T */
- DEBUGADD (5,(
- "qflags:%u curblocks:%lu softlimit:%lu hardlimit:%lu\n"
- "curinodes:%lu isoftlimit:%lu ihardlimit:%lu bsize:%lu\n",
- dp->qflags,(long unsigned)dp->curblocks,
- (long unsigned)dp->softlimit,(long unsigned)dp->hardlimit,
- (long unsigned)dp->curinodes,
- (long unsigned)dp->isoftlimit,(long unsigned)dp->ihardlimit,
- (long unsigned)dp->bsize));
-#endif /* LARGE_SMB_OFF_T */
- return 0;
- }
-
- DEBUG (0, ("get_quota_command failed!\n"));
- return -1;
- }
-
- errno = ENOSYS;
- return -1;
-
-invalid_param:
- DEBUG(0,("The output of get_quota_command is invalid!\n"));
- return -1;
-}
-
-static int command_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
-{
- const char *set_quota_command;
-
- set_quota_command = lp_set_quota_command();
- if (set_quota_command && *set_quota_command) {
- char **lines;
- pstring syscmd;
- int _id = -1;
-
- switch(qtype) {
- case SMB_USER_QUOTA_TYPE:
- case SMB_USER_FS_QUOTA_TYPE:
- _id = id.uid;
- break;
- case SMB_GROUP_QUOTA_TYPE:
- case SMB_GROUP_FS_QUOTA_TYPE:
- _id = id.gid;
- break;
- default:
- return -1;
- }
-
-#ifdef LARGE_SMB_OFF_T
- slprintf(syscmd, sizeof(syscmd)-1,
- "%s \"%s\" %d %d "
- "%u %llu %llu "
- "%llu %llu %llu ",
- set_quota_command, path, qtype, _id, dp->qflags,
- (long long unsigned)dp->softlimit,(long long unsigned)dp->hardlimit,
- (long long unsigned)dp->isoftlimit,(long long unsigned)dp->ihardlimit,
- (long long unsigned)dp->bsize);
-#else /* LARGE_SMB_OFF_T */
- slprintf(syscmd, sizeof(syscmd)-1,
- "%s \"%s\" %d %d "
- "%u %lu %lu "
- "%lu %lu %lu ",
- set_quota_command, path, qtype, _id, dp->qflags,
- (long unsigned)dp->softlimit,(long unsigned)dp->hardlimit,
- (long unsigned)dp->isoftlimit,(long unsigned)dp->ihardlimit,
- (long unsigned)dp->bsize);
-#endif /* LARGE_SMB_OFF_T */
-
-
-
- DEBUG (3, ("get_quota: Running command %s\n", syscmd));
-
- lines = file_lines_pload(syscmd, NULL);
- if (lines) {
- char *line = lines[0];
-
- DEBUG (3, ("Read output from set_quota, \"%s\"\n", line));
-
- file_lines_free(lines);
-
- return 0;
- }
- DEBUG (0, ("set_quota_command failed!\n"));
- return -1;
- }
-
- errno = ENOSYS;
- return -1;
-}
-
-int sys_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
-{
- int ret = -1;
- int i;
- BOOL ready = False;
- char *mntpath = NULL;
- char *bdev = NULL;
- char *fs = NULL;
-
- if (!path||!dp)
- smb_panic("sys_get_quota: called with NULL pointer");
-
- if (command_get_quota(path, qtype, id, dp)==0) {
- return 0;
- } else if (errno != ENOSYS) {
- return -1;
- }
-
- if ((ret=sys_path_to_bdev(path,&mntpath,&bdev,&fs))!=0) {
- DEBUG(0,("sys_path_to_bdev() failed for path [%s]!\n",path));
- return ret;
- }
-
- errno = 0;
- DEBUG(10,("sys_get_quota() uid(%u, %u)\n", (unsigned)getuid(), (unsigned)geteuid()));
-
- for (i=0;(fs && sys_quota_backends[i].name && sys_quota_backends[i].get_quota);i++) {
- if (strcmp(fs,sys_quota_backends[i].name)==0) {
- ret = sys_quota_backends[i].get_quota(mntpath, bdev, qtype, id, dp);
- if (ret!=0) {
- DEBUG(3,("sys_get_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
- fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
- } else {
- DEBUG(10,("sys_get_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
- fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
- }
- ready = True;
- break;
- }
- }
-
- if (!ready) {
- /* use the default vfs quota functions */
- ret=sys_get_vfs_quota(mntpath, bdev, qtype, id, dp);
- if (ret!=0) {
- DEBUG(3,("sys_get_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s\n",
- "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
- } else {
- DEBUG(10,("sys_get_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
- "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
- }
- }
-
- SAFE_FREE(mntpath);
- SAFE_FREE(bdev);
- SAFE_FREE(fs);
-
- if ((ret!=0)&& (errno == EDQUOT)) {
- DEBUG(10,("sys_get_quota() warning over quota!\n"));
- return 0;
- }
-
- return ret;
-}
-
-int sys_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
-{
- int ret = -1;
- int i;
- BOOL ready = False;
- char *mntpath = NULL;
- char *bdev = NULL;
- char *fs = NULL;
-
- /* find the block device file */
-
- if (!path||!dp)
- smb_panic("get_smb_quota: called with NULL pointer");
-
- if (command_set_quota(path, qtype, id, dp)==0) {
- return 0;
- } else if (errno != ENOSYS) {
- return -1;
- }
-
- if ((ret=sys_path_to_bdev(path,&mntpath,&bdev,&fs))!=0) {
- DEBUG(0,("sys_path_to_bdev() failed for path [%s]!\n",path));
- return ret;
- }
-
- errno = 0;
- DEBUG(10,("sys_set_quota() uid(%u, %u)\n", (unsigned)getuid(), (unsigned)geteuid()));
-
- for (i=0;(fs && sys_quota_backends[i].name && sys_quota_backends[i].set_quota);i++) {
- if (strcmp(fs,sys_quota_backends[i].name)==0) {
- ret = sys_quota_backends[i].set_quota(mntpath, bdev, qtype, id, dp);
- if (ret!=0) {
- DEBUG(3,("sys_set_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
- fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
- } else {
- DEBUG(10,("sys_set_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
- fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
- }
- ready = True;
- break;
- }
- }
-
- if (!ready) {
- /* use the default vfs quota functions */
- ret=sys_set_vfs_quota(mntpath, bdev, qtype, id, dp);
- if (ret!=0) {
- DEBUG(3,("sys_set_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
- "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
- } else {
- DEBUG(10,("sys_set_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
- "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
- }
- }
-
- SAFE_FREE(mntpath);
- SAFE_FREE(bdev);
- SAFE_FREE(fs);
-
- if ((ret!=0)&& (errno == EDQUOT)) {
- DEBUG(10,("sys_set_quota() warning over quota!\n"));
- return 0;
- }
-
- return ret;
-}
-
-#else /* HAVE_SYS_QUOTAS */
- void dummy_sysquotas_c(void)
-{
- return;
-}
-#endif /* HAVE_SYS_QUOTAS */
-
diff --git a/source/lib/sysquotas_4A.c b/source/lib/sysquotas_4A.c
deleted file mode 100644
index ffb4123799d..00000000000
--- a/source/lib/sysquotas_4A.c
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
- System QUOTA function wrappers for QUOTACTL_4A
- Copyright (C) Stefan (metze) Metzmacher 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"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_QUOTA
-
-#ifdef HAVE_QUOTACTL_4A
-/* long quotactl(int cmd, char *special, qid_t id, caddr_t addr) */
-/* this is used by: HPUX,IRIX */
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#ifdef HAVE_ASM_TYPES_H
-#include <asm/types.h>
-#endif
-
-#ifdef HAVE_SYS_QUOTA_H
-#include <sys/quota.h>
-#endif
-
-#ifndef Q_SETQLIM
-#define Q_SETQLIM Q_SETQUOTA
-#endif
-
-#ifndef QCMD
-#define QCMD(x,y) x
-#endif
-
-#ifndef QCMD
-#define QCMD(x,y) x
-#endif
-
-#ifdef GRPQUOTA
-#define HAVE_GROUP_QUOTA
-#endif
-
-#ifndef QUOTABLOCK_SIZE
-#define QUOTABLOCK_SIZE DEV_BSIZE
-#endif
-
-#ifdef HAVE_DQB_FSOFTLIMIT
-#define dqb_isoftlimit dqb_fsoftlimit
-#define dqb_ihardlimit dqb_fhardlimit
-#define dqb_curinodes dqb_curfiles
-#endif
-
-#ifdef INITQFNAMES
-#define USERQUOTAFILE_EXTENSION ".user"
-#else
-#define USERQUOTAFILE_EXTENSION ""
-#endif
-
-#if !defined(QUOTAFILENAME) && defined(QFILENAME)
-#define QUOTAFILENAME QFILENAME
-#endif
-
-/****************************************************************************
- Abstract out the quotactl_4A get calls.
-****************************************************************************/
-int sys_get_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
-{
- int ret = -1;
- uint32 qflags = 0;
- struct dqblk D;
- SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
-
- ZERO_STRUCT(D);
- ZERO_STRUCT(*dp);
- dp->qtype = qtype;
-
- switch (qtype) {
- case SMB_USER_QUOTA_TYPE:
- DEBUG(10,("sys_get_vfs_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
- path, bdev, (unsigned)id.uid));
-
- if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (void *)&D))&&errno != EDQUOT) {
- return ret;
- }
-
- if ((D.dqb_curblocks==0)&&
- (D.dqb_bsoftlimit==0)&&
- (D.dqb_bhardlimit==0)) {
- /* the upper layer functions don't want empty quota records...*/
- return -1;
- }
-
- break;
-#ifdef HAVE_GROUP_QUOTA
- case SMB_GROUP_QUOTA_TYPE:
- DEBUG(10,("sys_get_vfs_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
- path, bdev, (unsigned)id.gid));
-
- if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (void *)&D))&&errno != EDQUOT) {
- return ret;
- }
-
- if ((D.dqb_curblocks==0)&&
- (D.dqb_bsoftlimit==0)&&
- (D.dqb_bhardlimit==0)) {
- /* the upper layer functions don't want empty quota records...*/
- return -1;
- }
-
- break;
-#endif /* HAVE_GROUP_QUOTA */
- case SMB_USER_FS_QUOTA_TYPE:
- id.uid = getuid();
-
- DEBUG(10,("sys_get_vfs_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
- path, bdev, (unsigned)id.uid));
-
- if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (void *)&D))==0) {
- qflags |= QUOTAS_DENY_DISK;
- }
-
- ret = 0;
- break;
-#ifdef HAVE_GROUP_QUOTA
- case SMB_GROUP_FS_QUOTA_TYPE:
- id.gid = getgid();
-
- DEBUG(10,("sys_get_vfs_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
- path, bdev, (unsigned)id.gid));
-
- if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (void *)&D))==0) {
- qflags |= QUOTAS_DENY_DISK;
- }
-
- ret = 0;
- break;
-#endif /* HAVE_GROUP_QUOTA */
- default:
- errno = ENOSYS;
- return -1;
- }
-
- dp->bsize = bsize;
- dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
- dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
- dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
- dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
- dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
- dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
-
-
- dp->qflags = qflags;
-
- return ret;
-}
-
-/****************************************************************************
- Abstract out the quotactl_4A set calls.
-****************************************************************************/
-int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
-{
- int ret = -1;
- uint32 qflags = 0;
- uint32 oldqflags = 0;
- struct dqblk D;
- SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
-
- ZERO_STRUCT(D);
-
- if (bsize == dp->bsize) {
- D.dqb_bsoftlimit = dp->softlimit;
- D.dqb_bhardlimit = dp->hardlimit;
- D.dqb_ihardlimit = dp->ihardlimit;
- D.dqb_isoftlimit = dp->isoftlimit;
- } else {
- D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize;
- D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize;
- D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize;
- D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize;
- }
-
- qflags = dp->qflags;
-
- switch (qtype) {
- case SMB_USER_QUOTA_TYPE:
- DEBUG(10,("sys_set_vfs_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
- path, bdev, (unsigned)id.uid));
-
- ret = quotactl(QCMD(Q_SETQLIM,USRQUOTA), bdev, id.uid, (void *)&D);
- break;
-#ifdef HAVE_GROUP_QUOTA
- case SMB_GROUP_QUOTA_TYPE:
- DEBUG(10,("sys_set_vfs_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
- path, bdev, (unsigned)id.gid));
-
- ret = quotactl(QCMD(Q_SETQLIM,GRPQUOTA), bdev, id.gid, (void *)&D);
- break;
-#endif /* HAVE_GROUP_QUOTA */
- case SMB_USER_FS_QUOTA_TYPE:
- /* this stuff didn't work as it should:
- * switching on/off quota via quotactl()
- * didn't work!
- * So we just return 0
- * --metze
- *
- * On HPUX we didn't have the mount path,
- * we need to fix sys_path_to_bdev()
- *
- */
- id.uid = getuid();
- DEBUG(10,("sys_set_vfs_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
- path, bdev, (unsigned)id.uid));
-
-#if 0
- ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (void *)&D);
-
- if ((qflags&QUOTAS_DENY_DISK)||(qflags&QUOTAS_ENABLED)) {
- if (ret == 0) {
- char *quota_file = NULL;
-
- asprintf(&quota_file,"/%s/%s%s",path, QUOTAFILENAME,USERQUOTAFILE_EXTENSION);
- if (quota_file == NULL) {
- DEBUG(0,("asprintf() failed!\n"));
- errno = ENOMEM;
- return -1;
- }
-
- ret = quotactl(QCMD(Q_QUOTAON,USRQUOTA), bdev, -1,(void *)quota_file);
- } else {
- ret = 0;
- }
- } else {
- if (ret != 0) {
- /* turn off */
- ret = quotactl(QCMD(Q_QUOTAOFF,USRQUOTA), bdev, -1, (void *)0);
- } else {
- ret = 0;
- }
- }
-
- DEBUG(0,("sys_set_vfs_quota: ret(%d) errno(%d)[%s] uid(%d) bdev[%s]\n",
- ret,errno,strerror(errno),id.uid,bdev));
-#else
- if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (void *)&D))==0) {
- oldqflags |= QUOTAS_DENY_DISK;
- }
-
- if (oldqflags == qflags) {
- ret = 0;
- } else {
- ret = -1;
- }
-#endif
- break;
-#ifdef HAVE_GROUP_QUOTA
- case SMB_GROUP_FS_QUOTA_TYPE:
- /* this stuff didn't work as it should:
- * switching on/off quota via quotactl()
- * didn't work!
- * So we just return 0
- * --metze
- *
- * On HPUX we didn't have the mount path,
- * we need to fix sys_path_to_bdev()
- *
- */
- id.gid = getgid();
- DEBUG(10,("sys_set_vfs_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
- path, bdev, (unsigned)id.gid));
-
-#if 0
- ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id, (void *)&D);
-
- if ((qflags&QUOTAS_DENY_DISK)||(qflags&QUOTAS_ENABLED)) {
- if (ret == 0) {
- char *quota_file = NULL;
-
- asprintf(&quota_file,"/%s/%s%s",path, QUOTAFILENAME,GROUPQUOTAFILE_EXTENSION);
- if (quota_file == NULL) {
- DEBUG(0,("asprintf() failed!\n"));
- errno = ENOMEM;
- return -1;
- }
-
- ret = quotactl(QCMD(Q_QUOTAON,GRPQUOTA), bdev, -1,(void *)quota_file);
- } else {
- ret = 0;
- }
- } else {
- if (ret != 0) {
- /* turn off */
- ret = quotactl(QCMD(Q_QUOTAOFF,GRPQUOTA), bdev, -1, (void *)0);
- } else {
- ret = 0;
- }
- }
-
- DEBUG(0,("sys_set_vfs_quota: ret(%d) errno(%d)[%s] uid(%d) bdev[%s]\n",
- ret,errno,strerror(errno),id.gid,bdev));
-#else
- if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (void *)&D))==0) {
- oldqflags |= QUOTAS_DENY_DISK;
- }
-
- if (oldqflags == qflags) {
- ret = 0;
- } else {
- ret = -1;
- }
-#endif
- break;
-#endif /* HAVE_GROUP_QUOTA */
- default:
- errno = ENOSYS;
- return -1;
- }
-
- return ret;
-}
-
-#else /* HAVE_QUOTACTL_4A */
- void dummy_sysquotas_4A(void){}
-#endif /* HAVE_QUOTACTL_4A */
diff --git a/source/lib/sysquotas_linux.c b/source/lib/sysquotas_linux.c
deleted file mode 100644
index 3867c1b0f9b..00000000000
--- a/source/lib/sysquotas_linux.c
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
- System QUOTA function wrappers for LINUX
- Copyright (C) Stefan (metze) Metzmacher 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"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_QUOTA
-
-#ifdef HAVE_QUOTACTL_LINUX
-
-#include "samba_linux_quota.h"
-
-/****************************************************************************
- Abstract out the v1 Linux quota get calls.
-****************************************************************************/
-static int sys_get_linux_v1_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
-{
- int ret = -1;
- uint32 qflags = 0;
- struct v1_kern_dqblk D;
- SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
-
- ZERO_STRUCT(D);
-
- switch (qtype) {
- case SMB_USER_QUOTA_TYPE:
- DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
- path, bdev, (unsigned)id.uid));
-
- if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))&&errno != EDQUOT) {
- return ret;
- }
-
- break;
- case SMB_GROUP_QUOTA_TYPE:
- DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
- path, bdev, (unsigned)id.gid));
-
- if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))&&errno != EDQUOT) {
- return ret;
- }
-
- break;
- case SMB_USER_FS_QUOTA_TYPE:
- DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
- path, bdev, (unsigned)id.uid));
-
- if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
- qflags |= QUOTAS_DENY_DISK;
- }
-
- break;
- case SMB_GROUP_FS_QUOTA_TYPE:
- DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
- path, bdev, (unsigned)id.gid));
-
- if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
- qflags |= QUOTAS_DENY_DISK;
- }
-
- break;
- default:
- errno = ENOSYS;
- return -1;
- }
-
- dp->bsize = bsize;
- dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
- dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
- dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
- dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
- dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
- dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
-
-
- dp->qflags = qflags;
-
- return ret;
-}
-
-/****************************************************************************
- Abstract out the v1 Linux quota set calls.
-****************************************************************************/
-static int sys_set_linux_v1_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
-{
- int ret = -1;
- uint32 qflags = 0;
- uint32 oldqflags = 0;
- struct v1_kern_dqblk D;
- SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
-
- ZERO_STRUCT(D);
-
- if (bsize == dp->bsize) {
- D.dqb_bsoftlimit = dp->softlimit;
- D.dqb_bhardlimit = dp->hardlimit;
- D.dqb_ihardlimit = dp->ihardlimit;
- D.dqb_isoftlimit = dp->isoftlimit;
- } else {
- D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize;
- D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize;
- D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize;
- D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize;
- }
-
- qflags = dp->qflags;
-
- switch (qtype) {
- case SMB_USER_QUOTA_TYPE:
- DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
- path, bdev, (unsigned)id.uid));
-
- ret = quotactl(QCMD(Q_V1_SETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D);
- break;
- case SMB_GROUP_QUOTA_TYPE:
- DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
- path, bdev, (unsigned)id.gid));
-
- ret = quotactl(QCMD(Q_V1_SETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D);
- break;
- case SMB_USER_FS_QUOTA_TYPE:
- DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
- path, bdev, (unsigned)id.uid));
-
- if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
- oldqflags |= QUOTAS_DENY_DISK;
- }
-
- break;
- case SMB_GROUP_FS_QUOTA_TYPE:
- DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
- path, bdev, (unsigned)id.gid));
-
- if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
- oldqflags |= QUOTAS_DENY_DISK;
- }
-
- break;
- default:
- errno = ENOSYS;
- return -1;
- }
-
- return ret;
-}
-
-/****************************************************************************
- Abstract out the v2 Linux quota get calls.
-****************************************************************************/
-static int sys_get_linux_v2_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
-{
- int ret = -1;
- uint32 qflags = 0;
- struct v2_kern_dqblk D;
- SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
-
- ZERO_STRUCT(D);
-
- switch (qtype) {
- case SMB_USER_QUOTA_TYPE:
- DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
- path, bdev, (unsigned)id.uid));
-
- if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))&&errno != EDQUOT) {
- return ret;
- }
-
- break;
- case SMB_GROUP_QUOTA_TYPE:
- DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
- path, bdev, (unsigned)id.gid));
-
- if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))&&errno != EDQUOT) {
- return ret;
- }
-
- break;
- case SMB_USER_FS_QUOTA_TYPE:
- DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
- path, bdev, (unsigned)id.uid));
-
- if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
- qflags |= QUOTAS_DENY_DISK;
- }
-
- break;
- case SMB_GROUP_FS_QUOTA_TYPE:
- DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
- path, bdev, (unsigned)id.gid));
-
- if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
- qflags |= QUOTAS_DENY_DISK;
- }
-
- break;
- default:
- errno = ENOSYS;
- return -1;
- }
-
- dp->bsize = bsize;
- dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
- dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
- dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
- dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
- dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
- dp->curblocks = (SMB_BIG_UINT)D.dqb_curspace/bsize;
-
-
- dp->qflags = qflags;
-
- return ret;
-}
-
-/****************************************************************************
- Abstract out the v2 Linux quota set calls.
-****************************************************************************/
-static int sys_set_linux_v2_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
-{
- int ret = -1;
- uint32 qflags = 0;
- uint32 oldqflags = 0;
- struct v2_kern_dqblk D;
- SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
-
- ZERO_STRUCT(D);
-
- if (bsize == dp->bsize) {
- D.dqb_bsoftlimit = dp->softlimit;
- D.dqb_bhardlimit = dp->hardlimit;
- D.dqb_ihardlimit = dp->ihardlimit;
- D.dqb_isoftlimit = dp->isoftlimit;
- } else {
- D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize;
- D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize;
- D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize;
- D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize;
- }
-
- qflags = dp->qflags;
-
- switch (qtype) {
- case SMB_USER_QUOTA_TYPE:
- DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
- path, bdev, (unsigned)id.uid));
-
- ret = quotactl(QCMD(Q_V2_SETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D);
- break;
- case SMB_GROUP_QUOTA_TYPE:
- DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
- path, bdev, (unsigned)id.gid));
-
- ret = quotactl(QCMD(Q_V2_SETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D);
- break;
- case SMB_USER_FS_QUOTA_TYPE:
- DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
- path, bdev, (unsigned)id.uid));
-
- if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
- oldqflags |= QUOTAS_DENY_DISK;
- }
-
- break;
- case SMB_GROUP_FS_QUOTA_TYPE:
- DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
- path, bdev, (unsigned)id.gid));
-
- if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
- oldqflags |= QUOTAS_DENY_DISK;
- }
-
- break;
- default:
- errno = ENOSYS;
- return -1;
- }
-
- return ret;
-}
-
-/****************************************************************************
- Abstract out the generic Linux quota get calls.
-****************************************************************************/
-static int sys_get_linux_gen_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
-{
- int ret = -1;
- uint32 qflags = 0;
- struct if_dqblk D;
- SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
-
- ZERO_STRUCT(D);
-
- switch (qtype) {
- case SMB_USER_QUOTA_TYPE:
- DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
- path, bdev, (unsigned)id.uid));
-
- if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))&&errno != EDQUOT) {
- return ret;
- }
-
- break;
- case SMB_GROUP_QUOTA_TYPE:
- DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
- path, bdev, (unsigned)id.gid));
-
- if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))&&errno != EDQUOT) {
- return ret;
- }
-
- break;
- case SMB_USER_FS_QUOTA_TYPE:
- DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
- path, bdev, (unsigned)id.uid));
-
- if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
- qflags |= QUOTAS_DENY_DISK;
- }
-
- break;
- case SMB_GROUP_FS_QUOTA_TYPE:
- DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
- path, bdev, (unsigned)id.gid));
-
- if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
- qflags |= QUOTAS_DENY_DISK;
- }
-
- break;
- default:
- errno = ENOSYS;
- return -1;
- }
-
- dp->bsize = bsize;
- dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
- dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
- dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
- dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
- dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
- dp->curblocks = (SMB_BIG_UINT)D.dqb_curspace/bsize;
-
-
- dp->qflags = qflags;
-
- return ret;
-}
-
-/****************************************************************************
- Abstract out the gen Linux quota set calls.
-****************************************************************************/
-static int sys_set_linux_gen_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
-{
- int ret = -1;
- uint32 qflags = 0;
- uint32 oldqflags = 0;
- struct if_dqblk D;
- SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
-
- ZERO_STRUCT(D);
-
- if (bsize == dp->bsize) {
- D.dqb_bsoftlimit = dp->softlimit;
- D.dqb_bhardlimit = dp->hardlimit;
- D.dqb_ihardlimit = dp->ihardlimit;
- D.dqb_isoftlimit = dp->isoftlimit;
- } else {
- D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize;
- D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize;
- D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize;
- D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize;
- }
-
- qflags = dp->qflags;
-
- switch (qtype) {
- case SMB_USER_QUOTA_TYPE:
- DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
- path, bdev, (unsigned)id.uid));
-
- ret = quotactl(QCMD(Q_SETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D);
- break;
- case SMB_GROUP_QUOTA_TYPE:
- DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
- path, bdev, (unsigned)id.gid));
-
- ret = quotactl(QCMD(Q_SETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D);
- break;
- case SMB_USER_FS_QUOTA_TYPE:
- DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
- path, bdev, (unsigned)id.uid));
-
- if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
- oldqflags |= QUOTAS_DENY_DISK;
- }
-
- break;
- case SMB_GROUP_FS_QUOTA_TYPE:
- DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
- path, bdev, (unsigned)id.gid));
-
- if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
- oldqflags |= QUOTAS_DENY_DISK;
- }
-
- break;
- default:
- errno = ENOSYS;
- return -1;
- }
-
- return ret;
-}
-
-/****************************************************************************
- Abstract out the Linux quota get calls.
-****************************************************************************/
-int sys_get_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
-{
- int ret = -1;
-
- if (!path||!bdev||!dp)
- smb_panic("sys_set_vfs_quota: called with NULL pointer");
-
- ZERO_STRUCT(*dp);
- dp->qtype = qtype;
-
- switch (qtype) {
- case SMB_USER_QUOTA_TYPE:
- case SMB_GROUP_QUOTA_TYPE:
- if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
- if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
- if ((ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
- return ret;
- }
- }
- }
-
- if ((dp->curblocks==0)&&
- (dp->softlimit==0)&&
- (dp->hardlimit==0)) {
- /* the upper layer functions don't want empty quota records...*/
- return -1;
- }
-
- break;
- case SMB_USER_FS_QUOTA_TYPE:
- id.uid = getuid();
-
- if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
- if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
- ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp);
- }
- }
-
- ret = 0;
- break;
- case SMB_GROUP_FS_QUOTA_TYPE:
- id.gid = getgid();
-
- if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
- if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
- ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp);
- }
- }
-
- ret = 0;
- break;
- default:
- errno = ENOSYS;
- return -1;
- }
-
- return ret;
-}
-
-/****************************************************************************
- Abstract out the Linux quota set calls.
-****************************************************************************/
-int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
-{
- int ret = -1;
- uint32 oldqflags = 0;
-
- if (!path||!bdev||!dp)
- smb_panic("sys_set_vfs_quota: called with NULL pointer");
-
- oldqflags = dp->qflags;
-
- switch (qtype) {
- case SMB_USER_QUOTA_TYPE:
- case SMB_GROUP_QUOTA_TYPE:
- if ((ret=sys_set_linux_gen_quota(path, bdev, qtype, id, dp))) {
- if ((ret=sys_set_linux_v2_quota(path, bdev, qtype, id, dp))) {
- if ((ret=sys_set_linux_v1_quota(path, bdev, qtype, id, dp))) {
- return ret;
- }
- }
- }
- break;
- case SMB_USER_FS_QUOTA_TYPE:
- id.uid = getuid();
-
- if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))) {
- if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))) {
- ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp);
- }
- }
-
- if (oldqflags == dp->qflags) {
- ret = 0;
- } else {
- ret = -1;
- }
- break;
- case SMB_GROUP_FS_QUOTA_TYPE:
- id.gid = getgid();
-
- if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))) {
- if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))) {
- ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp);
- }
- }
-
- if (oldqflags == dp->qflags) {
- ret = 0;
- } else {
- ret = -1;
- }
-
- break;
- default:
- errno = ENOSYS;
- return -1;
- }
-
- return ret;
-}
-
-#else /* HAVE_QUOTACTL_LINUX */
- void dummy_sysquotas_linux(void){}
-#endif /* HAVE_QUOTACTL_LINUX */
diff --git a/source/lib/sysquotas_xfs.c b/source/lib/sysquotas_xfs.c
deleted file mode 100644
index 9fe4ec0d992..00000000000
--- a/source/lib/sysquotas_xfs.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
- System QUOTA function wrappers for XFS
- Copyright (C) Stefan (metze) Metzmacher 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"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_QUOTA
-
-#ifndef HAVE_SYS_QUOTAS
-#ifdef HAVE_XFS_QUOTAS
-#undef HAVE_XFS_QUOTAS
-#endif
-#endif
-
-#ifdef HAVE_XFS_QUOTAS
-
-#ifdef HAVE_LINUX_XFS_QUOTAS
-#include "samba_linux_quota.h"
-#include "samba_xfs_quota.h"
-#define HAVE_GROUP_QUOTA
-#else /* IRIX */
-#include <sys/quota.h>
-#endif
-
-/* on IRIX */
-#ifndef Q_XQUOTAON
-#define Q_XQUOTAON Q_QUOTAON
-#endif /* Q_XQUOTAON */
-#ifndef Q_XQUOTAOFF
-#define Q_XQUOTAOFF Q_QUOTAOFF
-#endif /* Q_XQUOTAOFF */
-#ifndef Q_XGETQSTAT
-#define Q_XGETQSTAT Q_GETQSTAT
-#endif /* Q_XGETQSTAT */
-
-/* currently doesn't support Group and Project quotas on IRIX
- */
-
-#ifndef QCMD
-#define QCMD(x,y) x
-#endif
-
-/*
- * IRIX has BBSIZE in <sys/param.h>
- */
-#ifndef BBSHIFT
-#define BBSHIFT 9
-#endif /* BBSHIFT */
-#ifndef BBSIZE
-#define BBSIZE (1<<BBSHIFT)
-#endif /* BBSIZE */
-
-/****************************************************************************
- Abstract out the XFS Quota Manager quota get call.
-****************************************************************************/
-int sys_get_xfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
-{
- int ret = -1;
- uint32 qflags = 0;
- SMB_BIG_UINT bsize = (SMB_BIG_UINT)BBSIZE;
- struct fs_disk_quota D;
- struct fs_quota_stat F;
- ZERO_STRUCT(D);
- ZERO_STRUCT(F);
-
- if (!bdev||!dp)
- smb_panic("sys_get_xfs_quota: called with NULL pointer");
-
- ZERO_STRUCT(*dp);
- dp->qtype = qtype;
-
- switch (qtype) {
- case SMB_USER_QUOTA_TYPE:
- DEBUG(10,("sys_get_xfs_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
- path, bdev, (unsigned)id.uid));
-
- if ((ret=quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D)))
- return ret;
- break;
-#ifdef HAVE_GROUP_QUOTA
- case SMB_GROUP_QUOTA_TYPE:
- DEBUG(10,("sys_get_xfs_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
- path, bdev, (unsigned)id.gid));
-
- if ((ret=quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D)))
- return ret;
- break;
-#endif /* HAVE_GROUP_QUOTA */
- case SMB_USER_FS_QUOTA_TYPE:
- DEBUG(10,("sys_get_xfs_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
- path, bdev, (unsigned)id.uid));
-
- quotactl(QCMD(Q_XGETQSTAT,USRQUOTA), bdev, -1, (caddr_t)&F);
-
- if (F.qs_flags & XFS_QUOTA_UDQ_ENFD) {
- qflags |= QUOTAS_DENY_DISK;
- }
- else if (F.qs_flags & XFS_QUOTA_UDQ_ACCT) {
- qflags |= QUOTAS_ENABLED;
- }
-
- ret = 0;
-
- break;
-#ifdef HAVE_GROUP_QUOTA
- case SMB_GROUP_FS_QUOTA_TYPE:
- DEBUG(10,("sys_get_xfs_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
- path, bdev, (unsigned)id.gid));
-
- quotactl(QCMD(Q_XGETQSTAT,GRPQUOTA), bdev, -1, (caddr_t)&F);
-
- if (F.qs_flags & XFS_QUOTA_GDQ_ENFD) {
- qflags |= QUOTAS_DENY_DISK;
- }
- else if (F.qs_flags & XFS_QUOTA_GDQ_ACCT) {
- qflags |= QUOTAS_ENABLED;
- }
-
- ret = 0;
-
- break;
-#endif /* HAVE_GROUP_QUOTA */
- default:
- errno = ENOSYS;
- return -1;
- }
-
- dp->bsize = bsize;
- dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit;
- dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit;
- dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit;
- dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit;
- dp->curinodes = (SMB_BIG_UINT)D.d_icount;
- dp->curblocks = (SMB_BIG_UINT)D.d_bcount;
- dp->qflags = qflags;
-
- return ret;
-}
-
-/****************************************************************************
- Abstract out the XFS Quota Manager quota set call.
-****************************************************************************/
-int sys_set_xfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
-{
- int ret = -1;
- uint32 qflags = 0;
- SMB_BIG_UINT bsize = (SMB_BIG_UINT)BBSIZE;
- struct fs_disk_quota D;
- struct fs_quota_stat F;
- int q_on = 0;
- int q_off = 0;
- ZERO_STRUCT(D);
- ZERO_STRUCT(F);
-
- if (!bdev||!dp)
- smb_panic("sys_set_xfs_quota: called with NULL pointer");
-
- if (bsize == dp->bsize) {
- D.d_blk_softlimit = dp->softlimit;
- D.d_blk_hardlimit = dp->hardlimit;
- D.d_ino_hardlimit = dp->ihardlimit;
- D.d_ino_softlimit = dp->isoftlimit;
- } else {
- D.d_blk_softlimit = (dp->softlimit*dp->bsize)/bsize;
- D.d_blk_hardlimit = (dp->hardlimit*dp->bsize)/bsize;
- D.d_ino_hardlimit = (dp->ihardlimit*dp->bsize)/bsize;
- D.d_ino_softlimit = (dp->isoftlimit*dp->bsize)/bsize;
- }
-
- qflags = dp->qflags;
-
- switch (qtype) {
- case SMB_USER_QUOTA_TYPE:
- DEBUG(10,("sys_set_xfs_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
- path, bdev, (unsigned)id.uid));
-
- D.d_fieldmask |= FS_DQ_LIMIT_MASK;
- ret = quotactl(QCMD(Q_XSETQLIM,USRQUOTA), bdev, id.uid, (caddr_t)&D);
- break;
-#ifdef HAVE_GROUP_QUOTA
- case SMB_GROUP_QUOTA_TYPE:
- DEBUG(10,("sys_set_xfs_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
- path, bdev, (unsigned)id.gid));
-
- D.d_fieldmask |= FS_DQ_LIMIT_MASK;
- ret = quotactl(QCMD(Q_XSETQLIM,GRPQUOTA), bdev, id.gid, (caddr_t)&D);
- break;
-#endif /* HAVE_GROUP_QUOTA */
- case SMB_USER_FS_QUOTA_TYPE:
- DEBUG(10,("sys_set_xfs_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
- path, bdev, (unsigned)id.uid));
-
- quotactl(QCMD(Q_XGETQSTAT,USRQUOTA), bdev, -1, (caddr_t)&F);
-
- if (qflags & QUOTAS_DENY_DISK) {
- if (!(F.qs_flags & XFS_QUOTA_UDQ_ENFD))
- q_on |= XFS_QUOTA_UDQ_ENFD;
- if (!(F.qs_flags & XFS_QUOTA_UDQ_ACCT))
- q_on |= XFS_QUOTA_UDQ_ACCT;
-
- if (q_on != 0) {
- ret = quotactl(QCMD(Q_XQUOTAON,USRQUOTA),bdev, -1, (caddr_t)&q_on);
- } else {
- ret = 0;
- }
-
- } else if (qflags & QUOTAS_ENABLED) {
- if (F.qs_flags & XFS_QUOTA_UDQ_ENFD)
- q_off |= XFS_QUOTA_UDQ_ENFD;
-
- if (q_off != 0) {
- ret = quotactl(QCMD(Q_XQUOTAOFF,USRQUOTA),bdev, -1, (caddr_t)&q_off);
- } else {
- ret = 0;
- }
-
- if (!(F.qs_flags & XFS_QUOTA_UDQ_ACCT))
- q_on |= XFS_QUOTA_UDQ_ACCT;
-
- if (q_on != 0) {
- ret = quotactl(QCMD(Q_XQUOTAON,USRQUOTA),bdev, -1, (caddr_t)&q_on);
- } else {
- ret = 0;
- }
- } else {
-#if 0
- /* Switch on XFS_QUOTA_UDQ_ACCT didn't work!
- * only swittching off XFS_QUOTA_UDQ_ACCT work
- */
- if (F.qs_flags & XFS_QUOTA_UDQ_ENFD)
- q_off |= XFS_QUOTA_UDQ_ENFD;
- if (F.qs_flags & XFS_QUOTA_UDQ_ACCT)
- q_off |= XFS_QUOTA_UDQ_ACCT;
-
- if (q_off !=0) {
- ret = quotactl(QCMD(Q_XQUOTAOFF,USRQUOTA),bdev, -1, (caddr_t)&q_off);
- } else {
- ret = 0;
- }
-#else
- ret = -1;
-#endif
- }
-
- break;
-#ifdef HAVE_GROUP_QUOTA
- case SMB_GROUP_FS_QUOTA_TYPE:
- DEBUG(10,("sys_set_xfs_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
- path, bdev, (unsigned)id.gid));
-
- quotactl(QCMD(Q_XGETQSTAT,GRPQUOTA), bdev, -1, (caddr_t)&F);
-
- if (qflags & QUOTAS_DENY_DISK) {
- if (!(F.qs_flags & XFS_QUOTA_GDQ_ENFD))
- q_on |= XFS_QUOTA_GDQ_ENFD;
- if (!(F.qs_flags & XFS_QUOTA_GDQ_ACCT))
- q_on |= XFS_QUOTA_GDQ_ACCT;
-
- if (q_on != 0) {
- ret = quotactl(QCMD(Q_XQUOTAON,GRPQUOTA),bdev, -1, (caddr_t)&q_on);
- } else {
- ret = 0;
- }
-
- } else if (qflags & QUOTAS_ENABLED) {
- if (F.qs_flags & XFS_QUOTA_GDQ_ENFD)
- q_off |= XFS_QUOTA_GDQ_ENFD;
-
- if (q_off != 0) {
- ret = quotactl(QCMD(Q_XQUOTAOFF,GRPQUOTA),bdev, -1, (caddr_t)&q_off);
- } else {
- ret = 0;
- }
-
- if (!(F.qs_flags & XFS_QUOTA_GDQ_ACCT))
- q_on |= XFS_QUOTA_GDQ_ACCT;
-
- if (q_on != 0) {
- ret = quotactl(QCMD(Q_XQUOTAON,GRPQUOTA),bdev, -1, (caddr_t)&q_on);
- } else {
- ret = 0;
- }
- } else {
-#if 0
- /* Switch on XFS_QUOTA_UDQ_ACCT didn't work!
- * only swittching off XFS_QUOTA_UDQ_ACCT work
- */
- if (F.qs_flags & XFS_QUOTA_GDQ_ENFD)
- q_off |= XFS_QUOTA_GDQ_ENFD;
- if (F.qs_flags & XFS_QUOTA_GDQ_ACCT)
- q_off |= XFS_QUOTA_GDQ_ACCT;
-
- if (q_off !=0) {
- ret = quotactl(QCMD(Q_XQUOTAOFF,GRPQUOTA),bdev, -1, (caddr_t)&q_off);
- } else {
- ret = 0;
- }
-#else
- ret = -1;
-#endif
- }
-
- break;
-#endif /* HAVE_GROUP_QUOTA */
- default:
- errno = ENOSYS;
- return -1;
- }
-
- return ret;
-}
-
-#else /* HAVE_XFS_QUOTAS */
- void dummy_sysquotas_xfs(void){}
-#endif /* HAVE_XFS_QUOTAS */
diff --git a/source/lib/system.c b/source/lib/system.c
index a0007ec83cd..98d975aa503 100644
--- a/source/lib/system.c
+++ b/source/lib/system.c
@@ -100,47 +100,6 @@ ssize_t sys_write(int fd, const void *buf, size_t count)
return ret;
}
-
-/*******************************************************************
-A pread wrapper that will deal with EINTR and 64-bit file offsets.
-********************************************************************/
-
-#if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
-ssize_t sys_pread(int fd, void *buf, size_t count, SMB_OFF_T off)
-{
- ssize_t ret;
-
- do {
-#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PREAD64)
- ret = pread64(fd, buf, count, off);
-#else
- ret = pread(fd, buf, count, off);
-#endif
- } while (ret == -1 && errno == EINTR);
- return ret;
-}
-#endif
-
-/*******************************************************************
-A write wrapper that will deal with EINTR and 64-bit file offsets.
-********************************************************************/
-
-#if defined(HAVE_PWRITE) || defined(HAVE_PWRITE64)
-ssize_t sys_pwrite(int fd, const void *buf, size_t count, SMB_OFF_T off)
-{
- ssize_t ret;
-
- do {
-#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PWRITE64)
- ret = pwrite64(fd, buf, count, off);
-#else
- ret = pwrite(fd, buf, count, off);
-#endif
- } while (ret == -1 && errno == EINTR);
- return ret;
-}
-#endif
-
/*******************************************************************
A send wrapper that will deal with EINTR.
********************************************************************/
@@ -365,7 +324,7 @@ FILE *sys_fopen(const char *path, const char *type)
A readdir wrapper that will deal with 64 bit filesizes.
********************************************************************/
-SMB_STRUCT_DIRENT *sys_readdir(DIR *dirp)
+struct smb_dirent *sys_readdir(DIR *dirp)
{
#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
return readdir64(dirp);
@@ -375,40 +334,6 @@ SMB_STRUCT_DIRENT *sys_readdir(DIR *dirp)
}
/*******************************************************************
- An mknod() wrapper that will deal with 64 bit filesizes.
-********************************************************************/
-
-int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
-{
-#if defined(HAVE_MKNOD) || defined(HAVE_MKNOD64)
-#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_MKNOD64) && defined(HAVE_DEV64_T)
- return mknod64(path, mode, dev);
-#else
- return mknod(path, mode, dev);
-#endif
-#else
- /* No mknod system call. */
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-/*******************************************************************
- Wrapper for realpath.
-********************************************************************/
-
-char *sys_realpath(const char *path, char *resolved_path)
-{
-#if defined(HAVE_REALPATH)
- return realpath(path, resolved_path);
-#else
- /* As realpath is not a system call we can't return ENOSYS. */
- errno = EINVAL;
- return NULL;
-#endif
-}
-
-/*******************************************************************
The wait() calls vary between systems
********************************************************************/
@@ -437,34 +362,6 @@ char *sys_getwd(char *s)
}
/*******************************************************************
-system wrapper for symlink
-********************************************************************/
-
-int sys_symlink(const char *oldpath, const char *newpath)
-{
-#ifndef HAVE_SYMLINK
- errno = ENOSYS;
- return -1;
-#else
- return symlink(oldpath, newpath);
-#endif
-}
-
-/*******************************************************************
-system wrapper for readlink
-********************************************************************/
-
-int sys_readlink(const char *path, char *buf, size_t bufsiz)
-{
-#ifndef HAVE_READLINK
- errno = ENOSYS;
- return -1;
-#else
- return readlink(path, buf, bufsiz);
-#endif
-}
-
-/*******************************************************************
system wrapper for link
********************************************************************/
@@ -479,25 +376,6 @@ int sys_link(const char *oldpath, const char *newpath)
}
/*******************************************************************
-chown isn't used much but OS/2 doesn't have it
-********************************************************************/
-
-int sys_chown(const char *fname,uid_t uid,gid_t gid)
-{
-#ifndef HAVE_CHOWN
- static int done;
- if (!done) {
- DEBUG(1,("WARNING: no chown!\n"));
- done=1;
- }
- errno = ENOSYS;
- return -1;
-#else
- return(chown(fname,uid,gid));
-#endif
-}
-
-/*******************************************************************
os/2 also doesn't have chroot
********************************************************************/
int sys_chroot(const char *dname)
@@ -736,6 +614,7 @@ int sys_getgroups(int setlen, gid_t *gidset)
#endif /* HAVE_BROKEN_GETGROUPS */
}
+#ifdef HAVE_SETGROUPS
/**************************************************************************
Wrapper for setgroups. Deals with broken (int) case. Automatically used
@@ -744,11 +623,6 @@ int sys_getgroups(int setlen, gid_t *gidset)
int sys_setgroups(int setlen, gid_t *gidset)
{
-#if !defined(HAVE_SETGROUPS)
- errno = ENOSYS;
- return -1;
-#endif /* HAVE_SETGROUPS */
-
#if !defined(HAVE_BROKEN_GETGROUPS)
return setgroups(setlen, gidset);
#else
@@ -789,14 +663,7 @@ int sys_setgroups(int setlen, gid_t *gidset)
#endif /* HAVE_BROKEN_GETGROUPS */
}
-/**************************************************************************
- Wrappers for setpwent(), getpwent() and endpwent()
-****************************************************************************/
-
-void sys_setpwent(void)
-{
- setpwent();
-}
+#endif /* HAVE_SETGROUPS */
struct passwd *sys_getpwent(void)
{
@@ -832,177 +699,6 @@ struct group *sys_getgrgid(gid_t gid)
return getgrgid(gid);
}
-#if 0 /* NOT CURRENTLY USED - JRA */
-/**************************************************************************
- The following are the UNICODE versions of *all* system interface functions
- called within Samba. Ok, ok, the exceptions are the gethostbyXX calls,
- which currently are left as ascii as they are not used other than in name
- resolution.
-****************************************************************************/
-
-/**************************************************************************
- Wide stat. Just narrow and call sys_xxx.
-****************************************************************************/
-
-int wsys_stat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
-{
- pstring fname;
- return sys_stat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
-}
-
-/**************************************************************************
- Wide lstat. Just narrow and call sys_xxx.
-****************************************************************************/
-
-int wsys_lstat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
-{
- pstring fname;
- return sys_lstat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
-}
-
-/**************************************************************************
- Wide creat. Just narrow and call sys_xxx.
-****************************************************************************/
-
-int wsys_creat(const smb_ucs2_t *wfname, mode_t mode)
-{
- pstring fname;
- return sys_creat(unicode_to_unix(fname,wfname,sizeof(fname)), mode);
-}
-
-/**************************************************************************
- Wide open. Just narrow and call sys_xxx.
-****************************************************************************/
-
-int wsys_open(const smb_ucs2_t *wfname, int oflag, mode_t mode)
-{
- pstring fname;
- return sys_open(unicode_to_unix(fname,wfname,sizeof(fname)), oflag, mode);
-}
-
-/**************************************************************************
- Wide fopen. Just narrow and call sys_xxx.
-****************************************************************************/
-
-FILE *wsys_fopen(const smb_ucs2_t *wfname, const char *type)
-{
- pstring fname;
- return sys_fopen(unicode_to_unix(fname,wfname,sizeof(fname)), type);
-}
-
-/**************************************************************************
- Wide opendir. Just narrow and call sys_xxx.
-****************************************************************************/
-
-DIR *wsys_opendir(const smb_ucs2_t *wfname)
-{
- pstring fname;
- return opendir(unicode_to_unix(fname,wfname,sizeof(fname)));
-}
-
-/**************************************************************************
- Wide readdir. Return a structure pointer containing a wide filename.
-****************************************************************************/
-
-SMB_STRUCT_WDIRENT *wsys_readdir(DIR *dirp)
-{
- static SMB_STRUCT_WDIRENT retval;
- SMB_STRUCT_DIRENT *dirval = sys_readdir(dirp);
-
- if(!dirval)
- return NULL;
-
- /*
- * The only POSIX defined member of this struct is d_name.
- */
-
- unix_to_unicode(retval.d_name,dirval->d_name,sizeof(retval.d_name));
-
- return &retval;
-}
-
-/**************************************************************************
- Wide getwd. Call sys_xxx and widen. Assumes s points to a wpstring.
-****************************************************************************/
-
-smb_ucs2_t *wsys_getwd(smb_ucs2_t *s)
-{
- pstring fname;
- char *p = sys_getwd(fname);
-
- if(!p)
- return NULL;
-
- return unix_to_unicode(s, p, sizeof(wpstring));
-}
-
-/**************************************************************************
- Wide chown. Just narrow and call sys_xxx.
-****************************************************************************/
-
-int wsys_chown(const smb_ucs2_t *wfname, uid_t uid, gid_t gid)
-{
- pstring fname;
- return chown(unicode_to_unix(fname,wfname,sizeof(fname)), uid, gid);
-}
-
-/**************************************************************************
- Wide chroot. Just narrow and call sys_xxx.
-****************************************************************************/
-
-int wsys_chroot(const smb_ucs2_t *wfname)
-{
- pstring fname;
- return chroot(unicode_to_unix(fname,wfname,sizeof(fname)));
-}
-
-/**************************************************************************
- Wide getpwnam. Return a structure pointer containing wide names.
-****************************************************************************/
-
-SMB_STRUCT_WPASSWD *wsys_getpwnam(const smb_ucs2_t *wname)
-{
- static SMB_STRUCT_WPASSWD retval;
- fstring name;
- struct passwd *pwret = sys_getpwnam(unicode_to_unix(name,wname,sizeof(name)));
-
- if(!pwret)
- return NULL;
-
- unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
- retval.pw_passwd = pwret->pw_passwd;
- retval.pw_uid = pwret->pw_uid;
- retval.pw_gid = pwret->pw_gid;
- unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
- unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
- unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
-
- return &retval;
-}
-
-/**************************************************************************
- Wide getpwuid. Return a structure pointer containing wide names.
-****************************************************************************/
-
-SMB_STRUCT_WPASSWD *wsys_getpwuid(uid_t uid)
-{
- static SMB_STRUCT_WPASSWD retval;
- struct passwd *pwret = sys_getpwuid(uid);
-
- if(!pwret)
- return NULL;
-
- unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
- retval.pw_passwd = pwret->pw_passwd;
- retval.pw_uid = pwret->pw_uid;
- retval.pw_gid = pwret->pw_gid;
- unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
- unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
- unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
-
- return &retval;
-}
-#endif /* NOT CURRENTLY USED - JRA */
/**************************************************************************
Extract a command into an arg list. Uses a static pstring for storage.
@@ -1052,35 +748,6 @@ static char **extract_args(const char *command)
}
/**************************************************************************
- Wrapper for fork. Ensures that mypid is reset. Used so we can write
- a sys_getpid() that only does a system call *once*.
-****************************************************************************/
-
-static pid_t mypid = (pid_t)-1;
-
-pid_t sys_fork(void)
-{
- pid_t forkret = fork();
-
- if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
- mypid = (pid_t) -1;
-
- return forkret;
-}
-
-/**************************************************************************
- Wrapper for getpid. Ensures we only do a system call *once*.
-****************************************************************************/
-
-pid_t sys_getpid(void)
-{
- if (mypid == (pid_t)-1)
- mypid = getpid();
-
- return mypid;
-}
-
-/**************************************************************************
Wrapper for popen. Safer as it doesn't search a path.
Modified from the glibc sources.
modified by tridge to return a file descriptor. We must kick our FILE* habit
@@ -1125,7 +792,7 @@ int sys_popen(const char *command)
if(!(argl = extract_args(command)))
goto err_exit;
- entry->child_pid = sys_fork();
+ entry->child_pid = fork();
if (entry->child_pid == -1) {
goto err_exit;
@@ -1274,309 +941,3 @@ int sys_dup2(int oldfd, int newfd)
#endif
}
-/**************************************************************************
- Wrapper for Admin Logs.
-****************************************************************************/
-
- void sys_adminlog(int priority, const char *format_str, ...)
-{
- va_list ap;
- int ret;
- char *msgbuf = NULL;
-
- va_start( ap, format_str );
- ret = vasprintf( &msgbuf, format_str, ap );
- va_end( ap );
-
- if (ret == -1)
- return;
-
-#if defined(HAVE_SYSLOG)
- syslog( priority, "%s", msgbuf );
-#else
- DEBUG(0,("%s", msgbuf ));
-#endif
- SAFE_FREE(msgbuf);
-}
-
-/**************************************************************************
- Wrappers for extented attribute calls. Based on the Linux package with
- support for IRIX also. Expand as other systems have them.
-****************************************************************************/
-
-ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
-{
-#if defined(HAVE_GETXATTR)
- return getxattr(path, name, value, size);
-#elif defined(HAVE_ATTR_GET)
- int retval, flags = 0;
- int valuelength = (int)size;
- char *attrname = strchr(name,'.') +1;
-
- if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
-
- retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
-
- return retval ? retval : valuelength;
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size)
-{
-#if defined(HAVE_LGETXATTR)
- return lgetxattr(path, name, value, size);
-#elif defined(HAVE_ATTR_GET)
- int retval, flags = ATTR_DONTFOLLOW;
- int valuelength = (int)size;
- char *attrname = strchr(name,'.') +1;
-
- if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
-
- retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
-
- return retval ? retval : valuelength;
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
-{
-#if defined(HAVE_FGETXATTR)
- return fgetxattr(filedes, name, value, size);
-#elif defined(HAVE_ATTR_GETF)
- int retval, flags = 0;
- int valuelength = (int)size;
- char *attrname = strchr(name,'.') +1;
-
- if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
-
- retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
-
- return retval ? retval : valuelength;
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-#if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
-static char attr_buffer[ATTR_MAX_VALUELEN];
-
-static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
-{
- int retval = 0, index;
- attrlist_cursor_t *cursor = 0;
- int total_size = 0;
- attrlist_t * al = (attrlist_t *)attr_buffer;
- attrlist_ent_t *ae;
- size_t ent_size, left = size;
- char *bp = list;
-
- while (True) {
- if (filedes)
- retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
- else
- retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
- if (retval) break;
- for (index = 0; index < al->al_count; index++) {
- ae = ATTR_ENTRY(attr_buffer, index);
- ent_size = strlen(ae->a_name) + sizeof("user.");
- if (left >= ent_size) {
- strncpy(bp, "user.", sizeof("user."));
- strncat(bp, ae->a_name, ent_size - sizeof("user."));
- bp += ent_size;
- left -= ent_size;
- } else if (size) {
- errno = ERANGE;
- retval = -1;
- break;
- }
- total_size += ent_size;
- }
- if (al->al_more == 0) break;
- }
- if (retval == 0) {
- flags |= ATTR_ROOT;
- cursor = 0;
- while (True) {
- if (filedes)
- retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
- else
- retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
- if (retval) break;
- for (index = 0; index < al->al_count; index++) {
- ae = ATTR_ENTRY(attr_buffer, index);
- ent_size = strlen(ae->a_name) + sizeof("system.");
- if (left >= ent_size) {
- strncpy(bp, "system.", sizeof("system."));
- strncat(bp, ae->a_name, ent_size - sizeof("system."));
- bp += ent_size;
- left -= ent_size;
- } else if (size) {
- errno = ERANGE;
- retval = -1;
- break;
- }
- total_size += ent_size;
- }
- if (al->al_more == 0) break;
- }
- }
- return (ssize_t)(retval ? retval : total_size);
-}
-
-#endif
-
-ssize_t sys_listxattr (const char *path, char *list, size_t size)
-{
-#if defined(HAVE_LISTXATTR)
- return listxattr(path, list, size);
-#elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
- return irix_attr_list(path, 0, list, size, 0);
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-ssize_t sys_llistxattr (const char *path, char *list, size_t size)
-{
-#if defined(HAVE_LLISTXATTR)
- return llistxattr(path, list, size);
-#elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
- return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-ssize_t sys_flistxattr (int filedes, char *list, size_t size)
-{
-#if defined(HAVE_FLISTXATTR)
- return flistxattr(filedes, list, size);
-#elif defined(HAVE_ATTR_LISTF)
- return irix_attr_list(NULL, filedes, list, size, 0);
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-int sys_removexattr (const char *path, const char *name)
-{
-#if defined(HAVE_REMOVEXATTR)
- return removexattr(path, name);
-#elif defined(HAVE_ATTR_REMOVE)
- int flags = 0;
- char *attrname = strchr(name,'.') +1;
-
- if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
-
- return attr_remove(path, attrname, flags);
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-int sys_lremovexattr (const char *path, const char *name)
-{
-#if defined(HAVE_LREMOVEXATTR)
- return lremovexattr(path, name);
-#elif defined(HAVE_ATTR_REMOVE)
- int flags = ATTR_DONTFOLLOW;
- char *attrname = strchr(name,'.') +1;
-
- if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
-
- return attr_remove(path, attrname, flags);
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-int sys_fremovexattr (int filedes, const char *name)
-{
-#if defined(HAVE_FREMOVEXATTR)
- return fremovexattr(filedes, name);
-#elif defined(HAVE_ATTR_REMOVEF)
- int flags = 0;
- char *attrname = strchr(name,'.') +1;
-
- if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
-
- return attr_removef(filedes, attrname, flags);
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-#if !defined(HAVE_SETXATTR)
-#define XATTR_CREATE 0x1 /* set value, fail if attr already exists */
-#define XATTR_REPLACE 0x2 /* set value, fail if attr does not exist */
-#endif
-
-int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
-{
-#if defined(HAVE_SETXATTR)
- return setxattr(path, name, value, size, flags);
-#elif defined(HAVE_ATTR_SET)
- int myflags = 0;
- char *attrname = strchr(name,'.') +1;
-
- if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
- if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
- if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
-
- return attr_set(path, attrname, (const char *)value, size, myflags);
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags)
-{
-#if defined(HAVE_LSETXATTR)
- return lsetxattr(path, name, value, size, flags);
-#elif defined(HAVE_ATTR_SET)
- int myflags = ATTR_DONTFOLLOW;
- char *attrname = strchr(name,'.') +1;
-
- if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
- if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
- if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
-
- return attr_set(path, attrname, (const char *)value, size, myflags);
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
-{
-#if defined(HAVE_FSETXATTR)
- return fsetxattr(filedes, name, value, size, flags);
-#elif defined(HAVE_ATTR_SETF)
- int myflags = 0;
- char *attrname = strchr(name,'.') +1;
-
- if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
- if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
- if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
-
- return attr_setf(filedes, attrname, (const char *)value, size, myflags);
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
diff --git a/source/lib/system_smbd.c b/source/lib/system_smbd.c
deleted file mode 100644
index 73c910e631d..00000000000
--- a/source/lib/system_smbd.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- 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 (sys_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)
-{
- char *p;
- int retval;
-
- DEBUG(10,("sys_getgrouplist: user [%s]\n", user));
-
- /* see if we should disable winbindd lookups for local users */
- if ( (p = strchr(user, *lp_winbind_separator())) == NULL ) {
- if ( !winbind_off() )
- DEBUG(0,("sys_getgroup_list: Insufficient environment space for %s\n",
- WINBINDD_DONT_ENV));
- else
- DEBUG(10,("sys_getgrouplist(): disabled winbindd for group lookup [user == %s]\n",
- user));
- }
-
-#ifdef HAVE_GETGROUPLIST
- retval = getgrouplist(user, gid, groups, grpcnt);
-#else
- become_root();
- retval = getgrouplist_internals(user, gid, groups, grpcnt);
- unbecome_root();
-#endif
-
- /* allow winbindd lookups */
- winbind_on();
-
- return retval;
-}
diff --git a/source/lib/talloc.c b/source/lib/talloc.c
index 485dc28f31d..59d4eac5004 100644
--- a/source/lib/talloc.c
+++ b/source/lib/talloc.c
@@ -48,12 +48,34 @@
**/
/**
- * If you want testing for memory corruption, link with dmalloc or use
- * Insure++. It doesn't seem useful to duplicate them here.
+ * If you want testing for memory corruption use valgrind
**/
#include "includes.h"
+#define MAX_TALLOC_SIZE 0x10000000
+
+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.
@@ -61,37 +83,30 @@
* @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 = NULL;
-
+static TALLOC_CTX *list_head;
/**
* Add to the global list
**/
static void talloc_enroll(TALLOC_CTX *t)
{
- t->next_ctx = list_head;
- list_head = 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)
{
- TALLOC_CTX **ttmp;
-
- /* Use a double-* so that no special case is required for the
- * list head. */
- for (ttmp = &list_head; *ttmp; ttmp = &((*ttmp)->next_ctx))
- if (*ttmp == t) {
- /* ttmp is the link that points to t, either
- * list_head or the next_ctx link in its
- * predecessor */
- *ttmp = t->next_ctx;
- t->next_ctx = NULL; /* clobber */
- return;
- }
- abort(); /* oops, this talloc was already
- * clobbered or something else went
- * wrong. */
+#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
}
@@ -174,8 +189,14 @@ void *talloc_realloc(TALLOC_CTX *t, void *ptr, size_t size)
void *new_ptr;
/* size zero is equivalent to free() */
- if (!t || size == 0)
+ if (!t) {
return NULL;
+ }
+
+ if (size == 0) {
+ talloc_free(t, ptr);
+ return NULL;
+ }
/* realloc(NULL) is equavalent to malloc() */
if (ptr == NULL)
@@ -223,25 +244,20 @@ void talloc_destroy(TALLOC_CTX *t)
talloc_destroy_pool(t);
talloc_disenroll(t);
SAFE_FREE(t->name);
- memset(t, 0, sizeof(TALLOC_CTX));
SAFE_FREE(t);
}
/** Return the current total size of the pool. */
size_t talloc_pool_size(TALLOC_CTX *t)
{
- if (t)
- return t->total_alloc_size;
- else
- return 0;
+ return t->total_alloc_size;
}
-const char * talloc_pool_name(TALLOC_CTX const *t)
+const char *talloc_pool_name(TALLOC_CTX const *t)
{
- if (t)
- return t->name;
- else
- return NULL;
+ if (t) return t->name;
+
+ return NULL;
}
@@ -250,19 +266,22 @@ void *talloc_zero(TALLOC_CTX *t, size_t size)
{
void *p = talloc(t, size);
- if (p)
+ 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)
+ if (newp) {
memcpy(newp, p, size);
+ }
return newp;
}
@@ -270,10 +289,20 @@ void *talloc_memdup(TALLOC_CTX *t, const void *p, size_t size)
/** strdup with a talloc */
char *talloc_strdup(TALLOC_CTX *t, const char *p)
{
- if (p)
- return talloc_memdup(t, p, strlen(p) + 1);
- else
- return NULL;
+ 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 */
@@ -281,8 +310,7 @@ 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));
- else
- return NULL;
+ return NULL;
}
/**
@@ -380,15 +408,16 @@ char *talloc_describe_all(TALLOC_CTX *rt)
if (!rt) return NULL;
s = talloc_asprintf(rt, "global talloc allocations in pid: %u\n",
- (unsigned) sys_getpid());
+ (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_ctx) {
+ for (it = list_head; it; it = it->next) {
size_t bytes;
int n_chunks;
fstring what;
@@ -410,6 +439,8 @@ char *talloc_describe_all(TALLOC_CTX *rt)
total_chunks += n_chunks;
}
+ MUTEX_UNLOCK_BY_ID(MUTEX_TALLOC);
+
s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n",
"----------------------------------------",
"--------",
@@ -446,4 +477,95 @@ void talloc_get_allocation(TALLOC_CTX *t,
}
+/*
+ free a lump from a pool. Use sparingly please.
+*/
+void talloc_free(TALLOC_CTX *ctx, void *ptr)
+{
+ struct talloc_chunk *tc;
+
+ if (!ptr || !ctx->list) return;
+
+ /* as a special case, see if its the first element in the
+ list */
+ if (ctx->list->ptr == ptr) {
+ ctx->total_alloc_size -= ctx->list->size;
+ tc = ctx->list;
+ ctx->list = ctx->list->next;
+ free(tc);
+ free(ptr);
+ return;
+ }
+
+ /* find it in the context */
+ for (tc=ctx->list; tc->next; tc=tc->next) {
+ if (tc->next->ptr == ptr) break;
+ }
+
+ if (tc->next) {
+ struct talloc_chunk *tc2 = tc->next;
+ ctx->total_alloc_size -= tc->next->size;
+ tc->next = tc->next->next;
+ free(tc2);
+ free(ptr);
+ } else {
+ DEBUG(0,("Attempt to free non-allocated chunk in context '%s'\n",
+ ctx->name));
+ }
+}
+
+
+/*
+ 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;
+}
+
+/*
+ realloc an array, checking for integer overflow in the array size
+*/
+void *talloc_realloc_array(TALLOC_CTX *ctx, void *ptr, size_t el_size, unsigned count)
+{
+ if (count == 0 ||
+ count >= MAX_TALLOC_SIZE/el_size) {
+ return NULL;
+ }
+ return talloc_realloc(ctx, ptr, el_size * count);
+}
+
/** @} */
diff --git a/source/lib/talloctort.c b/source/lib/talloctort.c
index 0cdf693bb91..9c10f4eed82 100644
--- a/source/lib/talloctort.c
+++ b/source/lib/talloctort.c
@@ -18,6 +18,10 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#error SAMBA4 clean up
+#error this file should be (re)moved
+#error and all unused stuff should go
+
#include "includes.h"
#define NCTX 10
@@ -51,9 +55,9 @@ int main(void)
}
for (i = 0; i < NCTX; i++) {
- printf("talloc@%p %-40s %ldkB\n", ctx[i],
+ printf("talloc@%p %-40s %dkB\n", ctx[i],
talloc_pool_name(ctx[i]),
- (unsigned long)talloc_pool_size(ctx[i]) >> 10);
+ talloc_pool_size(ctx[i]) >> 10);
}
printf("%s", talloc_describe_all(ctx[0]));
diff --git a/source/lib/tdb/README b/source/lib/tdb/README
new file mode 100644
index 00000000000..fac3eacb4db
--- /dev/null
+++ b/source/lib/tdb/README
@@ -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
diff --git a/source/lib/tdb/spinlock.c b/source/lib/tdb/spinlock.c
new file mode 100644
index 00000000000..1b789d4daad
--- /dev/null
+++ b/source/lib/tdb/spinlock.c
@@ -0,0 +1,481 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Anton Blanchard 2001
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) && defined(sgi) && (_COMPILER_VERSION >= 730)
+
+/* Implement spinlocks on IRIX using the MIPSPro atomic fetch operations. See
+ * sync(3) for the details of the intrinsic operations.
+ *
+ * "sgi" and "_COMPILER_VERSION" are always defined by MIPSPro.
+ */
+
+#if defined(STANDALONE)
+
+/* MIPSPro 7.3 has "__inline" as an extension, but not "inline. */
+#define inline __inline
+
+#endif /* STANDALONE */
+
+/* Returns 0 if the lock is acquired, EBUSY otherwise. */
+static inline int __spin_trylock(spinlock_t *lock)
+{
+ unsigned int val;
+ val = __lock_test_and_set(lock, 1);
+ return val == 0 ? 0 : EBUSY;
+}
+
+static inline void __spin_unlock(spinlock_t *lock)
+{
+ __lock_release(lock);
+}
+
+static inline void __spin_lock_init(spinlock_t *lock)
+{
+ __lock_release(lock);
+}
+
+/* Returns 1 if the lock is held, 0 otherwise. */
+static inline int __spin_is_locked(spinlock_t *lock)
+{
+ unsigned int val;
+ val = __add_and_fetch(lock, 0);
+ return val;
+}
+
+#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)
+{
+#if defined(HAVE_SYSCONF) && defined(SYSCONF_SC_NPROC_ONLN)
+ return (sysconf(_SC_NPROC_ONLN) > 1) ? 1 : 0;
+#else
+ return 0;
+#endif
+}
+
+/*
+ * 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 = TDB_SPINLOCK_SIZE(hash_size);
+ 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
diff --git a/source/lib/tdb/spinlock.h b/source/lib/tdb/spinlock.h
new file mode 100644
index 00000000000..967fe37457f
--- /dev/null
+++ b/source/lib/tdb/spinlock.h
@@ -0,0 +1,59 @@
+#ifndef __SPINLOCK_H__
+#define __SPINLOCK_H__
+
+#ifdef 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);
+
+#define TDB_SPINLOCK_SIZE(hash_size) (((hash_size) + 1) * sizeof(tdb_rwlock_t))
+
+#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);
+#define TDB_SPINLOCK_SIZE(hash_size) 0
+
+#endif
+
+#endif
diff --git a/source/lib/tdb/tdb.c b/source/lib/tdb/tdb.c
new file mode 100644
index 00000000000..47ba2cb52cd
--- /dev/null
+++ b/source/lib/tdb/tdb.c
@@ -0,0 +1,2090 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2004
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+/* NOTE: If you use tdbs under valgrind, and in particular if you run
+ * tdbtorture, you may get spurious "uninitialized value" warnings. I
+ * think this is because valgrind doesn't understand that the mmap'd
+ * area may be written to by other processes. Memory can, from the
+ * point of view of the grinded process, spontaneously become
+ * initialized.
+ *
+ * I can think of a few solutions. [mbp 20030311]
+ *
+ * 1 - Write suppressions for Valgrind so that it doesn't complain
+ * about this. Probably the most reasonable but people need to
+ * remember to use them.
+ *
+ * 2 - Use IO not mmap when running under valgrind. Not so nice.
+ *
+ * 3 - Use the special valgrind macros to mark memory as valid at the
+ * right time. Probably too hard -- the process just doesn't know.
+ */
+
+#ifdef STANDALONE
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include "tdb.h"
+#include "spinlock.h"
+#else
+#include "includes.h"
+#endif
+
+#define TDB_MAGIC_FOOD "TDB file\n"
+#define TDB_VERSION (0x26011967 + 6)
+#define TDB_MAGIC (0x26011999U)
+#define TDB_FREE_MAGIC (~TDB_MAGIC)
+#define TDB_DEAD_MAGIC (0xFEE1DEAD)
+#define TDB_ALIGNMENT 4
+#define MIN_REC_SIZE (2*sizeof(struct list_struct) + TDB_ALIGNMENT)
+#define DEFAULT_HASH_SIZE 131
+#define TDB_PAGE_SIZE 0x2000
+#define FREELIST_TOP (sizeof(struct tdb_header))
+#define TDB_ALIGN(x,a) (((x) + (a)-1) & ~((a)-1))
+#define TDB_BYTEREV(x) (((((x)&0xff)<<24)|((x)&0xFF00)<<8)|(((x)>>8)&0xFF00)|((x)>>24))
+#define TDB_DEAD(r) ((r)->magic == TDB_DEAD_MAGIC)
+#define TDB_BAD_MAGIC(r) ((r)->magic != TDB_MAGIC && !TDB_DEAD(r))
+#define TDB_HASH_TOP(hash) (FREELIST_TOP + (BUCKET(hash)+1)*sizeof(tdb_off))
+#define TDB_DATA_START(hash_size) (TDB_HASH_TOP(hash_size-1) + TDB_SPINLOCK_SIZE(hash_size))
+
+
+/* NB assumes there is a local variable called "tdb" that is the
+ * current context, also takes doubly-parenthesized print-style
+ * argument. */
+#define TDB_LOG(x) (tdb->log_fn?((tdb->log_fn x),0) : 0)
+
+/* lock offsets */
+#define GLOBAL_LOCK 0
+#define ACTIVE_LOCK 4
+
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#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
+
+#define BUCKET(hash) ((hash) % tdb->header.hash_size)
+TDB_DATA tdb_null;
+
+/* all contexts, to ensure no double-opens (fcntl locks don't nest!) */
+static TDB_CONTEXT *tdbs = NULL;
+
+static int tdb_munmap(TDB_CONTEXT *tdb)
+{
+ if (tdb->flags & TDB_INTERNAL)
+ return 0;
+
+#ifdef HAVE_MMAP
+ if (tdb->map_ptr) {
+ int ret = munmap(tdb->map_ptr, tdb->map_size);
+ if (ret != 0)
+ return ret;
+ }
+#endif
+ tdb->map_ptr = NULL;
+ return 0;
+}
+
+static void tdb_mmap(TDB_CONTEXT *tdb)
+{
+ if (tdb->flags & TDB_INTERNAL)
+ return;
+
+#ifdef HAVE_MMAP
+ if (!(tdb->flags & TDB_NOMMAP)) {
+ tdb->map_ptr = mmap(NULL, tdb->map_size,
+ PROT_READ|(tdb->read_only? 0:PROT_WRITE),
+ MAP_SHARED|MAP_FILE, tdb->fd, 0);
+
+ /*
+ * NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!!
+ */
+
+ if (tdb->map_ptr == MAP_FAILED) {
+ tdb->map_ptr = NULL;
+ TDB_LOG((tdb, 2, "tdb_mmap failed for size %d (%s)\n",
+ tdb->map_size, strerror(errno)));
+ }
+ } else {
+ tdb->map_ptr = NULL;
+ }
+#else
+ tdb->map_ptr = NULL;
+#endif
+}
+
+/* Endian conversion: we only ever deal with 4 byte quantities */
+static void *convert(void *buf, u32 size)
+{
+ u32 i, *p = buf;
+ for (i = 0; i < size / 4; i++)
+ p[i] = TDB_BYTEREV(p[i]);
+ return buf;
+}
+#define DOCONV() (tdb->flags & TDB_CONVERT)
+#define CONVERT(x) (DOCONV() ? convert(&x, sizeof(x)) : &x)
+
+/* the body of the database is made of one list_struct for the free space
+ plus a separate data list for each hash value */
+struct list_struct {
+ tdb_off next; /* offset of the next record in the list */
+ tdb_len rec_len; /* total byte length of record */
+ tdb_len key_len; /* byte length of key */
+ tdb_len data_len; /* byte length of data */
+ u32 full_hash; /* the full 32 bit hash of the key */
+ u32 magic; /* try to catch errors */
+ /* the following union is implied:
+ union {
+ char record[rec_len];
+ struct {
+ char key[key_len];
+ char data[data_len];
+ }
+ u32 totalsize; (tailer)
+ }
+ */
+};
+
+/***************************************************************
+ Allow a caller to set a "alarm" flag that tdb can check to abort
+ a blocking lock on SIGALRM.
+***************************************************************/
+
+static sig_atomic_t *palarm_fired;
+
+void tdb_set_lock_alarm(sig_atomic_t *palarm)
+{
+ palarm_fired = palarm;
+}
+
+/* a byte range locking function - return 0 on success
+ this functions locks/unlocks 1 byte at the specified offset.
+
+ On error, errno is also set so that errors are passed back properly
+ through tdb_open(). */
+static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset,
+ int rw_type, int lck_type, int probe)
+{
+ struct flock fl;
+ int ret;
+
+ if (tdb->flags & TDB_NOLOCK)
+ return 0;
+ if ((rw_type == F_WRLCK) && (tdb->read_only)) {
+ errno = EACCES;
+ return -1;
+ }
+
+ fl.l_type = rw_type;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = offset;
+ fl.l_len = 1;
+ fl.l_pid = 0;
+
+ do {
+ ret = fcntl(tdb->fd,lck_type,&fl);
+ if (ret == -1 && errno == EINTR && palarm_fired && *palarm_fired)
+ break;
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret == -1) {
+ if (!probe && lck_type != F_SETLK) {
+ /* Ensure error code is set for log fun to examine. */
+ if (errno == EINTR && palarm_fired && *palarm_fired)
+ tdb->ecode = TDB_ERR_LOCK_TIMEOUT;
+ else
+ tdb->ecode = TDB_ERR_LOCK;
+ TDB_LOG((tdb, 5,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d\n",
+ tdb->fd, offset, rw_type, lck_type));
+ }
+ /* Was it an alarm timeout ? */
+ if (errno == EINTR && palarm_fired && *palarm_fired) {
+ TDB_LOG((tdb, 5, "tdb_brlock timed out (fd=%d) at offset %d rw_type=%d lck_type=%d\n",
+ tdb->fd, offset, rw_type, lck_type));
+ return TDB_ERRCODE(TDB_ERR_LOCK_TIMEOUT, -1);
+ }
+ /* Otherwise - generic lock error. errno set by fcntl.
+ * EAGAIN is an expected return from non-blocking
+ * locks. */
+ if (errno != EAGAIN) {
+ TDB_LOG((tdb, 5, "tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d: %s\n",
+ tdb->fd, offset, rw_type, lck_type,
+ strerror(errno)));
+ }
+ return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+ }
+ return 0;
+}
+
+/* lock a list in the database. list -1 is the alloc list */
+static int tdb_lock(TDB_CONTEXT *tdb, int list, int ltype)
+{
+ if (list < -1 || list >= (int)tdb->header.hash_size) {
+ TDB_LOG((tdb, 0,"tdb_lock: invalid list %d for ltype=%d\n",
+ list, ltype));
+ return -1;
+ }
+ if (tdb->flags & TDB_NOLOCK)
+ return 0;
+
+ /* Since fcntl locks don't nest, we do a lock for the first one,
+ and simply bump the count for future ones */
+ if (tdb->locked[list+1].count == 0) {
+ if (!tdb->read_only && tdb->header.rwlocks) {
+ if (tdb_spinlock(tdb, list, ltype)) {
+ TDB_LOG((tdb, 0, "tdb_lock spinlock failed on list ltype=%d\n",
+ list, ltype));
+ return -1;
+ }
+ } else if (tdb_brlock(tdb,FREELIST_TOP+4*list,ltype,F_SETLKW, 0)) {
+ TDB_LOG((tdb, 0,"tdb_lock failed on list %d ltype=%d (%s)\n",
+ list, ltype, strerror(errno)));
+ return -1;
+ }
+ tdb->locked[list+1].ltype = ltype;
+ }
+ tdb->locked[list+1].count++;
+ return 0;
+}
+
+/* unlock the database: returns void because it's too late for errors. */
+ /* changed to return int it may be interesting to know there
+ has been an error --simo */
+static int tdb_unlock(TDB_CONTEXT *tdb, int list, int ltype)
+{
+ int ret = -1;
+
+ if (tdb->flags & TDB_NOLOCK)
+ return 0;
+
+ /* Sanity checks */
+ if (list < -1 || list >= (int)tdb->header.hash_size) {
+ TDB_LOG((tdb, 0, "tdb_unlock: list %d invalid (%d)\n", list, tdb->header.hash_size));
+ return ret;
+ }
+
+ if (tdb->locked[list+1].count==0) {
+ TDB_LOG((tdb, 0, "tdb_unlock: count is 0\n"));
+ return ret;
+ }
+
+ if (tdb->locked[list+1].count == 1) {
+ /* Down to last nested lock: unlock underneath */
+ if (!tdb->read_only && tdb->header.rwlocks) {
+ ret = tdb_spinunlock(tdb, list, ltype);
+ } else {
+ ret = tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK, F_SETLKW, 0);
+ }
+ } else {
+ ret = 0;
+ }
+ tdb->locked[list+1].count--;
+
+ if (ret)
+ TDB_LOG((tdb, 0,"tdb_unlock: An error occurred unlocking!\n"));
+ return ret;
+}
+
+/* This is based on the hash algorithm from gdbm */
+static u32 tdb_hash(TDB_DATA *key)
+{
+ u32 value; /* Used to compute the hash value. */
+ u32 i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++)
+ value = (value + (key->dptr[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345);
+}
+
+/* check for an out of bounds access - if it is out of bounds then
+ see if the database has been expanded by someone else and expand
+ if necessary
+ note that "len" is the minimum length needed for the db
+*/
+static int tdb_oob(TDB_CONTEXT *tdb, tdb_off len, int probe)
+{
+ struct stat st;
+ if (len <= tdb->map_size)
+ return 0;
+ if (tdb->flags & TDB_INTERNAL) {
+ if (!probe) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, 0,"tdb_oob len %d beyond internal malloc size %d\n",
+ (int)len, (int)tdb->map_size));
+ }
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+ }
+
+ if (fstat(tdb->fd, &st) == -1)
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+
+ if (st.st_size < (size_t)len) {
+ if (!probe) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, 0,"tdb_oob len %d beyond eof at %d\n",
+ (int)len, (int)st.st_size));
+ }
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+ }
+
+ /* Unmap, update size, remap */
+ if (tdb_munmap(tdb) == -1)
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+ tdb->map_size = st.st_size;
+ tdb_mmap(tdb);
+ return 0;
+}
+
+/* write a lump of data at a specified offset */
+static int tdb_write(TDB_CONTEXT *tdb, tdb_off off, void *buf, tdb_len len)
+{
+ if (tdb_oob(tdb, off + len, 0) != 0)
+ return -1;
+
+ if (tdb->map_ptr)
+ memcpy(off + (char *)tdb->map_ptr, buf, len);
+#ifdef HAVE_PWRITE
+ else if (pwrite(tdb->fd, buf, len, off) != (ssize_t)len) {
+#else
+ else if (lseek(tdb->fd, off, SEEK_SET) != off
+ || write(tdb->fd, buf, len) != (ssize_t)len) {
+#endif
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, 0,"tdb_write failed at %d len=%d (%s)\n",
+ off, len, strerror(errno)));
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+ }
+ return 0;
+}
+
+/* read a lump of data at a specified offset, maybe convert */
+static int tdb_read(TDB_CONTEXT *tdb,tdb_off off,void *buf,tdb_len len,int cv)
+{
+ if (tdb_oob(tdb, off + len, 0) != 0)
+ return -1;
+
+ if (tdb->map_ptr)
+ memcpy(buf, off + (char *)tdb->map_ptr, len);
+#ifdef HAVE_PREAD
+ else if (pread(tdb->fd, buf, len, off) != (ssize_t)len) {
+#else
+ else if (lseek(tdb->fd, off, SEEK_SET) != off
+ || read(tdb->fd, buf, len) != (ssize_t)len) {
+#endif
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, 0,"tdb_read failed at %d len=%d (%s)\n",
+ off, len, strerror(errno)));
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
+ }
+ if (cv)
+ convert(buf, len);
+ return 0;
+}
+
+/* read a lump of data, allocating the space for it */
+static char *tdb_alloc_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_len len)
+{
+ char *buf;
+
+ if (!(buf = malloc(len))) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_OOM;
+ TDB_LOG((tdb, 0,"tdb_alloc_read malloc failed len=%d (%s)\n",
+ len, strerror(errno)));
+ return TDB_ERRCODE(TDB_ERR_OOM, buf);
+ }
+ if (tdb_read(tdb, offset, buf, len, 0) == -1) {
+ SAFE_FREE(buf);
+ return NULL;
+ }
+ return buf;
+}
+
+/* read/write a tdb_off */
+static int ofs_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_off *d)
+{
+ return tdb_read(tdb, offset, (char*)d, sizeof(*d), DOCONV());
+}
+static int ofs_write(TDB_CONTEXT *tdb, tdb_off offset, tdb_off *d)
+{
+ tdb_off off = *d;
+ return tdb_write(tdb, offset, CONVERT(off), sizeof(*d));
+}
+
+/* read/write a record */
+static int rec_read(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
+{
+ if (tdb_read(tdb, offset, rec, sizeof(*rec),DOCONV()) == -1)
+ return -1;
+ if (TDB_BAD_MAGIC(rec)) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_CORRUPT;
+ TDB_LOG((tdb, 0,"rec_read bad magic 0x%x at offset=%d\n", rec->magic, offset));
+ return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
+ }
+ return tdb_oob(tdb, rec->next+sizeof(*rec), 0);
+}
+static int rec_write(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
+{
+ struct list_struct r = *rec;
+ return tdb_write(tdb, offset, CONVERT(r), sizeof(r));
+}
+
+/* read a freelist record and check for simple errors */
+static int rec_free_read(TDB_CONTEXT *tdb, tdb_off off, struct list_struct *rec)
+{
+ if (tdb_read(tdb, off, rec, sizeof(*rec),DOCONV()) == -1)
+ return -1;
+
+ if (rec->magic == TDB_MAGIC) {
+ /* this happens when a app is showdown while deleting a record - we should
+ not completely fail when this happens */
+ TDB_LOG((tdb, 0,"rec_free_read non-free magic at offset=%d - fixing\n",
+ rec->magic, off));
+ rec->magic = TDB_FREE_MAGIC;
+ if (tdb_write(tdb, off, rec, sizeof(*rec)) == -1)
+ return -1;
+ }
+
+ if (rec->magic != TDB_FREE_MAGIC) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_CORRUPT;
+ TDB_LOG((tdb, 0,"rec_free_read bad magic 0x%x at offset=%d\n",
+ rec->magic, off));
+ return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
+ }
+ if (tdb_oob(tdb, rec->next+sizeof(*rec), 0) != 0)
+ return -1;
+ return 0;
+}
+
+/* update a record tailer (must hold allocation lock) */
+static int update_tailer(TDB_CONTEXT *tdb, tdb_off offset,
+ const struct list_struct *rec)
+{
+ tdb_off totalsize;
+
+ /* Offset of tailer from record header */
+ totalsize = sizeof(*rec) + rec->rec_len;
+ return ofs_write(tdb, offset + totalsize - sizeof(tdb_off),
+ &totalsize);
+}
+
+static tdb_off tdb_dump_record(TDB_CONTEXT *tdb, tdb_off offset)
+{
+ struct list_struct rec;
+ tdb_off tailer_ofs, tailer;
+
+ if (tdb_read(tdb, offset, (char *)&rec, sizeof(rec), DOCONV()) == -1) {
+ printf("ERROR: failed to read record at %u\n", offset);
+ return 0;
+ }
+
+ printf(" rec: offset=%u next=%d rec_len=%d key_len=%d data_len=%d full_hash=0x%x magic=0x%x\n",
+ offset, rec.next, rec.rec_len, rec.key_len, rec.data_len, rec.full_hash, rec.magic);
+
+ tailer_ofs = offset + sizeof(rec) + rec.rec_len - sizeof(tdb_off);
+ if (ofs_read(tdb, tailer_ofs, &tailer) == -1) {
+ printf("ERROR: failed to read tailer at %u\n", tailer_ofs);
+ return rec.next;
+ }
+
+ if (tailer != rec.rec_len + sizeof(rec)) {
+ printf("ERROR: tailer does not match record! tailer=%u totalsize=%u\n",
+ (unsigned)tailer, (unsigned)(rec.rec_len + sizeof(rec)));
+ }
+ return rec.next;
+}
+
+static int tdb_dump_chain(TDB_CONTEXT *tdb, int i)
+{
+ tdb_off rec_ptr, top;
+
+ top = TDB_HASH_TOP(i);
+
+ if (tdb_lock(tdb, i, F_WRLCK) != 0)
+ return -1;
+
+ if (ofs_read(tdb, top, &rec_ptr) == -1)
+ return tdb_unlock(tdb, i, F_WRLCK);
+
+ if (rec_ptr)
+ printf("hash=%d\n", i);
+
+ while (rec_ptr) {
+ rec_ptr = tdb_dump_record(tdb, rec_ptr);
+ }
+
+ return tdb_unlock(tdb, i, F_WRLCK);
+}
+
+void tdb_dump_all(TDB_CONTEXT *tdb)
+{
+ int i;
+ for (i=0;i<tdb->header.hash_size;i++) {
+ tdb_dump_chain(tdb, i);
+ }
+ printf("freelist:\n");
+ tdb_dump_chain(tdb, -1);
+}
+
+int tdb_printfreelist(TDB_CONTEXT *tdb)
+{
+ int ret;
+ long total_free = 0;
+ tdb_off offset, rec_ptr;
+ struct list_struct rec;
+
+ if ((ret = tdb_lock(tdb, -1, F_WRLCK)) != 0)
+ return ret;
+
+ offset = FREELIST_TOP;
+
+ /* read in the freelist top */
+ if (ofs_read(tdb, offset, &rec_ptr) == -1) {
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return 0;
+ }
+
+ printf("freelist top=[0x%08x]\n", rec_ptr );
+ while (rec_ptr) {
+ if (tdb_read(tdb, rec_ptr, (char *)&rec, sizeof(rec), DOCONV()) == -1) {
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return -1;
+ }
+
+ if (rec.magic != TDB_FREE_MAGIC) {
+ printf("bad magic 0x%08x in free list\n", rec.magic);
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return -1;
+ }
+
+ printf("entry offset=[0x%08x], rec.rec_len = [0x%08x (%d)]\n", rec.next, rec.rec_len, rec.rec_len );
+ total_free += rec.rec_len;
+
+ /* move to the next record */
+ rec_ptr = rec.next;
+ }
+ printf("total rec_len = [0x%08x (%d)]\n", (int)total_free,
+ (int)total_free);
+
+ return tdb_unlock(tdb, -1, F_WRLCK);
+}
+
+/* Remove an element from the freelist. Must have alloc lock. */
+static int remove_from_freelist(TDB_CONTEXT *tdb, tdb_off off, tdb_off next)
+{
+ tdb_off last_ptr, i;
+
+ /* read in the freelist top */
+ last_ptr = FREELIST_TOP;
+ while (ofs_read(tdb, last_ptr, &i) != -1 && i != 0) {
+ if (i == off) {
+ /* We've found it! */
+ return ofs_write(tdb, last_ptr, &next);
+ }
+ /* Follow chain (next offset is at start of record) */
+ last_ptr = i;
+ }
+ TDB_LOG((tdb, 0,"remove_from_freelist: not on list at off=%d\n", off));
+ return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
+}
+
+/* Add an element into the freelist. Merge adjacent records if
+ neccessary. */
+static int tdb_free(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
+{
+ tdb_off right, left;
+
+ /* Allocation and tailer lock */
+ if (tdb_lock(tdb, -1, F_WRLCK) != 0)
+ return -1;
+
+ /* set an initial tailer, so if we fail we don't leave a bogus record */
+ if (update_tailer(tdb, offset, rec) != 0) {
+ TDB_LOG((tdb, 0, "tdb_free: upfate_tailer failed!\n"));
+ goto fail;
+ }
+
+ /* Look right first (I'm an Australian, dammit) */
+ right = offset + sizeof(*rec) + rec->rec_len;
+ if (right + sizeof(*rec) <= tdb->map_size) {
+ struct list_struct r;
+
+ if (tdb_read(tdb, right, &r, sizeof(r), DOCONV()) == -1) {
+ TDB_LOG((tdb, 0, "tdb_free: right read failed at %u\n", right));
+ goto left;
+ }
+
+ /* If it's free, expand to include it. */
+ if (r.magic == TDB_FREE_MAGIC) {
+ if (remove_from_freelist(tdb, right, r.next) == -1) {
+ TDB_LOG((tdb, 0, "tdb_free: right free failed at %u\n", right));
+ goto left;
+ }
+ rec->rec_len += sizeof(r) + r.rec_len;
+ }
+ }
+
+left:
+ /* Look left */
+ left = offset - sizeof(tdb_off);
+ if (left > TDB_DATA_START(tdb->header.hash_size)) {
+ struct list_struct l;
+ tdb_off leftsize;
+
+ /* Read in tailer and jump back to header */
+ if (ofs_read(tdb, left, &leftsize) == -1) {
+ TDB_LOG((tdb, 0, "tdb_free: left offset read failed at %u\n", left));
+ goto update;
+ }
+ left = offset - leftsize;
+
+ /* Now read in record */
+ if (tdb_read(tdb, left, &l, sizeof(l), DOCONV()) == -1) {
+ TDB_LOG((tdb, 0, "tdb_free: left read failed at %u (%u)\n", left, leftsize));
+ goto update;
+ }
+
+ /* If it's free, expand to include it. */
+ if (l.magic == TDB_FREE_MAGIC) {
+ if (remove_from_freelist(tdb, left, l.next) == -1) {
+ TDB_LOG((tdb, 0, "tdb_free: left free failed at %u\n", left));
+ goto update;
+ } else {
+ offset = left;
+ rec->rec_len += leftsize;
+ }
+ }
+ }
+
+update:
+ if (update_tailer(tdb, offset, rec) == -1) {
+ TDB_LOG((tdb, 0, "tdb_free: update_tailer failed at %u\n", offset));
+ goto fail;
+ }
+
+ /* Now, prepend to free list */
+ rec->magic = TDB_FREE_MAGIC;
+
+ if (ofs_read(tdb, FREELIST_TOP, &rec->next) == -1 ||
+ rec_write(tdb, offset, rec) == -1 ||
+ ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
+ TDB_LOG((tdb, 0, "tdb_free record write failed at offset=%d\n", offset));
+ goto fail;
+ }
+
+ /* And we're done. */
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return 0;
+
+ fail:
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return -1;
+}
+
+
+/* expand a file. we prefer to use ftruncate, as that is what posix
+ says to use for mmap expansion */
+static int expand_file(TDB_CONTEXT *tdb, tdb_off size, tdb_off addition)
+{
+ char buf[1024];
+#if HAVE_FTRUNCATE_EXTEND
+ if (ftruncate(tdb->fd, size+addition) != 0) {
+ TDB_LOG((tdb, 0, "expand_file ftruncate to %d failed (%s)\n",
+ size+addition, strerror(errno)));
+ return -1;
+ }
+#else
+ char b = 0;
+
+#ifdef HAVE_PWRITE
+ if (pwrite(tdb->fd, &b, 1, (size+addition) - 1) != 1) {
+#else
+ if (lseek(tdb->fd, (size+addition) - 1, SEEK_SET) != (size+addition) - 1 ||
+ write(tdb->fd, &b, 1) != 1) {
+#endif
+ TDB_LOG((tdb, 0, "expand_file to %d failed (%s)\n",
+ size+addition, strerror(errno)));
+ return -1;
+ }
+#endif
+
+ /* now fill the file with something. This ensures that the file isn't sparse, which would be
+ very bad if we ran out of disk. This must be done with write, not via mmap */
+ memset(buf, 0x42, sizeof(buf));
+ while (addition) {
+ int n = addition>sizeof(buf)?sizeof(buf):addition;
+#ifdef HAVE_PWRITE
+ int ret = pwrite(tdb->fd, buf, n, size);
+#else
+ int ret;
+ if (lseek(tdb->fd, size, SEEK_SET) != size)
+ return -1;
+ ret = write(tdb->fd, buf, n);
+#endif
+ if (ret != n) {
+ TDB_LOG((tdb, 0, "expand_file write of %d failed (%s)\n",
+ n, strerror(errno)));
+ return -1;
+ }
+ addition -= n;
+ size += n;
+ }
+ return 0;
+}
+
+
+/* expand the database at least size bytes by expanding the underlying
+ file and doing the mmap again if necessary */
+static int tdb_expand(TDB_CONTEXT *tdb, tdb_off size)
+{
+ struct list_struct rec;
+ tdb_off offset;
+
+ if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
+ TDB_LOG((tdb, 0, "lock failed in tdb_expand\n"));
+ return -1;
+ }
+
+ /* must know about any previous expansions by another process */
+ tdb_oob(tdb, tdb->map_size + 1, 1);
+
+ /* always make room for at least 10 more records, and round
+ the database up to a multiple of TDB_PAGE_SIZE */
+ size = TDB_ALIGN(tdb->map_size + size*10, TDB_PAGE_SIZE) - tdb->map_size;
+
+ if (!(tdb->flags & TDB_INTERNAL))
+ tdb_munmap(tdb);
+
+ /*
+ * We must ensure the file is unmapped before doing this
+ * to ensure consistency with systems like OpenBSD where
+ * writes and mmaps are not consistent.
+ */
+
+ /* expand the file itself */
+ if (!(tdb->flags & TDB_INTERNAL)) {
+ if (expand_file(tdb, tdb->map_size, size) != 0)
+ goto fail;
+ }
+
+ tdb->map_size += size;
+
+ if (tdb->flags & TDB_INTERNAL)
+ tdb->map_ptr = realloc(tdb->map_ptr, tdb->map_size);
+ else {
+ /*
+ * We must ensure the file is remapped before adding the space
+ * to ensure consistency with systems like OpenBSD where
+ * writes and mmaps are not consistent.
+ */
+
+ /* We're ok if the mmap fails as we'll fallback to read/write */
+ tdb_mmap(tdb);
+ }
+
+ /* form a new freelist record */
+ memset(&rec,'\0',sizeof(rec));
+ rec.rec_len = size - sizeof(rec);
+
+ /* link it into the free list */
+ offset = tdb->map_size - size;
+ if (tdb_free(tdb, offset, &rec) == -1)
+ goto fail;
+
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return 0;
+ fail:
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return -1;
+}
+
+/* allocate some space from the free list. The offset returned points
+ to a unconnected list_struct within the database with room for at
+ least length bytes of total data
+
+ 0 is returned if the space could not be allocated
+ */
+static tdb_off tdb_allocate(TDB_CONTEXT *tdb, tdb_len length,
+ struct list_struct *rec)
+{
+ tdb_off rec_ptr, last_ptr, newrec_ptr;
+ struct list_struct newrec;
+
+ memset(&newrec, '\0', sizeof(newrec));
+
+ if (tdb_lock(tdb, -1, F_WRLCK) == -1)
+ return 0;
+
+ /* Extra bytes required for tailer */
+ length += sizeof(tdb_off);
+
+ again:
+ last_ptr = FREELIST_TOP;
+
+ /* read in the freelist top */
+ if (ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1)
+ goto fail;
+
+ /* keep looking until we find a freelist record big enough */
+ while (rec_ptr) {
+ if (rec_free_read(tdb, rec_ptr, rec) == -1)
+ goto fail;
+
+ if (rec->rec_len >= length) {
+ /* found it - now possibly split it up */
+ if (rec->rec_len > length + MIN_REC_SIZE) {
+ /* Length of left piece */
+ length = TDB_ALIGN(length, TDB_ALIGNMENT);
+
+ /* Right piece to go on free list */
+ newrec.rec_len = rec->rec_len
+ - (sizeof(*rec) + length);
+ newrec_ptr = rec_ptr + sizeof(*rec) + length;
+
+ /* And left record is shortened */
+ rec->rec_len = length;
+ } else
+ newrec_ptr = 0;
+
+ /* Remove allocated record from the free list */
+ if (ofs_write(tdb, last_ptr, &rec->next) == -1)
+ goto fail;
+
+ /* Update header: do this before we drop alloc
+ lock, otherwise tdb_free() might try to
+ merge with us, thinking we're free.
+ (Thanks Jeremy Allison). */
+ rec->magic = TDB_MAGIC;
+ if (rec_write(tdb, rec_ptr, rec) == -1)
+ goto fail;
+
+ /* Did we create new block? */
+ if (newrec_ptr) {
+ /* Update allocated record tailer (we
+ shortened it). */
+ if (update_tailer(tdb, rec_ptr, rec) == -1)
+ goto fail;
+
+ /* Free new record */
+ if (tdb_free(tdb, newrec_ptr, &newrec) == -1)
+ goto fail;
+ }
+
+ /* all done - return the new record offset */
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return rec_ptr;
+ }
+ /* move to the next record */
+ last_ptr = rec_ptr;
+ rec_ptr = rec->next;
+ }
+ /* we didn't find enough space. See if we can expand the
+ database and if we can then try again */
+ if (tdb_expand(tdb, length + sizeof(*rec)) == 0)
+ goto again;
+ fail:
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return 0;
+}
+
+/* initialise a new database with a specified hash size */
+static int tdb_new_database(TDB_CONTEXT *tdb, int hash_size)
+{
+ struct tdb_header *newdb;
+ int size, ret = -1;
+
+ /* We make it up in memory, then write it out if not internal */
+ size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off);
+ if (!(newdb = calloc(size, 1)))
+ return TDB_ERRCODE(TDB_ERR_OOM, -1);
+
+ /* Fill in the header */
+ newdb->version = TDB_VERSION;
+ newdb->hash_size = hash_size;
+#ifdef USE_SPINLOCKS
+ newdb->rwlocks = size;
+#endif
+ if (tdb->flags & TDB_INTERNAL) {
+ tdb->map_size = size;
+ tdb->map_ptr = (char *)newdb;
+ memcpy(&tdb->header, newdb, sizeof(tdb->header));
+ /* Convert the `ondisk' version if asked. */
+ CONVERT(*newdb);
+ return 0;
+ }
+ if (lseek(tdb->fd, 0, SEEK_SET) == -1)
+ goto fail;
+
+ if (ftruncate(tdb->fd, 0) == -1)
+ goto fail;
+
+ /* This creates an endian-converted header, as if read from disk */
+ CONVERT(*newdb);
+ memcpy(&tdb->header, newdb, sizeof(tdb->header));
+ /* Don't endian-convert the magic food! */
+ memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
+ if (write(tdb->fd, newdb, size) != size)
+ ret = -1;
+ else
+ ret = tdb_create_rwlocks(tdb->fd, hash_size);
+
+ fail:
+ SAFE_FREE(newdb);
+ return ret;
+}
+
+/* Returns 0 on fail. On success, return offset of record, and fills
+ in rec */
+static tdb_off tdb_find(TDB_CONTEXT *tdb, TDB_DATA key, u32 hash,
+ struct list_struct *r)
+{
+ tdb_off rec_ptr;
+
+ /* read in the hash top */
+ if (ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
+ return 0;
+
+ /* keep looking until we find the right record */
+ while (rec_ptr) {
+ if (rec_read(tdb, rec_ptr, r) == -1)
+ return 0;
+
+ if (!TDB_DEAD(r) && hash==r->full_hash && key.dsize==r->key_len) {
+ char *k;
+ /* a very likely hit - read the key */
+ k = tdb_alloc_read(tdb, rec_ptr + sizeof(*r),
+ r->key_len);
+ if (!k)
+ return 0;
+
+ if (memcmp(key.dptr, k, key.dsize) == 0) {
+ SAFE_FREE(k);
+ return rec_ptr;
+ }
+ SAFE_FREE(k);
+ }
+ rec_ptr = r->next;
+ }
+ return TDB_ERRCODE(TDB_ERR_NOEXIST, 0);
+}
+
+/* If they do lockkeys, check that this hash is one they locked */
+static int tdb_keylocked(TDB_CONTEXT *tdb, u32 hash)
+{
+ u32 i;
+ if (!tdb->lockedkeys)
+ return 1;
+ for (i = 0; i < tdb->lockedkeys[0]; i++)
+ if (tdb->lockedkeys[i+1] == hash)
+ return 1;
+ return TDB_ERRCODE(TDB_ERR_NOLOCK, 0);
+}
+
+/* As tdb_find, but if you succeed, keep the lock */
+static tdb_off tdb_find_lock_hash(TDB_CONTEXT *tdb, TDB_DATA key, u32 hash, int locktype,
+ struct list_struct *rec)
+{
+ u32 rec_ptr;
+
+ if (!tdb_keylocked(tdb, hash))
+ return 0;
+ if (tdb_lock(tdb, BUCKET(hash), locktype) == -1)
+ return 0;
+ if (!(rec_ptr = tdb_find(tdb, key, hash, rec)))
+ tdb_unlock(tdb, BUCKET(hash), locktype);
+ return rec_ptr;
+}
+
+enum TDB_ERROR tdb_error(TDB_CONTEXT *tdb)
+{
+ return tdb->ecode;
+}
+
+static struct tdb_errname {
+ enum TDB_ERROR ecode; const char *estring;
+} emap[] = { {TDB_SUCCESS, "Success"},
+ {TDB_ERR_CORRUPT, "Corrupt database"},
+ {TDB_ERR_IO, "IO Error"},
+ {TDB_ERR_LOCK, "Locking error"},
+ {TDB_ERR_OOM, "Out of memory"},
+ {TDB_ERR_EXISTS, "Record exists"},
+ {TDB_ERR_NOLOCK, "Lock exists on other keys"},
+ {TDB_ERR_NOEXIST, "Record does not exist"} };
+
+/* Error string for the last tdb error */
+const char *tdb_errorstr(TDB_CONTEXT *tdb)
+{
+ u32 i;
+ for (i = 0; i < sizeof(emap) / sizeof(struct tdb_errname); i++)
+ if (tdb->ecode == emap[i].ecode)
+ return emap[i].estring;
+ return "Invalid error code";
+}
+
+/* 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.
+*/
+
+static int tdb_update_hash(TDB_CONTEXT *tdb, TDB_DATA key, u32 hash, TDB_DATA dbuf)
+{
+ struct list_struct rec;
+ tdb_off rec_ptr;
+
+ /* find entry */
+ if (!(rec_ptr = tdb_find(tdb, key, hash, &rec)))
+ return -1;
+
+ /* must be long enough key, data and tailer */
+ if (rec.rec_len < key.dsize + dbuf.dsize + sizeof(tdb_off)) {
+ tdb->ecode = TDB_SUCCESS; /* Not really an error */
+ return -1;
+ }
+
+ if (tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
+ dbuf.dptr, dbuf.dsize) == -1)
+ return -1;
+
+ if (dbuf.dsize != rec.data_len) {
+ /* update size */
+ rec.data_len = dbuf.dsize;
+ return rec_write(tdb, rec_ptr, &rec);
+ }
+
+ return 0;
+}
+
+/* find an entry in the database given a key */
+/* If an entry doesn't exist tdb_err will be set to
+ * TDB_ERR_NOEXIST. If a key has no data attached
+ * tdb_err will not be set. Both will return a
+ * zero pptr and zero dsize.
+ */
+
+TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ tdb_off rec_ptr;
+ struct list_struct rec;
+ TDB_DATA ret;
+ u32 hash;
+
+ /* find which hash bucket it is in */
+ hash = tdb_hash(&key);
+ if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec)))
+ return tdb_null;
+
+ if (rec.data_len)
+ ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
+ rec.data_len);
+ else
+ ret.dptr = NULL;
+ ret.dsize = rec.data_len;
+ tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
+ return ret;
+}
+
+/* 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
+*/
+static int tdb_exists_hash(TDB_CONTEXT *tdb, TDB_DATA key, u32 hash)
+{
+ struct list_struct rec;
+
+ if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0)
+ return 0;
+ tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
+ return 1;
+}
+
+int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ u32 hash = tdb_hash(&key);
+ return tdb_exists_hash(tdb, key, hash);
+}
+
+/* record lock stops delete underneath */
+static int lock_record(TDB_CONTEXT *tdb, tdb_off off)
+{
+ return off ? tdb_brlock(tdb, off, F_RDLCK, F_SETLKW, 0) : 0;
+}
+/*
+ Write locks override our own fcntl readlocks, so check it here.
+ Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not
+ an error to fail to get the lock here.
+*/
+
+static int write_lock_record(TDB_CONTEXT *tdb, tdb_off off)
+{
+ struct tdb_traverse_lock *i;
+ for (i = &tdb->travlocks; i; i = i->next)
+ if (i->off == off)
+ return -1;
+ return tdb_brlock(tdb, off, F_WRLCK, F_SETLK, 1);
+}
+
+/*
+ Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not
+ an error to fail to get the lock here.
+*/
+
+static int write_unlock_record(TDB_CONTEXT *tdb, tdb_off off)
+{
+ return tdb_brlock(tdb, off, F_UNLCK, F_SETLK, 0);
+}
+/* fcntl locks don't stack: avoid unlocking someone else's */
+static int unlock_record(TDB_CONTEXT *tdb, tdb_off off)
+{
+ struct tdb_traverse_lock *i;
+ u32 count = 0;
+
+ if (off == 0)
+ return 0;
+ for (i = &tdb->travlocks; i; i = i->next)
+ if (i->off == off)
+ count++;
+ return (count == 1 ? tdb_brlock(tdb, off, F_UNLCK, F_SETLKW, 0) : 0);
+}
+
+/* actually delete an entry in the database given the offset */
+static int do_delete(TDB_CONTEXT *tdb, tdb_off rec_ptr, struct list_struct*rec)
+{
+ tdb_off last_ptr, i;
+ struct list_struct lastrec;
+
+ if (tdb->read_only) return -1;
+
+ if (write_lock_record(tdb, rec_ptr) == -1) {
+ /* Someone traversing here: mark it as dead */
+ rec->magic = TDB_DEAD_MAGIC;
+ return rec_write(tdb, rec_ptr, rec);
+ }
+ if (write_unlock_record(tdb, rec_ptr) != 0)
+ return -1;
+
+ /* find previous record in hash chain */
+ if (ofs_read(tdb, TDB_HASH_TOP(rec->full_hash), &i) == -1)
+ return -1;
+ for (last_ptr = 0; i != rec_ptr; last_ptr = i, i = lastrec.next)
+ if (rec_read(tdb, i, &lastrec) == -1)
+ return -1;
+
+ /* unlink it: next ptr is at start of record. */
+ if (last_ptr == 0)
+ last_ptr = TDB_HASH_TOP(rec->full_hash);
+ if (ofs_write(tdb, last_ptr, &rec->next) == -1)
+ return -1;
+
+ /* recover the space */
+ if (tdb_free(tdb, rec_ptr, rec) == -1)
+ return -1;
+ return 0;
+}
+
+/* Uses traverse lock: 0 = finish, -1 = error, other = record offset */
+static int tdb_next_lock(TDB_CONTEXT *tdb, struct tdb_traverse_lock *tlock,
+ struct list_struct *rec)
+{
+ int want_next = (tlock->off != 0);
+
+ /* No traversal allows if you've called tdb_lockkeys() */
+ if (tdb->lockedkeys)
+ return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
+
+ /* Lock each chain from the start one. */
+ for (; tlock->hash < tdb->header.hash_size; tlock->hash++) {
+ if (tdb_lock(tdb, tlock->hash, F_WRLCK) == -1)
+ return -1;
+
+ /* No previous record? Start at top of chain. */
+ if (!tlock->off) {
+ if (ofs_read(tdb, TDB_HASH_TOP(tlock->hash),
+ &tlock->off) == -1)
+ goto fail;
+ } else {
+ /* Otherwise unlock the previous record. */
+ if (unlock_record(tdb, tlock->off) != 0)
+ goto fail;
+ }
+
+ if (want_next) {
+ /* We have offset of old record: grab next */
+ if (rec_read(tdb, tlock->off, rec) == -1)
+ goto fail;
+ tlock->off = rec->next;
+ }
+
+ /* Iterate through chain */
+ while( tlock->off) {
+ tdb_off current;
+ if (rec_read(tdb, tlock->off, rec) == -1)
+ goto fail;
+ if (!TDB_DEAD(rec)) {
+ /* Woohoo: we found one! */
+ if (lock_record(tdb, tlock->off) != 0)
+ goto fail;
+ return tlock->off;
+ }
+ /* Try to clean dead ones from old traverses */
+ current = tlock->off;
+ tlock->off = rec->next;
+ if (!tdb->read_only &&
+ do_delete(tdb, current, rec) != 0)
+ goto fail;
+ }
+ tdb_unlock(tdb, tlock->hash, F_WRLCK);
+ want_next = 0;
+ }
+ /* We finished iteration without finding anything */
+ return TDB_ERRCODE(TDB_SUCCESS, 0);
+
+ fail:
+ tlock->off = 0;
+ if (tdb_unlock(tdb, tlock->hash, F_WRLCK) != 0)
+ TDB_LOG((tdb, 0, "tdb_next_lock: On error unlock failed!\n"));
+ return -1;
+}
+
+/* traverse the entire database - calling fn(tdb, key, data) 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
+ */
+int tdb_traverse(TDB_CONTEXT *tdb, tdb_traverse_func fn, void *private)
+{
+ TDB_DATA key, dbuf;
+ struct list_struct rec;
+ struct tdb_traverse_lock tl = { NULL, 0, 0 };
+ int ret, count = 0;
+
+ /* This was in the initializaton, above, but the IRIX compiler
+ * did not like it. crh
+ */
+ tl.next = tdb->travlocks.next;
+
+ /* fcntl locks don't stack: beware traverse inside traverse */
+ tdb->travlocks.next = &tl;
+
+ /* tdb_next_lock places locks on the record returned, and its chain */
+ while ((ret = tdb_next_lock(tdb, &tl, &rec)) > 0) {
+ count++;
+ /* now read the full record */
+ key.dptr = tdb_alloc_read(tdb, tl.off + sizeof(rec),
+ rec.key_len + rec.data_len);
+ if (!key.dptr) {
+ ret = -1;
+ if (tdb_unlock(tdb, tl.hash, F_WRLCK) != 0)
+ goto out;
+ if (unlock_record(tdb, tl.off) != 0)
+ TDB_LOG((tdb, 0, "tdb_traverse: key.dptr == NULL and unlock_record failed!\n"));
+ goto out;
+ }
+ key.dsize = rec.key_len;
+ dbuf.dptr = key.dptr + rec.key_len;
+ dbuf.dsize = rec.data_len;
+
+ /* Drop chain lock, call out */
+ if (tdb_unlock(tdb, tl.hash, F_WRLCK) != 0) {
+ ret = -1;
+ goto out;
+ }
+ if (fn && fn(tdb, key, dbuf, private)) {
+ /* They want us to terminate traversal */
+ ret = count;
+ if (unlock_record(tdb, tl.off) != 0) {
+ TDB_LOG((tdb, 0, "tdb_traverse: unlock_record failed!\n"));;
+ ret = -1;
+ }
+ tdb->travlocks.next = tl.next;
+ SAFE_FREE(key.dptr);
+ return count;
+ }
+ SAFE_FREE(key.dptr);
+ }
+out:
+ tdb->travlocks.next = tl.next;
+ if (ret < 0)
+ return -1;
+ else
+ return count;
+}
+
+/* find the first entry in the database and return its key */
+TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb)
+{
+ TDB_DATA key;
+ struct list_struct rec;
+
+ /* release any old lock */
+ if (unlock_record(tdb, tdb->travlocks.off) != 0)
+ return tdb_null;
+ tdb->travlocks.off = tdb->travlocks.hash = 0;
+
+ if (tdb_next_lock(tdb, &tdb->travlocks, &rec) <= 0)
+ return tdb_null;
+ /* now read the key */
+ key.dsize = rec.key_len;
+ key.dptr =tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),key.dsize);
+ if (tdb_unlock(tdb, BUCKET(tdb->travlocks.hash), F_WRLCK) != 0)
+ TDB_LOG((tdb, 0, "tdb_firstkey: error occurred while tdb_unlocking!\n"));
+ return key;
+}
+
+/* find the next entry in the database, returning its key */
+TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA oldkey)
+{
+ u32 oldhash;
+ TDB_DATA key = tdb_null;
+ struct list_struct rec;
+ char *k = NULL;
+
+ /* Is locked key the old key? If so, traverse will be reliable. */
+ if (tdb->travlocks.off) {
+ if (tdb_lock(tdb,tdb->travlocks.hash,F_WRLCK))
+ return tdb_null;
+ if (rec_read(tdb, tdb->travlocks.off, &rec) == -1
+ || !(k = tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),
+ rec.key_len))
+ || memcmp(k, oldkey.dptr, oldkey.dsize) != 0) {
+ /* No, it wasn't: unlock it and start from scratch */
+ if (unlock_record(tdb, tdb->travlocks.off) != 0)
+ return tdb_null;
+ if (tdb_unlock(tdb, tdb->travlocks.hash, F_WRLCK) != 0)
+ return tdb_null;
+ tdb->travlocks.off = 0;
+ }
+
+ SAFE_FREE(k);
+ }
+
+ if (!tdb->travlocks.off) {
+ /* No previous element: do normal find, and lock record */
+ tdb->travlocks.off = tdb_find_lock_hash(tdb, oldkey, tdb_hash(&oldkey), F_WRLCK, &rec);
+ if (!tdb->travlocks.off)
+ return tdb_null;
+ tdb->travlocks.hash = BUCKET(rec.full_hash);
+ if (lock_record(tdb, tdb->travlocks.off) != 0) {
+ TDB_LOG((tdb, 0, "tdb_nextkey: lock_record failed (%s)!\n", strerror(errno)));
+ return tdb_null;
+ }
+ }
+ oldhash = tdb->travlocks.hash;
+
+ /* Grab next record: locks chain and returned record,
+ unlocks old record */
+ if (tdb_next_lock(tdb, &tdb->travlocks, &rec) > 0) {
+ key.dsize = rec.key_len;
+ key.dptr = tdb_alloc_read(tdb, tdb->travlocks.off+sizeof(rec),
+ key.dsize);
+ /* Unlock the chain of this new record */
+ if (tdb_unlock(tdb, tdb->travlocks.hash, F_WRLCK) != 0)
+ TDB_LOG((tdb, 0, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
+ }
+ /* Unlock the chain of old record */
+ if (tdb_unlock(tdb, BUCKET(oldhash), F_WRLCK) != 0)
+ TDB_LOG((tdb, 0, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
+ return key;
+}
+
+/* delete an entry in the database given a key */
+static int tdb_delete_hash(TDB_CONTEXT *tdb, TDB_DATA key, u32 hash)
+{
+ tdb_off rec_ptr;
+ struct list_struct rec;
+ int ret;
+
+ if (!(rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK, &rec)))
+ return -1;
+ ret = do_delete(tdb, rec_ptr, &rec);
+ if (tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK) != 0)
+ TDB_LOG((tdb, 0, "tdb_delete: WARNING tdb_unlock failed!\n"));
+ return ret;
+}
+
+int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ u32 hash = tdb_hash(&key);
+ return tdb_delete_hash(tdb, key, hash);
+}
+
+/* store an element in the database, replacing any existing element
+ with the same key
+
+ return 0 on success, -1 on failure
+*/
+int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
+{
+ struct list_struct rec;
+ u32 hash;
+ tdb_off rec_ptr;
+ char *p = NULL;
+ int ret = 0;
+
+ /* find which hash bucket it is in */
+ hash = tdb_hash(&key);
+ if (!tdb_keylocked(tdb, hash))
+ return -1;
+ if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
+ return -1;
+
+ /* check for it existing, on insert. */
+ if (flag == TDB_INSERT) {
+ if (tdb_exists_hash(tdb, key, hash)) {
+ tdb->ecode = TDB_ERR_EXISTS;
+ goto fail;
+ }
+ } else {
+ /* first try in-place update, on modify or replace. */
+ if (tdb_update_hash(tdb, key, hash, dbuf) == 0)
+ goto out;
+ if (tdb->ecode == TDB_ERR_NOEXIST &&
+ flag == TDB_MODIFY) {
+ /* if the record doesn't exist and we are in TDB_MODIFY mode then
+ we should fail the store */
+ goto fail;
+ }
+ }
+ /* reset the error code potentially set by the tdb_update() */
+ tdb->ecode = TDB_SUCCESS;
+
+ /* delete any existing record - if it doesn't exist we don't
+ care. Doing this first reduces fragmentation, and avoids
+ coalescing with `allocated' block before it's updated. */
+ if (flag != TDB_INSERT)
+ tdb_delete_hash(tdb, key, hash);
+
+ /* Copy key+value *before* allocating free space in case malloc
+ fails and we are left with a dead spot in the tdb. */
+
+ if (!(p = (char *)malloc(key.dsize + dbuf.dsize))) {
+ tdb->ecode = TDB_ERR_OOM;
+ goto fail;
+ }
+
+ memcpy(p, key.dptr, key.dsize);
+ if (dbuf.dsize)
+ memcpy(p+key.dsize, dbuf.dptr, dbuf.dsize);
+
+ /* we have to allocate some space */
+ if (!(rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec)))
+ goto fail;
+
+ /* Read hash top into next ptr */
+ if (ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)
+ goto fail;
+
+ rec.key_len = key.dsize;
+ rec.data_len = dbuf.dsize;
+ rec.full_hash = hash;
+ rec.magic = TDB_MAGIC;
+
+ /* write out and point the top of the hash chain at it */
+ if (rec_write(tdb, rec_ptr, &rec) == -1
+ || tdb_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+dbuf.dsize)==-1
+ || ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) {
+ /* Need to tdb_unallocate() here */
+ goto fail;
+ }
+ out:
+ SAFE_FREE(p);
+ tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
+ return ret;
+fail:
+ ret = -1;
+ goto out;
+}
+
+/* Attempt to append data to 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. Record must be locked before calling.
+*/
+static int tdb_append_inplace(TDB_CONTEXT *tdb, TDB_DATA key, u32 hash, TDB_DATA new_dbuf)
+{
+ struct list_struct rec;
+ tdb_off rec_ptr;
+
+ /* find entry */
+ if (!(rec_ptr = tdb_find(tdb, key, hash, &rec)))
+ return -1;
+
+ /* Append of 0 is always ok. */
+ if (new_dbuf.dsize == 0)
+ return 0;
+
+ /* must be long enough for key, old data + new data and tailer */
+ if (rec.rec_len < key.dsize + rec.data_len + new_dbuf.dsize + sizeof(tdb_off)) {
+ /* No room. */
+ tdb->ecode = TDB_SUCCESS; /* Not really an error */
+ return -1;
+ }
+
+ if (tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len + rec.data_len,
+ new_dbuf.dptr, new_dbuf.dsize) == -1)
+ return -1;
+
+ /* update size */
+ rec.data_len += new_dbuf.dsize;
+ return rec_write(tdb, rec_ptr, &rec);
+}
+
+/* Append to an entry. Create if not exist. */
+
+int tdb_append(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA new_dbuf)
+{
+ struct list_struct rec;
+ u32 hash;
+ tdb_off rec_ptr;
+ char *p = NULL;
+ int ret = 0;
+ size_t new_data_size = 0;
+
+ /* find which hash bucket it is in */
+ hash = tdb_hash(&key);
+ if (!tdb_keylocked(tdb, hash))
+ return -1;
+ if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
+ return -1;
+
+ /* first try in-place. */
+ if (tdb_append_inplace(tdb, key, hash, new_dbuf) == 0)
+ goto out;
+
+ /* reset the error code potentially set by the tdb_append_inplace() */
+ tdb->ecode = TDB_SUCCESS;
+
+ /* find entry */
+ if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) {
+ if (tdb->ecode != TDB_ERR_NOEXIST)
+ goto fail;
+
+ /* Not found - create. */
+
+ ret = tdb_store(tdb, key, new_dbuf, TDB_INSERT);
+ goto out;
+ }
+
+ new_data_size = rec.data_len + new_dbuf.dsize;
+
+ /* Copy key+old_value+value *before* allocating free space in case malloc
+ fails and we are left with a dead spot in the tdb. */
+
+ if (!(p = (char *)malloc(key.dsize + new_data_size))) {
+ tdb->ecode = TDB_ERR_OOM;
+ goto fail;
+ }
+
+ /* Copy the key in place. */
+ memcpy(p, key.dptr, key.dsize);
+
+ /* Now read the old data into place. */
+ if (rec.data_len &&
+ tdb_read(tdb, rec_ptr + sizeof(rec) + rec.key_len, p + key.dsize, rec.data_len, 0) == -1)
+ goto fail;
+
+ /* Finally append the new data. */
+ if (new_dbuf.dsize)
+ memcpy(p+key.dsize+rec.data_len, new_dbuf.dptr, new_dbuf.dsize);
+
+ /* delete any existing record - if it doesn't exist we don't
+ care. Doing this first reduces fragmentation, and avoids
+ coalescing with `allocated' block before it's updated. */
+
+ tdb_delete_hash(tdb, key, hash);
+
+ if (!(rec_ptr = tdb_allocate(tdb, key.dsize + new_data_size, &rec)))
+ goto fail;
+
+ /* Read hash top into next ptr */
+ if (ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)
+ goto fail;
+
+ rec.key_len = key.dsize;
+ rec.data_len = new_data_size;
+ rec.full_hash = hash;
+ rec.magic = TDB_MAGIC;
+
+ /* write out and point the top of the hash chain at it */
+ if (rec_write(tdb, rec_ptr, &rec) == -1
+ || tdb_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+new_data_size)==-1
+ || ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) {
+ /* Need to tdb_unallocate() here */
+ goto fail;
+ }
+
+ out:
+ SAFE_FREE(p);
+ tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
+ return ret;
+
+fail:
+ ret = -1;
+ goto out;
+}
+
+static int tdb_already_open(dev_t device,
+ ino_t ino)
+{
+ TDB_CONTEXT *i;
+
+ for (i = tdbs; i; i = i->next) {
+ if (i->device == device && i->inode == ino) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* 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, in which case errno is also set. Don't
+ try to call tdb_error or tdb_errname, just do strerror(errno).
+
+ @param name may be NULL for internal databases. */
+TDB_CONTEXT *tdb_open(const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode)
+{
+ return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL);
+}
+
+
+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)
+{
+ TDB_CONTEXT *tdb;
+ struct stat st;
+ int rev = 0, locked = 0;
+ unsigned char *vp;
+ u32 vertest;
+
+ if (!(tdb = calloc(1, sizeof *tdb))) {
+ /* Can't log this */
+ errno = ENOMEM;
+ goto fail;
+ }
+ tdb->fd = -1;
+ tdb->name = NULL;
+ tdb->map_ptr = NULL;
+ tdb->lockedkeys = NULL;
+ tdb->flags = tdb_flags;
+ tdb->open_flags = open_flags;
+ tdb->log_fn = log_fn;
+
+ if ((open_flags & O_ACCMODE) == O_WRONLY) {
+ TDB_LOG((tdb, 0, "tdb_open_ex: can't open tdb %s write-only\n",
+ name));
+ errno = EINVAL;
+ goto fail;
+ }
+
+ if (hash_size == 0)
+ hash_size = DEFAULT_HASH_SIZE;
+ if ((open_flags & O_ACCMODE) == O_RDONLY) {
+ tdb->read_only = 1;
+ /* read only databases don't do locking or clear if first */
+ tdb->flags |= TDB_NOLOCK;
+ tdb->flags &= ~TDB_CLEAR_IF_FIRST;
+ }
+
+ /* internal databases don't mmap or lock, and start off cleared */
+ if (tdb->flags & TDB_INTERNAL) {
+ tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
+ tdb->flags &= ~TDB_CLEAR_IF_FIRST;
+ if (tdb_new_database(tdb, hash_size) != 0) {
+ TDB_LOG((tdb, 0, "tdb_open_ex: tdb_new_database failed!"));
+ goto fail;
+ }
+ goto internal;
+ }
+
+ if ((tdb->fd = open(name, open_flags, mode)) == -1) {
+ TDB_LOG((tdb, 5, "tdb_open_ex: could not open file %s: %s\n",
+ name, strerror(errno)));
+ goto fail; /* errno set by open(2) */
+ }
+
+ /* ensure there is only one process initialising at once */
+ if (tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0) == -1) {
+ TDB_LOG((tdb, 0, "tdb_open_ex: failed to get global lock on %s: %s\n",
+ name, strerror(errno)));
+ goto fail; /* errno set by tdb_brlock */
+ }
+
+ /* we need to zero database if we are the only one with it open */
+ if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
+ (locked = (tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0) == 0))) {
+ open_flags |= O_CREAT;
+ if (ftruncate(tdb->fd, 0) == -1) {
+ TDB_LOG((tdb, 0, "tdb_open_ex: "
+ "failed to truncate %s: %s\n",
+ name, strerror(errno)));
+ goto fail; /* errno set by ftruncate */
+ }
+ }
+
+ if (read(tdb->fd, &tdb->header, sizeof(tdb->header)) != sizeof(tdb->header)
+ || strcmp(tdb->header.magic_food, TDB_MAGIC_FOOD) != 0
+ || (tdb->header.version != TDB_VERSION
+ && !(rev = (tdb->header.version==TDB_BYTEREV(TDB_VERSION))))) {
+ /* its not a valid database - possibly initialise it */
+ if (!(open_flags & O_CREAT) || tdb_new_database(tdb, hash_size) == -1) {
+ errno = EIO; /* ie bad format or something */
+ goto fail;
+ }
+ rev = (tdb->flags & TDB_CONVERT);
+ }
+ vp = (unsigned char *)&tdb->header.version;
+ vertest = (((u32)vp[0]) << 24) | (((u32)vp[1]) << 16) |
+ (((u32)vp[2]) << 8) | (u32)vp[3];
+ tdb->flags |= (vertest==TDB_VERSION) ? TDB_BIGENDIAN : 0;
+ if (!rev)
+ tdb->flags &= ~TDB_CONVERT;
+ else {
+ tdb->flags |= TDB_CONVERT;
+ convert(&tdb->header, sizeof(tdb->header));
+ }
+ if (fstat(tdb->fd, &st) == -1)
+ goto fail;
+
+ /* Is it already in the open list? If so, fail. */
+ if (tdb_already_open(st.st_dev, st.st_ino)) {
+ TDB_LOG((tdb, 2, "tdb_open_ex: "
+ "%s (%d,%d) is already open in this process\n",
+ name, st.st_dev, st.st_ino));
+ errno = EBUSY;
+ goto fail;
+ }
+
+ if (!(tdb->name = (char *)strdup(name))) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ tdb->map_size = st.st_size;
+ tdb->device = st.st_dev;
+ tdb->inode = st.st_ino;
+ tdb->locked = calloc(tdb->header.hash_size+1, sizeof(tdb->locked[0]));
+ if (!tdb->locked) {
+ TDB_LOG((tdb, 2, "tdb_open_ex: "
+ "failed to allocate lock structure for %s\n",
+ name));
+ errno = ENOMEM;
+ goto fail;
+ }
+ tdb_mmap(tdb);
+ if (locked) {
+ if (!tdb->read_only)
+ if (tdb_clear_spinlocks(tdb) != 0) {
+ TDB_LOG((tdb, 0, "tdb_open_ex: "
+ "failed to clear spinlock\n"));
+ goto fail;
+ }
+ if (tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0) == -1) {
+ TDB_LOG((tdb, 0, "tdb_open_ex: "
+ "failed to take ACTIVE_LOCK on %s: %s\n",
+ name, strerror(errno)));
+ goto fail;
+ }
+
+ }
+
+ /* We always need to do this if the CLEAR_IF_FIRST flag is set, even if
+ we didn't get the initial exclusive lock as we need to let all other
+ users know we're using it. */
+
+ if (tdb_flags & TDB_CLEAR_IF_FIRST) {
+ /* leave this lock in place to indicate it's in use */
+ if (tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1)
+ goto fail;
+ }
+
+
+ internal:
+ /* Internal (memory-only) databases skip all the code above to
+ * do with disk files, and resume here by releasing their
+ * global lock and hooking into the active list. */
+ if (tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0) == -1)
+ goto fail;
+ tdb->next = tdbs;
+ tdbs = tdb;
+ return tdb;
+
+ fail:
+ { int save_errno = errno;
+
+ if (!tdb)
+ return NULL;
+
+ if (tdb->map_ptr) {
+ if (tdb->flags & TDB_INTERNAL)
+ SAFE_FREE(tdb->map_ptr);
+ else
+ tdb_munmap(tdb);
+ }
+ SAFE_FREE(tdb->name);
+ if (tdb->fd != -1)
+ if (close(tdb->fd) != 0)
+ TDB_LOG((tdb, 5, "tdb_open_ex: failed to close tdb->fd on error!\n"));
+ SAFE_FREE(tdb->locked);
+ SAFE_FREE(tdb);
+ errno = save_errno;
+ return NULL;
+ }
+}
+
+/**
+ * Close a database.
+ *
+ * @returns -1 for error; 0 for success.
+ **/
+int tdb_close(TDB_CONTEXT *tdb)
+{
+ TDB_CONTEXT **i;
+ int ret = 0;
+
+ if (tdb->map_ptr) {
+ if (tdb->flags & TDB_INTERNAL)
+ SAFE_FREE(tdb->map_ptr);
+ else
+ tdb_munmap(tdb);
+ }
+ SAFE_FREE(tdb->name);
+ if (tdb->fd != -1)
+ ret = close(tdb->fd);
+ SAFE_FREE(tdb->locked);
+ SAFE_FREE(tdb->lockedkeys);
+
+ /* Remove from contexts list */
+ for (i = &tdbs; *i; i = &(*i)->next) {
+ if (*i == tdb) {
+ *i = tdb->next;
+ break;
+ }
+ }
+
+ memset(tdb, 0, sizeof(*tdb));
+ SAFE_FREE(tdb);
+
+ return ret;
+}
+
+/* lock/unlock entire database */
+int tdb_lockall(TDB_CONTEXT *tdb)
+{
+ u32 i;
+
+ /* There are no locks on read-only dbs */
+ if (tdb->read_only)
+ return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+ if (tdb->lockedkeys)
+ return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
+ for (i = 0; i < tdb->header.hash_size; i++)
+ if (tdb_lock(tdb, i, F_WRLCK))
+ break;
+
+ /* If error, release locks we have... */
+ if (i < tdb->header.hash_size) {
+ u32 j;
+
+ for ( j = 0; j < i; j++)
+ tdb_unlock(tdb, j, F_WRLCK);
+ return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
+ }
+
+ return 0;
+}
+void tdb_unlockall(TDB_CONTEXT *tdb)
+{
+ u32 i;
+ for (i=0; i < tdb->header.hash_size; i++)
+ tdb_unlock(tdb, i, F_WRLCK);
+}
+
+int tdb_lockkeys(TDB_CONTEXT *tdb, u32 number, TDB_DATA keys[])
+{
+ u32 i, j, hash;
+
+ /* Can't lock more keys if already locked */
+ if (tdb->lockedkeys)
+ return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
+ if (!(tdb->lockedkeys = malloc(sizeof(u32) * (number+1))))
+ return TDB_ERRCODE(TDB_ERR_OOM, -1);
+ /* First number in array is # keys */
+ tdb->lockedkeys[0] = number;
+
+ /* Insertion sort by bucket */
+ for (i = 0; i < number; i++) {
+ hash = tdb_hash(&keys[i]);
+ for (j = 0; j < i && BUCKET(tdb->lockedkeys[j+1]) < BUCKET(hash); j++);
+ memmove(&tdb->lockedkeys[j+2], &tdb->lockedkeys[j+1], sizeof(u32) * (i-j));
+ tdb->lockedkeys[j+1] = hash;
+ }
+ /* Finally, lock in order */
+ for (i = 0; i < number; i++)
+ if (tdb_lock(tdb, i, F_WRLCK))
+ break;
+
+ /* If error, release locks we have... */
+ if (i < number) {
+ for ( j = 0; j < i; j++)
+ tdb_unlock(tdb, j, F_WRLCK);
+ SAFE_FREE(tdb->lockedkeys);
+ return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
+ }
+ return 0;
+}
+
+/* Unlock the keys previously locked by tdb_lockkeys() */
+void tdb_unlockkeys(TDB_CONTEXT *tdb)
+{
+ u32 i;
+ if (!tdb->lockedkeys)
+ return;
+ for (i = 0; i < tdb->lockedkeys[0]; i++)
+ tdb_unlock(tdb, tdb->lockedkeys[i+1], F_WRLCK);
+ SAFE_FREE(tdb->lockedkeys);
+}
+
+/* lock/unlock one hash chain. This is meant to be used to reduce
+ contention - it cannot guarantee how many records will be locked */
+int tdb_chainlock(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ return tdb_lock(tdb, BUCKET(tdb_hash(&key)), F_WRLCK);
+}
+
+int tdb_chainunlock(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ return tdb_unlock(tdb, BUCKET(tdb_hash(&key)), F_WRLCK);
+}
+
+int tdb_chainlock_read(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ return tdb_lock(tdb, BUCKET(tdb_hash(&key)), F_RDLCK);
+}
+
+int tdb_chainunlock_read(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ return tdb_unlock(tdb, BUCKET(tdb_hash(&key)), F_RDLCK);
+}
+
+
+/* register a loging function */
+void tdb_logging_function(TDB_CONTEXT *tdb, void (*fn)(TDB_CONTEXT *, int , const char *, ...))
+{
+ tdb->log_fn = fn;
+}
+
+
+/* reopen a tdb - this can be used after a fork to ensure that we have an independent
+ seek pointer from our parent and to re-establish locks */
+int tdb_reopen(TDB_CONTEXT *tdb)
+{
+ struct stat st;
+
+ if (tdb->flags & TDB_INTERNAL)
+ return 0; /* Nothing to do. */
+ if (tdb_munmap(tdb) != 0) {
+ TDB_LOG((tdb, 0, "tdb_reopen: munmap failed (%s)\n", strerror(errno)));
+ goto fail;
+ }
+ if (close(tdb->fd) != 0)
+ TDB_LOG((tdb, 0, "tdb_reopen: WARNING closing tdb->fd failed!\n"));
+ tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0);
+ if (tdb->fd == -1) {
+ TDB_LOG((tdb, 0, "tdb_reopen: open failed (%s)\n", strerror(errno)));
+ goto fail;
+ }
+ if (fstat(tdb->fd, &st) != 0) {
+ TDB_LOG((tdb, 0, "tdb_reopen: fstat failed (%s)\n", strerror(errno)));
+ goto fail;
+ }
+ if (st.st_ino != tdb->inode || st.st_dev != tdb->device) {
+ TDB_LOG((tdb, 0, "tdb_reopen: file dev/inode has changed!\n"));
+ goto fail;
+ }
+ tdb_mmap(tdb);
+ if ((tdb->flags & TDB_CLEAR_IF_FIRST) && (tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1)) {
+ TDB_LOG((tdb, 0, "tdb_reopen: failed to obtain active lock\n"));
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ tdb_close(tdb);
+ return -1;
+}
+
+/* reopen all tdb's */
+int tdb_reopen_all(void)
+{
+ TDB_CONTEXT *tdb;
+
+ for (tdb=tdbs; tdb; tdb = tdb->next) {
+ /* Ensure no clear-if-first. */
+ tdb->flags &= ~TDB_CLEAR_IF_FIRST;
+ if (tdb_reopen(tdb) != 0)
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/source/lib/tdb/tdb.h b/source/lib/tdb/tdb.h
new file mode 100644
index 00000000000..281925068c8
--- /dev/null
+++ b/source/lib/tdb/tdb.h
@@ -0,0 +1,151 @@
+#ifndef __TDB_H__
+#define __TDB_H__
+
+/*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2004
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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_NOLOCK, TDB_ERR_LOCK_TIMEOUT,
+ TDB_ERR_NOEXIST};
+
+#ifndef u32
+#define u32 unsigned
+#endif
+
+typedef struct TDB_DATA {
+ 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 *);
+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 */
diff --git a/source/lib/tdb/tdb.magic b/source/lib/tdb/tdb.magic
new file mode 100644
index 00000000000..f5619e7327e
--- /dev/null
+++ b/source/lib/tdb/tdb.magic
@@ -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
diff --git a/source/lib/tdb/tdbutil.c b/source/lib/tdb/tdbutil.c
new file mode 100644
index 00000000000..4a4423d2ce7
--- /dev/null
+++ b/source/lib/tdb/tdbutil.c
@@ -0,0 +1,764 @@
+/*
+ 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_bystring(TDB_CONTEXT *tdb, const char *keystr, TDB_DATA data, int flags)
+{
+ TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
+
+ return tdb_store(tdb, key, data, flags);
+}
+
+/****************************************************************************
+ Fetch a buffer using a null terminated string key. Don't forget to call
+ free() on the result dptr.
+****************************************************************************/
+
+TDB_DATA tdb_fetch_bystring(TDB_CONTEXT *tdb, const char *keystr)
+{
+ TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
+
+ return tdb_fetch(tdb, key);
+}
+
+/****************************************************************************
+ Delete an entry using a null terminated string key.
+****************************************************************************/
+
+int tdb_delete_bystring(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 because it didn't exist */
+ goto err_out;
+ }
+
+ /* Start with 'old' value */
+ val = *oldval;
+
+ } else {
+ /* It worked, set return value (oldval) to tdb data */
+ *oldval = val;
+ }
+
+ /* Increment value for storage and return next time */
+ val += change_val;
+
+ if (tdb_store_int32(tdb, keystr, val) == -1)
+ goto err_out;
+
+ ret = 0;
+
+ err_out:
+
+ tdb_unlock_bystring(tdb, keystr);
+ return ret;
+}
+
+/****************************************************************************
+ Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval.
+****************************************************************************/
+
+BOOL tdb_change_uint32_atomic(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 because it didn't exist */
+ goto err_out;
+ }
+
+ /* Start with 'old' value */
+ val = *oldval;
+
+ } else {
+ /* it worked, set return value (oldval) to tdb data */
+ *oldval = val;
+
+ }
+
+ /* get a new value to store */
+ val += change_val;
+
+ if (!tdb_store_uint32(tdb, keystr, val))
+ goto err_out;
+
+ ret = True;
+
+ err_out:
+
+ tdb_unlock_bystring(tdb, keystr);
+ return ret;
+}
+
+/****************************************************************************
+ 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;
+ uint8 bt;
+ 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 'b': /* unsigned 8-bit integer */
+ len = 1;
+ bt = (uint8)va_arg(ap, int);
+ if (bufsize && bufsize >= len)
+ SSVAL(buf, 0, bt);
+ break;
+ case 'w': /* unsigned 16-bit integer */
+ len = 2;
+ w = (uint16)va_arg(ap, int);
+ if (bufsize && bufsize >= len)
+ SSVAL(buf, 0, w);
+ break;
+ case 'd': /* signed 32-bit integer (standard int in most systems) */
+ len = 4;
+ d = va_arg(ap, uint32);
+ if (bufsize && bufsize >= len)
+ SIVAL(buf, 0, d);
+ break;
+ case 'p': /* pointer */
+ len = 4;
+ p = va_arg(ap, void *);
+ d = p?1:0;
+ if (bufsize && bufsize >= len)
+ SIVAL(buf, 0, d);
+ break;
+ case 'P': /* null-terminated string */
+ s = va_arg(ap,char *);
+ w = strlen(s);
+ len = w + 1;
+ if (bufsize && bufsize >= len)
+ memcpy(buf, s, len);
+ break;
+ case 'f': /* null-terminated string */
+ s = va_arg(ap,char *);
+ w = strlen(s);
+ len = w + 1;
+ if (bufsize && bufsize >= len)
+ memcpy(buf, s, len);
+ break;
+ case 'B': /* fixed-length string */
+ i = va_arg(ap, int);
+ s = va_arg(ap, char *);
+ len = 4+i;
+ if (bufsize && bufsize >= len) {
+ SIVAL(buf, 0, i);
+ memcpy(buf+4, s, i);
+ }
+ break;
+ default:
+ DEBUG(0,("Unknown tdb_pack format %c in %s\n",
+ c, fmt));
+ len = 0;
+ break;
+ }
+
+ buf += len;
+ if (bufsize)
+ bufsize -= len;
+ if (bufsize < 0)
+ bufsize = 0;
+ }
+
+ va_end(ap);
+
+ 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;
+ uint8 *bt;
+ 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 'b':
+ len = 1;
+ bt = va_arg(ap, uint8 *);
+ if (bufsize < len)
+ goto no_space;
+ *bt = SVAL(buf, 0);
+ break;
+ 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;
+}
+
+
+/**
+ * Pack SID passed by pointer
+ *
+ * @param pack_buf pointer to buffer which is to be filled with packed data
+ * @param bufsize size of packing buffer
+ * @param sid pointer to sid to be packed
+ *
+ * @return length of the packed representation of the whole structure
+ **/
+size_t tdb_sid_pack(char* pack_buf, int bufsize, DOM_SID* sid)
+{
+ int idx;
+ size_t len = 0;
+
+ if (!sid || !pack_buf) return -1;
+
+ len += tdb_pack(pack_buf + len, bufsize - len, "bb", sid->sid_rev_num,
+ sid->num_auths);
+
+ for (idx = 0; idx < 6; idx++) {
+ len += tdb_pack(pack_buf + len, bufsize - len, "b", sid->id_auth[idx]);
+ }
+
+ for (idx = 0; idx < MAXSUBAUTHS; idx++) {
+ len += tdb_pack(pack_buf + len, bufsize - len, "d", sid->sub_auths[idx]);
+ }
+
+ return len;
+}
+
+
+/**
+ * Unpack SID into a pointer
+ *
+ * @param pack_buf pointer to buffer with packed representation
+ * @param bufsize size of the buffer
+ * @param sid pointer to sid structure to be filled with unpacked data
+ *
+ * @return size of structure unpacked from buffer
+ **/
+size_t tdb_sid_unpack(char* pack_buf, int bufsize, DOM_SID* sid)
+{
+ int idx, len = 0;
+
+ if (!sid || !pack_buf) return -1;
+
+ len += tdb_unpack(pack_buf + len, bufsize - len, "bb",
+ &sid->sid_rev_num, &sid->num_auths);
+
+ for (idx = 0; idx < 6; idx++) {
+ len += tdb_unpack(pack_buf + len, bufsize - len, "b", &sid->id_auth[idx]);
+ }
+
+ for (idx = 0; idx < MAXSUBAUTHS; idx++) {
+ len += tdb_unpack(pack_buf + len, bufsize - len, "d", &sid->sub_auths[idx]);
+ }
+
+ return len;
+}
+
+/****************************************************************************
+ 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;
+
+ 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, TDB_LIST_NODE *);
+
+ 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_key.dptr);
+ SAFE_FREE(node);
+ node = next_node;
+ }
+}
diff --git a/source/lib/dummyroot.c b/source/lib/tdb/tdbutil.h
index c8465cb791a..01473446a1c 100644
--- a/source/lib/dummyroot.c
+++ b/source/lib/tdb/tdbutil.h
@@ -1,9 +1,8 @@
/*
Unix SMB/CIFS implementation.
- RPC pipe client
-
- Copyright (C) Tim Potter 2003
-
+ 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
@@ -19,15 +18,20 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* Stupid dummy functions required due to the horrible dependency mess
- in Samba. */
+#ifndef __TDBUTIL_H__
+#define __TDBUTIL_H__
-void become_root(void)
-{
- return;
-}
-void unbecome_root(void)
+/* single node of a list returned by tdb_search_keys */
+typedef struct keys_node
{
- return;
-}
+ 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__ */
diff --git a/source/lib/time.c b/source/lib/time.c
index faca2cba879..2844da004d5 100644
--- a/source/lib/time.c
+++ b/source/lib/time.c
@@ -250,7 +250,7 @@ static int TimeZoneFaster(time_t t)
**************************************************************************/
int TimeDiff(time_t t)
{
- return TimeZoneFaster(t) + 60*extra_time_offset;
+ return TimeZoneFaster(t) + 60 * lp_time_offset();
}
@@ -263,12 +263,12 @@ int TimeDiff(time_t t)
+**************************************************************************/
static int LocTimeDiff(time_t lte)
{
- time_t lt = lte - 60*extra_time_offset;
+ 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) ^ (extra_time_offset < 0)) | ((t < lt) ^ (d < 0)))
+ 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 */
@@ -299,7 +299,7 @@ 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(NTTIME *nt)
+time_t nt_time_to_unix(const NTTIME *nt)
{
double d;
time_t ret;
@@ -308,8 +308,7 @@ time_t nt_time_to_unix(NTTIME *nt)
time_t l_time_min = TIME_T_MIN;
time_t l_time_max = TIME_T_MAX;
- if (nt->high == 0 || (nt->high == 0xffffffff && nt->low == 0xffffffff))
- return(0);
+ if (nt->high == 0) return(0);
d = ((double)nt->high)*4.0*(double)(1<<30);
d += (nt->low&0xFFF00000);
@@ -318,11 +317,8 @@ time_t nt_time_to_unix(NTTIME *nt)
/* now adjust by 369 years to make the secs since 1970 */
d -= TIME_FIXUP_CONSTANT;
- if (d <= l_time_min)
- return (l_time_min);
-
- if (d >= l_time_max)
- return (l_time_max);
+ if (!(l_time_min <= d && d <= l_time_max))
+ return(0);
ret = (time_t)(d+0.5);
@@ -375,17 +371,6 @@ time_t nt_time_to_unix_abs(NTTIME *nt)
}
/****************************************************************************
-interprets an nt time into a unix time_t
-****************************************************************************/
-time_t interpret_long_date(char *p)
-{
- NTTIME nt;
- nt.low = IVAL(p,0);
- nt.high = IVAL(p,4);
- return nt_time_to_unix(&nt);
-}
-
-/****************************************************************************
put a 8 byte filetime from a time_t
This takes real GMT as input and converts to kludge-GMT
****************************************************************************/
@@ -393,20 +378,17 @@ void unix_to_nt_time(NTTIME *nt, time_t t)
{
double d;
- if (t==0)
- {
+ if (t==0) {
nt->low = 0;
nt->high = 0;
return;
}
- if (t == TIME_T_MAX)
- {
+ if (t == TIME_T_MAX) {
nt->low = 0xffffffff;
nt->high = 0x7fffffff;
return;
}
- if (t == -1)
- {
+ if (t == -1) {
nt->low = 0xffffffff;
nt->high = 0xffffffff;
return;
@@ -465,9 +447,10 @@ void unix_to_nt_time_abs(NTTIME *nt, time_t t)
nt->low=~nt->low;
}
+
/****************************************************************************
-take a Unix time and convert to an NTTIME structure and place in buffer
-pointed to by p.
+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)
{
@@ -482,9 +465,9 @@ 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);
+ if (mtime == 0 || mtime == (time_t)0xFFFFFFFF || mtime == (time_t)-1)
+ return True;
+ return False;
}
/*******************************************************************
@@ -492,10 +475,10 @@ BOOL null_mtime(time_t mtime)
********************************************************************/
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);
+ 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;
}
/*******************************************************************
@@ -503,10 +486,10 @@ static uint16 make_dos_date1(struct tm *t)
********************************************************************/
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);
+ 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;
}
/*******************************************************************
@@ -515,17 +498,22 @@ static uint16 make_dos_time1(struct tm *t)
********************************************************************/
static uint32 make_dos_date(time_t unixdate)
{
- struct tm *t;
- uint32 ret=0;
+ struct tm *t;
+ uint32 ret=0;
- t = LocalTime(&unixdate);
- if (!t)
- return 0xFFFFFFFF;
+ 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);
+ ret = make_dos_date1(t);
+ ret = ((ret&0xFFFF)<<16) | make_dos_time1(t);
- return(ret);
+ return ret;
}
/*******************************************************************
@@ -534,8 +522,8 @@ 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);
+ uint32 x = make_dos_date(unixdate);
+ SIVAL(buf,offset,x);
}
/*******************************************************************
@@ -544,9 +532,10 @@ This takes GMT time and puts local time in the buffer
********************************************************************/
void put_dos_date2(char *buf,int offset,time_t unixdate)
{
- uint32 x = make_dos_date(unixdate);
- x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
- SIVAL(buf,offset,x);
+ uint32 x;
+ x = make_dos_date(unixdate);
+ x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+ SIVAL(buf,offset,x);
}
/*******************************************************************
@@ -556,9 +545,9 @@ 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);
+ if (!null_mtime(unixdate))
+ unixdate -= TimeDiff(unixdate);
+ SIVAL(buf,offset,unixdate);
}
/*******************************************************************
@@ -585,22 +574,22 @@ static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *ho
********************************************************************/
time_t make_unix_date(void *date_ptr)
{
- uint32 dos_date=0;
- struct tm t;
- time_t ret;
+ uint32 dos_date=0;
+ struct tm t;
+ time_t ret;
- dos_date = IVAL(date_ptr,0);
+ dos_date = IVAL(date_ptr,0);
- if (dos_date == 0) return(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;
+ 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);
+ /* mktime() also does the local to GMT time conversion for us */
+ ret = mktime(&t);
- return(ret);
+ return(ret);
}
/*******************************************************************
@@ -608,13 +597,13 @@ like make_unix_date() but the words are reversed
********************************************************************/
time_t make_unix_date2(void *date_ptr)
{
- uint32 x,x2;
+ uint32 x,x2;
- x = IVAL(date_ptr,0);
- x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
- SIVAL(&x,0,x2);
+ x = IVAL(date_ptr,0);
+ x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+ SIVAL(&x,0,x2);
- return(make_unix_date((void *)&x));
+ return make_unix_date((void *)&x);
}
/*******************************************************************
@@ -623,30 +612,32 @@ time_t make_unix_date2(void *date_ptr)
******************************************************************/
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);
+ 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(time_t t)
+char *http_timestring(TALLOC_CTX *mem_ctx, time_t t)
{
- static fstring buf;
+ char *buf;
+ fstring tempTime;
struct tm *tm = LocalTime(&t);
if (!tm)
- slprintf(buf,sizeof(buf)-1,"%ld seconds since the Epoch",(long)t);
+ buf = talloc_asprintf(mem_ctx,"%ld seconds since the Epoch",(long)t);
else
#ifndef HAVE_STRFTIME
- fstrcpy(buf, asctime(tm));
+ buf = talloc_strdup(mem_ctx, asctime(tm));
if(buf[strlen(buf)-1] == '\n')
buf[strlen(buf)-1] = 0;
#else /* !HAVE_STRFTIME */
- strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S %Z", tm);
+ 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;
}
@@ -657,9 +648,10 @@ char *http_timestring(time_t t)
Return the date and time as a string
****************************************************************************/
-char *timestring(BOOL hires)
+char *timestring(TALLOC_CTX *mem_ctx, BOOL hires)
{
- static fstring TimeBuf;
+ char *TimeBuf;
+ fstring tempTime;
struct timeval tp;
time_t t;
struct tm *tm;
@@ -673,37 +665,33 @@ char *timestring(BOOL hires)
tm = LocalTime(&t);
if (!tm) {
if (hires) {
- slprintf(TimeBuf,
- sizeof(TimeBuf)-1,
+ TimeBuf = talloc_asprintf(mem_ctx,
"%ld.%06ld seconds since the Epoch",
(long)tp.tv_sec,
(long)tp.tv_usec);
} else {
- slprintf(TimeBuf,
- sizeof(TimeBuf)-1,
+ TimeBuf = talloc_asprintf(mem_ctx,
"%ld seconds since the Epoch",
(long)t);
}
} else {
#ifdef HAVE_STRFTIME
if (hires) {
- strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm);
- slprintf(TimeBuf+strlen(TimeBuf),
- sizeof(TimeBuf)-1 - strlen(TimeBuf),
- ".%06ld",
- (long)tp.tv_usec);
+ 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(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm);
+ strftime(tempTime,100,"%Y/%m/%d %H:%M:%S",tm);
+ TimeBuf = talloc_strdup(mem_ctx, tempTime);
}
#else
if (hires) {
- slprintf(TimeBuf,
- sizeof(TimeBuf)-1,
+ TimeBuf = talloc_asprintf(mem_ctx,
"%s.%06ld",
asctime(tm),
(long)tp.tv_usec);
} else {
- fstrcpy(TimeBuf, asctime(tm));
+ TimeBuf = talloc_strdup(mem_ctx, asctime(tm));
}
#endif
}
@@ -754,3 +742,13 @@ BOOL nt_time_is_zero(NTTIME *nt)
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));
+}
+
diff --git a/source/lib/ufc.c b/source/lib/ufc.c
deleted file mode 100644
index ecc04d9e97c..00000000000
--- a/source/lib/ufc.c
+++ /dev/null
@@ -1,771 +0,0 @@
-/*
- This bit of code was derived from the UFC-crypt package which
- carries the following copyright
-
- Modified for use by Samba by Andrew Tridgell, October 1994
-
- Note that this routine is only faster on some machines. Under Linux 1.1.51
- libc 4.5.26 I actually found this routine to be slightly slower.
-
- Under SunOS I found a huge speedup by using these routines
- (a factor of 20 or so)
-
- Warning: I've had a report from Steve Kennedy <steve@gbnet.org>
- that this crypt routine may sometimes get the wrong answer. Only
- use UFC_CRYT if you really need it.
-
-*/
-
-#include "includes.h"
-
-#ifndef HAVE_CRYPT
-
-/*
- * UFC-crypt: ultra fast crypt(3) implementation
- *
- * Copyright (C) 1991-1998, Free Software Foundation, Inc.
- *
- * This 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.
- *
- * This 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 this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * @(#)crypt_util.c 2.31 02/08/92
- *
- * Support routines
- *
- */
-
-
-#ifndef long32
-#define long32 int32
-#endif
-
-#ifndef long64
-#define long64 int64
-#endif
-
-#ifndef ufc_long
-#define ufc_long unsigned
-#endif
-
-#ifndef _UFC_64_
-#define _UFC_32_
-#endif
-
-/*
- * Permutation done once on the 56 bit
- * key derived from the original 8 byte ASCII key.
- */
-static int pc1[56] = {
- 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
- 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
- 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
- 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
-};
-
-/*
- * How much to rotate each 28 bit half of the pc1 permutated
- * 56 bit key before using pc2 to give the i' key
- */
-static int rots[16] = {
- 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
-};
-
-/*
- * Permutation giving the key
- * of the i' DES round
- */
-static int pc2[48] = {
- 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
- 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
- 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
- 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
-};
-
-/*
- * The E expansion table which selects
- * bits from the 32 bit intermediate result.
- */
-static int esel[48] = {
- 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9,
- 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
- 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
- 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1
-};
-static int e_inverse[64];
-
-/*
- * Permutation done on the
- * result of sbox lookups
- */
-static int perm32[32] = {
- 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
- 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
-};
-
-/*
- * The sboxes
- */
-static int sbox[8][4][16]= {
- { { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 },
- { 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 },
- { 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0 },
- { 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 }
- },
-
- { { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 },
- { 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 },
- { 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15 },
- { 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 }
- },
-
- { { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 },
- { 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 },
- { 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7 },
- { 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 }
- },
-
- { { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 },
- { 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 },
- { 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4 },
- { 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 }
- },
-
- { { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 },
- { 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 },
- { 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14 },
- { 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 }
- },
-
- { { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 },
- { 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 },
- { 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6 },
- { 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 }
- },
-
- { { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 },
- { 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 },
- { 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2 },
- { 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 }
- },
-
- { { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 },
- { 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 },
- { 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 },
- { 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 }
- }
-};
-
-/*
- * This is the final
- * permutation matrix
- */
-static int final_perm[64] = {
- 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
- 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
- 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
- 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25
-};
-
-/*
- * The 16 DES keys in BITMASK format
- */
-#ifdef _UFC_32_
-long32 _ufc_keytab[16][2];
-#endif
-
-#ifdef _UFC_64_
-long64 _ufc_keytab[16];
-#endif
-
-
-#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.')
-#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
-
-/* Macro to set a bit (0..23) */
-#define BITMASK(i) ( (1<<(11-(i)%12+3)) << ((i)<12?16:0) )
-
-/*
- * sb arrays:
- *
- * Workhorses of the inner loop of the DES implementation.
- * They do sbox lookup, shifting of this value, 32 bit
- * permutation and E permutation for the next round.
- *
- * Kept in 'BITMASK' format.
- */
-
-#ifdef _UFC_32_
-long32 _ufc_sb0[8192], _ufc_sb1[8192], _ufc_sb2[8192], _ufc_sb3[8192];
-static long32 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3};
-#endif
-
-#ifdef _UFC_64_
-long64 _ufc_sb0[4096], _ufc_sb1[4096], _ufc_sb2[4096], _ufc_sb3[4096];
-static long64 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3};
-#endif
-
-/*
- * eperm32tab: do 32 bit permutation and E selection
- *
- * The first index is the byte number in the 32 bit value to be permuted
- * - second - is the value of this byte
- * - third - selects the two 32 bit values
- *
- * The table is used and generated internally in init_des to speed it up
- */
-static ufc_long eperm32tab[4][256][2];
-
-/*
- * do_pc1: permform pc1 permutation in the key schedule generation.
- *
- * The first index is the byte number in the 8 byte ASCII key
- * - second - - the two 28 bits halfs of the result
- * - third - selects the 7 bits actually used of each byte
- *
- * The result is kept with 28 bit per 32 bit with the 4 most significant
- * bits zero.
- */
-static ufc_long do_pc1[8][2][128];
-
-/*
- * do_pc2: permform pc2 permutation in the key schedule generation.
- *
- * The first index is the septet number in the two 28 bit intermediate values
- * - second - - - septet values
- *
- * Knowledge of the structure of the pc2 permutation is used.
- *
- * The result is kept with 28 bit per 32 bit with the 4 most significant
- * bits zero.
- */
-static ufc_long do_pc2[8][128];
-
-/*
- * efp: undo an extra e selection and do final
- * permutation giving the DES result.
- *
- * Invoked 6 bit a time on two 48 bit values
- * giving two 32 bit longs.
- */
-static ufc_long efp[16][64][2];
-
-static unsigned char bytemask[8] = {
- 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
-};
-
-static ufc_long longmask[32] = {
- 0x80000000, 0x40000000, 0x20000000, 0x10000000,
- 0x08000000, 0x04000000, 0x02000000, 0x01000000,
- 0x00800000, 0x00400000, 0x00200000, 0x00100000,
- 0x00080000, 0x00040000, 0x00020000, 0x00010000,
- 0x00008000, 0x00004000, 0x00002000, 0x00001000,
- 0x00000800, 0x00000400, 0x00000200, 0x00000100,
- 0x00000080, 0x00000040, 0x00000020, 0x00000010,
- 0x00000008, 0x00000004, 0x00000002, 0x00000001
-};
-
-
-/*
- * Silly rewrite of 'bzero'. I do so
- * because some machines don't have
- * bzero and some don't have memset.
- */
-
-static void clearmem(char *start, int cnt)
- { while(cnt--)
- *start++ = '\0';
- }
-
-static int initialized = 0;
-
-/* lookup a 6 bit value in sbox */
-
-#define s_lookup(i,s) sbox[(i)][(((s)>>4) & 0x2)|((s) & 0x1)][((s)>>1) & 0xf];
-
-/*
- * Initialize unit - may be invoked directly
- * by fcrypt users.
- */
-
-static void ufc_init_des(void)
- { int comes_from_bit;
- int bit, sg;
- ufc_long j;
- ufc_long mask1, mask2;
-
- /*
- * Create the do_pc1 table used
- * to affect pc1 permutation
- * when generating keys
- */
- for(bit = 0; bit < 56; bit++) {
- comes_from_bit = pc1[bit] - 1;
- mask1 = bytemask[comes_from_bit % 8 + 1];
- mask2 = longmask[bit % 28 + 4];
- for(j = 0; j < 128; j++) {
- if(j & mask1)
- do_pc1[comes_from_bit / 8][bit / 28][j] |= mask2;
- }
- }
-
- /*
- * Create the do_pc2 table used
- * to affect pc2 permutation when
- * generating keys
- */
- for(bit = 0; bit < 48; bit++) {
- comes_from_bit = pc2[bit] - 1;
- mask1 = bytemask[comes_from_bit % 7 + 1];
- mask2 = BITMASK(bit % 24);
- for(j = 0; j < 128; j++) {
- if(j & mask1)
- do_pc2[comes_from_bit / 7][j] |= mask2;
- }
- }
-
- /*
- * Now generate the table used to do combined
- * 32 bit permutation and e expansion
- *
- * We use it because we have to permute 16384 32 bit
- * longs into 48 bit in order to initialize sb.
- *
- * Looping 48 rounds per permutation becomes
- * just too slow...
- *
- */
-
- clearmem((char*)eperm32tab, sizeof(eperm32tab));
-
- for(bit = 0; bit < 48; bit++) {
- ufc_long inner_mask1,comes_from;
-
- comes_from = perm32[esel[bit]-1]-1;
- inner_mask1 = bytemask[comes_from % 8];
-
- for(j = 256; j--;) {
- if(j & inner_mask1)
- eperm32tab[comes_from / 8][j][bit / 24] |= BITMASK(bit % 24);
- }
- }
-
- /*
- * Create the sb tables:
- *
- * For each 12 bit segment of an 48 bit intermediate
- * result, the sb table precomputes the two 4 bit
- * values of the sbox lookups done with the two 6
- * bit halves, shifts them to their proper place,
- * sends them through perm32 and finally E expands
- * them so that they are ready for the next
- * DES round.
- *
- */
- for(sg = 0; sg < 4; sg++) {
- int j1, j2;
- int s1, s2;
-
- for(j1 = 0; j1 < 64; j1++) {
- s1 = s_lookup(2 * sg, j1);
- for(j2 = 0; j2 < 64; j2++) {
- ufc_long to_permute, inx;
-
- s2 = s_lookup(2 * sg + 1, j2);
- to_permute = ((s1 << 4) | s2) << (24 - 8 * sg);
-
-#ifdef _UFC_32_
- inx = ((j1 << 6) | j2) << 1;
- sb[sg][inx ] = eperm32tab[0][(to_permute >> 24) & 0xff][0];
- sb[sg][inx+1] = eperm32tab[0][(to_permute >> 24) & 0xff][1];
- sb[sg][inx ] |= eperm32tab[1][(to_permute >> 16) & 0xff][0];
- sb[sg][inx+1] |= eperm32tab[1][(to_permute >> 16) & 0xff][1];
- sb[sg][inx ] |= eperm32tab[2][(to_permute >> 8) & 0xff][0];
- sb[sg][inx+1] |= eperm32tab[2][(to_permute >> 8) & 0xff][1];
- sb[sg][inx ] |= eperm32tab[3][(to_permute) & 0xff][0];
- sb[sg][inx+1] |= eperm32tab[3][(to_permute) & 0xff][1];
-#endif
-#ifdef _UFC_64_
- inx = ((j1 << 6) | j2);
- sb[sg][inx] =
- ((long64)eperm32tab[0][(to_permute >> 24) & 0xff][0] << 32) |
- (long64)eperm32tab[0][(to_permute >> 24) & 0xff][1];
- sb[sg][inx] |=
- ((long64)eperm32tab[1][(to_permute >> 16) & 0xff][0] << 32) |
- (long64)eperm32tab[1][(to_permute >> 16) & 0xff][1];
- sb[sg][inx] |=
- ((long64)eperm32tab[2][(to_permute >> 8) & 0xff][0] << 32) |
- (long64)eperm32tab[2][(to_permute >> 8) & 0xff][1];
- sb[sg][inx] |=
- ((long64)eperm32tab[3][(to_permute) & 0xff][0] << 32) |
- (long64)eperm32tab[3][(to_permute) & 0xff][1];
-#endif
- }
- }
- }
-
- /*
- * Create an inverse matrix for esel telling
- * where to plug out bits if undoing it
- */
- for(bit=48; bit--;) {
- e_inverse[esel[bit] - 1 ] = bit;
- e_inverse[esel[bit] - 1 + 32] = bit + 48;
- }
-
- /*
- * create efp: the matrix used to
- * undo the E expansion and effect final permutation
- */
- clearmem((char*)efp, sizeof efp);
- for(bit = 0; bit < 64; bit++) {
- int o_bit, o_long;
- ufc_long word_value, inner_mask1, inner_mask2;
- int comes_from_f_bit, comes_from_e_bit;
- int comes_from_word, bit_within_word;
-
- /* See where bit i belongs in the two 32 bit long's */
- o_long = bit / 32; /* 0..1 */
- o_bit = bit % 32; /* 0..31 */
-
- /*
- * And find a bit in the e permutated value setting this bit.
- *
- * Note: the e selection may have selected the same bit several
- * times. By the initialization of e_inverse, we only look
- * for one specific instance.
- */
- comes_from_f_bit = final_perm[bit] - 1; /* 0..63 */
- comes_from_e_bit = e_inverse[comes_from_f_bit]; /* 0..95 */
- comes_from_word = comes_from_e_bit / 6; /* 0..15 */
- bit_within_word = comes_from_e_bit % 6; /* 0..5 */
-
- inner_mask1 = longmask[bit_within_word + 26];
- inner_mask2 = longmask[o_bit];
-
- for(word_value = 64; word_value--;) {
- if(word_value & inner_mask1)
- efp[comes_from_word][word_value][o_long] |= inner_mask2;
- }
- }
- initialized++;
- }
-
-/*
- * Process the elements of the sb table permuting the
- * bits swapped in the expansion by the current salt.
- */
-
-#ifdef _UFC_32_
-static void shuffle_sb(long32 *k, ufc_long saltbits)
- { ufc_long j;
- long32 x;
- for(j=4096; j--;) {
- x = (k[0] ^ k[1]) & (long32)saltbits;
- *k++ ^= x;
- *k++ ^= x;
- }
- }
-#endif
-
-#ifdef _UFC_64_
-static void shuffle_sb(long64 *k, ufc_long saltbits)
- { ufc_long j;
- long64 x;
- for(j=4096; j--;) {
- x = ((*k >> 32) ^ *k) & (long64)saltbits;
- *k++ ^= (x << 32) | x;
- }
- }
-#endif
-
-/*
- * Setup the unit for a new salt
- * Hopefully we'll not see a new salt in each crypt call.
- */
-
-static unsigned char current_salt[3] = "&&"; /* invalid value */
-static ufc_long current_saltbits = 0;
-static int direction = 0;
-
-static void setup_salt(const char *s1)
- { ufc_long i, j, saltbits;
- const unsigned char *s2 = (const unsigned char *)s1;
-
- if(!initialized)
- ufc_init_des();
-
- if(s2[0] == current_salt[0] && s2[1] == current_salt[1])
- return;
- current_salt[0] = s2[0]; current_salt[1] = s2[1];
-
- /*
- * This is the only crypt change to DES:
- * entries are swapped in the expansion table
- * according to the bits set in the salt.
- */
- saltbits = 0;
- for(i = 0; i < 2; i++) {
- long c=ascii_to_bin(s2[i]);
- if(c < 0 || c > 63)
- c = 0;
- for(j = 0; j < 6; j++) {
- if((c >> j) & 0x1)
- saltbits |= BITMASK(6 * i + j);
- }
- }
-
- /*
- * Permute the sb table values
- * to reflect the changed e
- * selection table
- */
- shuffle_sb(_ufc_sb0, current_saltbits ^ saltbits);
- shuffle_sb(_ufc_sb1, current_saltbits ^ saltbits);
- shuffle_sb(_ufc_sb2, current_saltbits ^ saltbits);
- shuffle_sb(_ufc_sb3, current_saltbits ^ saltbits);
-
- current_saltbits = saltbits;
- }
-
-static void ufc_mk_keytab(char *key)
- { ufc_long v1, v2, *k1;
- int i;
-#ifdef _UFC_32_
- long32 v, *k2 = &_ufc_keytab[0][0];
-#endif
-#ifdef _UFC_64_
- long64 v, *k2 = &_ufc_keytab[0];
-#endif
-
- v1 = v2 = 0; k1 = &do_pc1[0][0][0];
- for(i = 8; i--;) {
- v1 |= k1[*key & 0x7f]; k1 += 128;
- v2 |= k1[*key++ & 0x7f]; k1 += 128;
- }
-
- for(i = 0; i < 16; i++) {
- k1 = &do_pc2[0][0];
-
- v1 = (v1 << rots[i]) | (v1 >> (28 - rots[i]));
- v = k1[(v1 >> 21) & 0x7f]; k1 += 128;
- v |= k1[(v1 >> 14) & 0x7f]; k1 += 128;
- v |= k1[(v1 >> 7) & 0x7f]; k1 += 128;
- v |= k1[(v1 ) & 0x7f]; k1 += 128;
-
-#ifdef _UFC_32_
- *k2++ = v;
- v = 0;
-#endif
-#ifdef _UFC_64_
- v <<= 32;
-#endif
-
- v2 = (v2 << rots[i]) | (v2 >> (28 - rots[i]));
- v |= k1[(v2 >> 21) & 0x7f]; k1 += 128;
- v |= k1[(v2 >> 14) & 0x7f]; k1 += 128;
- v |= k1[(v2 >> 7) & 0x7f]; k1 += 128;
- v |= k1[(v2 ) & 0x7f];
-
- *k2++ = v;
- }
-
- direction = 0;
- }
-
-/*
- * Undo an extra E selection and do final permutations
- */
-
-ufc_long *_ufc_dofinalperm(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2)
- { ufc_long v1, v2, x;
- static ufc_long ary[2];
-
- x = (l1 ^ l2) & current_saltbits; l1 ^= x; l2 ^= x;
- x = (r1 ^ r2) & current_saltbits; r1 ^= x; r2 ^= x;
-
- v1=v2=0; l1 >>= 3; l2 >>= 3; r1 >>= 3; r2 >>= 3;
-
- v1 |= efp[15][ r2 & 0x3f][0]; v2 |= efp[15][ r2 & 0x3f][1];
- v1 |= efp[14][(r2 >>= 6) & 0x3f][0]; v2 |= efp[14][ r2 & 0x3f][1];
- v1 |= efp[13][(r2 >>= 10) & 0x3f][0]; v2 |= efp[13][ r2 & 0x3f][1];
- v1 |= efp[12][(r2 >>= 6) & 0x3f][0]; v2 |= efp[12][ r2 & 0x3f][1];
-
- v1 |= efp[11][ r1 & 0x3f][0]; v2 |= efp[11][ r1 & 0x3f][1];
- v1 |= efp[10][(r1 >>= 6) & 0x3f][0]; v2 |= efp[10][ r1 & 0x3f][1];
- v1 |= efp[ 9][(r1 >>= 10) & 0x3f][0]; v2 |= efp[ 9][ r1 & 0x3f][1];
- v1 |= efp[ 8][(r1 >>= 6) & 0x3f][0]; v2 |= efp[ 8][ r1 & 0x3f][1];
-
- v1 |= efp[ 7][ l2 & 0x3f][0]; v2 |= efp[ 7][ l2 & 0x3f][1];
- v1 |= efp[ 6][(l2 >>= 6) & 0x3f][0]; v2 |= efp[ 6][ l2 & 0x3f][1];
- v1 |= efp[ 5][(l2 >>= 10) & 0x3f][0]; v2 |= efp[ 5][ l2 & 0x3f][1];
- v1 |= efp[ 4][(l2 >>= 6) & 0x3f][0]; v2 |= efp[ 4][ l2 & 0x3f][1];
-
- v1 |= efp[ 3][ l1 & 0x3f][0]; v2 |= efp[ 3][ l1 & 0x3f][1];
- v1 |= efp[ 2][(l1 >>= 6) & 0x3f][0]; v2 |= efp[ 2][ l1 & 0x3f][1];
- v1 |= efp[ 1][(l1 >>= 10) & 0x3f][0]; v2 |= efp[ 1][ l1 & 0x3f][1];
- v1 |= efp[ 0][(l1 >>= 6) & 0x3f][0]; v2 |= efp[ 0][ l1 & 0x3f][1];
-
- ary[0] = v1; ary[1] = v2;
- return ary;
- }
-
-/*
- * crypt only: convert from 64 bit to 11 bit ASCII
- * prefixing with the salt
- */
-
-static char *output_conversion(ufc_long v1, ufc_long v2, const char *salt)
- { static char outbuf[14];
- int i, s;
-
- outbuf[0] = salt[0];
- outbuf[1] = salt[1] ? salt[1] : salt[0];
-
- for(i = 0; i < 5; i++)
- outbuf[i + 2] = bin_to_ascii((v1 >> (26 - 6 * i)) & 0x3f);
-
- s = (v2 & 0xf) << 2;
- v2 = (v2 >> 2) | ((v1 & 0x3) << 30);
-
- for(i = 5; i < 10; i++)
- outbuf[i + 2] = bin_to_ascii((v2 >> (56 - 6 * i)) & 0x3f);
-
- outbuf[12] = bin_to_ascii(s);
- outbuf[13] = 0;
-
- return outbuf;
- }
-
-/*
- * UNIX crypt function
- */
-
-static ufc_long *_ufc_doit(ufc_long , ufc_long, ufc_long, ufc_long, ufc_long);
-
-char *ufc_crypt(const char *key,const char *salt)
- { ufc_long *s;
- char ktab[9];
-
- /*
- * Hack DES tables according to salt
- */
- setup_salt(salt);
-
- /*
- * Setup key schedule
- */
- clearmem(ktab, sizeof ktab);
- StrnCpy(ktab, key, 8);
- ufc_mk_keytab(ktab);
-
- /*
- * Go for the 25 DES encryptions
- */
- s = _ufc_doit((ufc_long)0, (ufc_long)0,
- (ufc_long)0, (ufc_long)0, (ufc_long)25);
-
- /*
- * And convert back to 6 bit ASCII
- */
- return output_conversion(s[0], s[1], salt);
- }
-
-
-#ifdef _UFC_32_
-
-/*
- * 32 bit version
- */
-
-extern long32 _ufc_keytab[16][2];
-extern long32 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[];
-
-#define SBA(sb, v) (*(long32*)((char*)(sb)+(v)))
-
-static ufc_long *_ufc_doit(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2, ufc_long itr)
- { int i;
- long32 s, *k;
-
- while(itr--) {
- k = &_ufc_keytab[0][0];
- for(i=8; i--; ) {
- s = *k++ ^ r1;
- l1 ^= SBA(_ufc_sb1, s & 0xffff); l2 ^= SBA(_ufc_sb1, (s & 0xffff)+4);
- l1 ^= SBA(_ufc_sb0, s >>= 16); l2 ^= SBA(_ufc_sb0, (s) +4);
- s = *k++ ^ r2;
- l1 ^= SBA(_ufc_sb3, s & 0xffff); l2 ^= SBA(_ufc_sb3, (s & 0xffff)+4);
- l1 ^= SBA(_ufc_sb2, s >>= 16); l2 ^= SBA(_ufc_sb2, (s) +4);
-
- s = *k++ ^ l1;
- r1 ^= SBA(_ufc_sb1, s & 0xffff); r2 ^= SBA(_ufc_sb1, (s & 0xffff)+4);
- r1 ^= SBA(_ufc_sb0, s >>= 16); r2 ^= SBA(_ufc_sb0, (s) +4);
- s = *k++ ^ l2;
- r1 ^= SBA(_ufc_sb3, s & 0xffff); r2 ^= SBA(_ufc_sb3, (s & 0xffff)+4);
- r1 ^= SBA(_ufc_sb2, s >>= 16); r2 ^= SBA(_ufc_sb2, (s) +4);
- }
- s=l1; l1=r1; r1=s; s=l2; l2=r2; r2=s;
- }
- return _ufc_dofinalperm(l1, l2, r1, r2);
- }
-
-#endif
-
-#ifdef _UFC_64_
-
-/*
- * 64 bit version
- */
-
-extern long64 _ufc_keytab[16];
-extern long64 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[];
-
-#define SBA(sb, v) (*(long64*)((char*)(sb)+(v)))
-
-static ufc_long *_ufc_doit(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2, ufc_long itr)
- { int i;
- long64 l, r, s, *k;
-
- l = (((long64)l1) << 32) | ((long64)l2);
- r = (((long64)r1) << 32) | ((long64)r2);
-
- while(itr--) {
- k = &_ufc_keytab[0];
- for(i=8; i--; ) {
- s = *k++ ^ r;
- l ^= SBA(_ufc_sb3, (s >> 0) & 0xffff);
- l ^= SBA(_ufc_sb2, (s >> 16) & 0xffff);
- l ^= SBA(_ufc_sb1, (s >> 32) & 0xffff);
- l ^= SBA(_ufc_sb0, (s >> 48) & 0xffff);
-
- s = *k++ ^ l;
- r ^= SBA(_ufc_sb3, (s >> 0) & 0xffff);
- r ^= SBA(_ufc_sb2, (s >> 16) & 0xffff);
- r ^= SBA(_ufc_sb1, (s >> 32) & 0xffff);
- r ^= SBA(_ufc_sb0, (s >> 48) & 0xffff);
- }
- s=l; l=r; r=s;
- }
-
- l1 = l >> 32; l2 = l & 0xffffffff;
- r1 = r >> 32; r2 = r & 0xffffffff;
- return _ufc_dofinalperm(l1, l2, r1, r2);
- }
-
-#endif
-
-
-#else
- int ufc_dummy_procedure(void);
- int ufc_dummy_procedure(void) {return 0;}
-#endif
diff --git a/source/lib/username.c b/source/lib/username.c
index ac5530b5c71..2d6cd651c57 100644
--- a/source/lib/username.c
+++ b/source/lib/username.c
@@ -69,7 +69,7 @@ BOOL split_domain_and_name(const char *name, char *domain, char* username)
char *get_user_home_dir(const char *user)
{
- static struct passwd *pass;
+ struct passwd *pass;
/* Ensure the user exists. */
@@ -82,120 +82,6 @@ char *get_user_home_dir(const char *user)
return(pass->pw_dir);
}
-/*******************************************************************
- Map a username from a dos name to a unix name by looking in the username
- map. Note that this modifies the name in place.
- This is the main function that should be called *once* on
- any incoming or new username - in order to canonicalize the name.
- This is being done to de-couple the case conversions from the user mapping
- function. Previously, the map_username was being called
- every time Get_Pwnam was called.
- Returns True if username was changed, false otherwise.
-********************************************************************/
-
-BOOL map_username(char *user)
-{
- static BOOL initialised=False;
- static fstring last_from,last_to;
- XFILE *f;
- char *mapfile = lp_username_map();
- char *s;
- pstring buf;
- BOOL mapped_user = False;
-
- if (!*user)
- return False;
-
- if (!*mapfile)
- return False;
-
- if (!initialised) {
- *last_from = *last_to = 0;
- initialised = True;
- }
-
- if (strequal(user,last_to))
- return False;
-
- if (strequal(user,last_from)) {
- DEBUG(3,("Mapped user %s to %s\n",user,last_to));
- fstrcpy(user,last_to);
- return True;
- }
-
- f = x_fopen(mapfile,O_RDONLY, 0);
- if (!f) {
- DEBUG(0,("can't open username map %s. Error %s\n",mapfile, strerror(errno) ));
- return False;
- }
-
- DEBUG(4,("Scanning username map %s\n",mapfile));
-
- while((s=fgets_slash(buf,sizeof(buf),f))!=NULL) {
- char *unixname = s;
- char *dosname = strchr_m(unixname,'=');
- char **dosuserlist;
- BOOL return_if_mapped = False;
-
- if (!dosname)
- continue;
-
- *dosname++ = 0;
-
- while (isspace((int)*unixname))
- unixname++;
-
- if ('!' == *unixname) {
- return_if_mapped = True;
- unixname++;
- while (*unixname && isspace((int)*unixname))
- unixname++;
- }
-
- if (!*unixname || strchr_m("#;",*unixname))
- continue;
-
- {
- int l = strlen(unixname);
- while (l && isspace((int)unixname[l-1])) {
- unixname[l-1] = 0;
- l--;
- }
- }
-
- dosuserlist = str_list_make(dosname, NULL);
- if (!dosuserlist) {
- DEBUG(0,("Unable to build user list\n"));
- return False;
- }
-
- if (strchr_m(dosname,'*') || user_in_list(user, (const char **)dosuserlist, NULL, 0)) {
- DEBUG(3,("Mapped user %s to %s\n",user,unixname));
- mapped_user = True;
- fstrcpy(last_from,user);
- sscanf(unixname,"%s",user);
- fstrcpy(last_to,user);
- if(return_if_mapped) {
- str_list_free (&dosuserlist);
- x_fclose(f);
- return True;
- }
- }
-
- str_list_free (&dosuserlist);
- }
-
- x_fclose(f);
-
- /*
- * Setup the last_from and last_to as an optimization so
- * that we don't scan the file again for the same user.
- */
- fstrcpy(last_from,user);
- fstrcpy(last_to,user);
-
- return mapped_user;
-}
/****************************************************************************
* A wrapper for sys_getpwnam(). The following variations are tried:
@@ -219,7 +105,7 @@ static struct passwd *Get_Pwnam_internals(const char *user, char *user2)
/* Try in all lower case first as this is the most
common case on UNIX systems */
- strlower_m(user2);
+ strlower(user2);
DEBUG(5,("Trying _Get_Pwnam(), username as lowercase is %s\n",user2));
ret = getpwnam_alloc(user2);
if(ret)
@@ -234,7 +120,7 @@ static struct passwd *Get_Pwnam_internals(const char *user, char *user2)
}
/* Try as uppercase, if username wasn't originally uppercase */
- strupper_m(user2);
+ strupper(user2);
if(strcmp(user, user2) != 0) {
DEBUG(5,("Trying _Get_Pwnam(), username as uppercase is %s\n", user2));
ret = getpwnam_alloc(user2);
@@ -243,7 +129,7 @@ static struct passwd *Get_Pwnam_internals(const char *user, char *user2)
}
/* Try all combinations up to usernamelevel */
- strlower_m(user2);
+ 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());
@@ -283,11 +169,6 @@ struct passwd *Get_Pwnam(const char *user)
fstring user2;
struct passwd *ret;
- if ( *user == '\0' ) {
- DEBUG(10,("Get_Pwnam: empty username!\n"));
- return NULL;
- }
-
fstrcpy(user2, user);
DEBUG(5,("Finding user %s\n", user));
@@ -298,61 +179,16 @@ struct passwd *Get_Pwnam(const char *user)
}
/****************************************************************************
- Check if a user is in a netgroup user list. If at first we don't succeed,
- try lower case.
-****************************************************************************/
-
-static BOOL user_in_netgroup_list(const char *user, const char *ngname)
-{
-#ifdef HAVE_NETGROUP
- static char *mydomain = NULL;
- fstring lowercase_user, lowercase_ngname;
-
- 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);
-
- /*
- * Ok, innetgr is case sensitive. Try once more with lowercase
- * just in case. Attempt to fix #703. JRA.
- */
-
- fstrcpy(lowercase_user, user);
- strlower_m(lowercase_user);
- fstrcpy(lowercase_ngname, ngname);
- strlower_m(lowercase_ngname);
-
- if (innetgr(lowercase_ngname, NULL, lowercase_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;
- static gid_t *groups = NULL;
- static int num_groups = 0;
- static fstring last_user = "";
*winbind_answered = False;
@@ -362,7 +198,7 @@ static BOOL user_in_winbind_group_list(const char *user, const char *gname, BOOL
goto err;
}
- if (!lp_idmap_gid(&gid_low, &gid_high)) {
+ 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;
}
@@ -372,44 +208,27 @@ static BOOL user_in_winbind_group_list(const char *user, const char *gname, BOOL
goto err;
}
- /* try to user the last user we looked up */
- /* otherwise fall back to lookups */
-
- if ( !strequal( last_user, user ) || !groups )
- {
- /* clear any cached information */
-
- SAFE_FREE(groups);
- fstrcpy( last_user, "" );
-
- /*
- * Get the gid's that this user belongs to.
- */
+ /*
+ * Get the gid's that this user belongs to.
+ */
- if ((num_groups = winbind_getgroups(user, &groups)) == -1)
- return False;
-
- if ( num_groups == -1 )
- return False;
+ if ((num_groups = winbind_getgroups(user, 0, NULL)) == -1)
+ return False;
- if ( num_groups == 0 ) {
- *winbind_answered = True;
- return False;
- }
-
- /* save the last username */
-
- fstrcpy( last_user, user );
-
- }
- else
- DEBUG(10,("user_in_winbind_group_list: using cached user groups for [%s]\n", user));
+ if (num_groups == 0) {
+ *winbind_answered = True;
+ return False;
+ }
- if ( DEBUGLEVEL >= 10 ) {
- DEBUG(10,("user_in_winbind_group_list: using groups -- "));
- for ( i=0; i<num_groups; i++ )
- DEBUGADD(10,("%lu ", (unsigned long)groups[i]));
- DEBUGADD(10,("\n"));
+ 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;
}
/*
@@ -438,12 +257,12 @@ static BOOL user_in_winbind_group_list(const char *user, const char *gname, BOOL
/****************************************************************************
Check if a user is in a UNIX group.
****************************************************************************/
-
-BOOL user_in_unix_group_list(const char *user,const char *gname)
+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));
@@ -452,10 +271,12 @@ BOOL user_in_unix_group_list(const char *user,const char *gname)
* 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(pass->pw_gid))) {
+ if (strequal(gname,gidtoname(mem_ctx, pass->pw_gid))) {
DEBUG(10,("user_in_unix_group_list: group %s is primary group.\n", gname ));
- return True;
+ goto exit;
}
}
@@ -470,19 +291,22 @@ BOOL user_in_unix_group_list(const char *user,const char *gname)
user, member->unix_name ));
if (strequal(member->unix_name,user)) {
free_userlist(user_list);
- return(True);
+ 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.
****************************************************************************/
-
-BOOL user_in_group_list(const char *user, const char *gname, gid_t *groups, size_t n_groups)
+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;
@@ -545,8 +369,6 @@ BOOL user_in_list(const char *user,const char **list, gid_t *groups, size_t n_gr
* 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 == '+') {
@@ -557,9 +379,6 @@ BOOL user_in_list(const char *user,const char **list, gid_t *groups, size_t n_gr
*/
if(user_in_group_list(user, *list +2, groups, n_groups))
return True;
- if(user_in_netgroup_list(user, *list +2))
- return True;
-
} else {
/*
@@ -576,16 +395,8 @@ BOOL user_in_list(const char *user,const char **list, gid_t *groups, size_t n_gr
/*
* 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)) {
/*
@@ -611,16 +422,10 @@ BOOL user_in_list(const char *user,const char **list, gid_t *groups, size_t n_gr
fstrcpy(domain, *list);
domain[PTR_DIFF(p, *list)] = 0;
- /* Check to see if name is a Windows group; Win2k native mode DCs
- will return domain local groups; while NT4 or mixed mode 2k DCs
- will not */
-
- if ( winbind_lookup_name(domain, groupname, &g_sid, &name_type)
- && ( name_type==SID_NAME_DOM_GRP ||
- (strequal(lp_workgroup(), domain) && name_type==SID_NAME_ALIAS) ) )
- {
+ /* 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 */
+ /* Check if user name is in the Windows group */
ret = user_in_winbind_group_list(user, *list, &winbind_answered);
if (winbind_answered && ret == True) {
diff --git a/source/lib/util.c b/source/lib/util.c
index 3f57048a00b..0cb5258a645 100644
--- a/source/lib/util.c
+++ b/source/lib/util.c
@@ -4,7 +4,8 @@
Copyright (C) Andrew Tridgell 1992-1998
Copyright (C) Jeremy Allison 2001-2002
Copyright (C) Simo Sorce 2001
- Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+ Copyright (C) Anthony Liguori 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
@@ -23,257 +24,6 @@
#include "includes.h"
-#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
-#ifdef WITH_NISPLUS_HOME
-#ifdef BROKEN_NISPLUS_INCLUDE_FILES
-/*
- * The following lines are needed due to buggy include files
- * in Solaris 2.6 which define GROUP in both /usr/include/sys/acl.h and
- * also in /usr/include/rpcsvc/nis.h. The definitions conflict. JRA.
- * Also GROUP_OBJ is defined as 0x4 in /usr/include/sys/acl.h and as
- * an enum in /usr/include/rpcsvc/nis.h.
- */
-
-#if defined(GROUP)
-#undef GROUP
-#endif
-
-#if defined(GROUP_OBJ)
-#undef GROUP_OBJ
-#endif
-
-#endif /* BROKEN_NISPLUS_INCLUDE_FILES */
-
-#include <rpcsvc/nis.h>
-
-#else /* !WITH_NISPLUS_HOME */
-
-#include "rpcsvc/ypclnt.h"
-
-#endif /* WITH_NISPLUS_HOME */
-#endif /* HAVE_NETGROUP && WITH_AUTOMOUNT */
-
-int Protocol = PROTOCOL_COREPLUS;
-
-/* a default finfo structure to ensure all fields are sensible */
-file_info def_finfo = {-1,0,0,0,0,0,0,"",""};
-
-/* this is used by the chaining code */
-int chain_size = 0;
-
-int trans_num = 0;
-
-/*
- case handling on filenames
-*/
-int case_default = CASE_LOWER;
-
-/* the following control case operations - they are put here so the
- client can link easily */
-BOOL case_sensitive;
-BOOL case_preserve;
-BOOL use_mangled_map = False;
-BOOL short_case_preserve;
-BOOL case_mangle;
-
-static enum remote_arch_types ra_type = RA_UNKNOWN;
-pstring user_socket_options=DEFAULT_SOCKET_OPTIONS;
-
-/***********************************************************************
- Definitions for all names.
-***********************************************************************/
-
-static char *smb_myname;
-static char *smb_myworkgroup;
-static char *smb_scope;
-static int smb_num_netbios_names;
-static char **smb_my_netbios_names;
-
-/***********************************************************************
- Allocate and set myname. Ensure upper case.
-***********************************************************************/
-
-BOOL set_global_myname(const char *myname)
-{
- SAFE_FREE(smb_myname);
- smb_myname = strdup(myname);
- if (!smb_myname)
- return False;
- strupper_m(smb_myname);
- return True;
-}
-
-const char *global_myname(void)
-{
- return smb_myname;
-}
-
-/***********************************************************************
- Allocate and set myworkgroup. Ensure upper case.
-***********************************************************************/
-
-BOOL set_global_myworkgroup(const char *myworkgroup)
-{
- SAFE_FREE(smb_myworkgroup);
- smb_myworkgroup = strdup(myworkgroup);
- if (!smb_myworkgroup)
- return False;
- strupper_m(smb_myworkgroup);
- return True;
-}
-
-const char *lp_workgroup(void)
-{
- return smb_myworkgroup;
-}
-
-/***********************************************************************
- Allocate and set scope. Ensure upper case.
-***********************************************************************/
-
-BOOL set_global_scope(const char *scope)
-{
- SAFE_FREE(smb_scope);
- smb_scope = strdup(scope);
- if (!smb_scope)
- return False;
- strupper_m(smb_scope);
- return True;
-}
-
-/*********************************************************************
- Ensure scope is never null string.
-*********************************************************************/
-
-const char *global_scope(void)
-{
- if (!smb_scope)
- set_global_scope("");
- return smb_scope;
-}
-
-static void free_netbios_names_array(void)
-{
- int i;
-
- for (i = 0; i < smb_num_netbios_names; i++)
- SAFE_FREE(smb_my_netbios_names[i]);
-
- SAFE_FREE(smb_my_netbios_names);
- smb_num_netbios_names = 0;
-}
-
-static BOOL allocate_my_netbios_names_array(size_t number)
-{
- free_netbios_names_array();
-
- smb_num_netbios_names = number + 1;
- smb_my_netbios_names = (char **)malloc( sizeof(char *) * smb_num_netbios_names );
-
- if (!smb_my_netbios_names)
- return False;
-
- memset(smb_my_netbios_names, '\0', sizeof(char *) * smb_num_netbios_names);
- return True;
-}
-
-static BOOL set_my_netbios_names(const char *name, int i)
-{
- SAFE_FREE(smb_my_netbios_names[i]);
-
- smb_my_netbios_names[i] = strdup(name);
- if (!smb_my_netbios_names[i])
- return False;
- strupper_m(smb_my_netbios_names[i]);
- return True;
-}
-
-const char *my_netbios_names(int i)
-{
- return smb_my_netbios_names[i];
-}
-
-BOOL set_netbios_aliases(const char **str_array)
-{
- size_t namecount;
-
- /* Work out the max number of netbios aliases that we have */
- for( namecount=0; str_array && (str_array[namecount] != NULL); namecount++ )
- ;
-
- if ( global_myname() && *global_myname())
- namecount++;
-
- /* Allocate space for the netbios aliases */
- if (!allocate_my_netbios_names_array(namecount))
- return False;
-
- /* Use the global_myname string first */
- namecount=0;
- if ( global_myname() && *global_myname()) {
- set_my_netbios_names( global_myname(), namecount );
- namecount++;
- }
-
- if (str_array) {
- size_t i;
- for ( i = 0; str_array[i] != NULL; i++) {
- size_t n;
- BOOL duplicate = False;
-
- /* Look for duplicates */
- for( n=0; n<namecount; n++ ) {
- if( strequal( str_array[i], my_netbios_names(n) ) ) {
- duplicate = True;
- break;
- }
- }
- if (!duplicate) {
- if (!set_my_netbios_names(str_array[i], namecount))
- return False;
- namecount++;
- }
- }
- }
- return True;
-}
-
-/****************************************************************************
- Common name initialization code.
-****************************************************************************/
-
-BOOL init_names(void)
-{
- extern fstring local_machine;
- char *p;
- int n;
-
- if (global_myname() == NULL || *global_myname() == '\0') {
- if (!set_global_myname(myhostname())) {
- DEBUG( 0, ( "init_structs: malloc fail.\n" ) );
- return False;
- }
- }
-
- if (!set_netbios_aliases(lp_netbios_aliases())) {
- DEBUG( 0, ( "init_structs: malloc fail.\n" ) );
- return False;
- }
-
- fstrcpy( local_machine, global_myname() );
- trim_char( local_machine, ' ', ' ' );
- p = strchr( local_machine, ' ' );
- if (p)
- *p = 0;
- strlower_m( local_machine );
-
- DEBUG( 5, ("Netbios name list:-\n") );
- for( n=0; my_netbios_names(n); n++ )
- DEBUGADD( 5, ( "my_netbios_names[%d]=\"%s\"\n", n, my_netbios_names(n) ) );
-
- return( True );
-}
-
/**************************************************************************n
Find a suitable temporary directory. The result should be copied immediately
as it may be overwritten by a subsequent call.
@@ -305,61 +55,6 @@ BOOL in_group(gid_t group, gid_t current_gid, int ngroups, const gid_t *groups)
return(False);
}
-/****************************************************************************
- Like atoi but gets the value up to the separator character.
-****************************************************************************/
-
-static const char *Atoic(const char *p, int *n, const char *c)
-{
- if (!isdigit((int)*p)) {
- DEBUG(5, ("Atoic: malformed number\n"));
- return NULL;
- }
-
- (*n) = atoi(p);
-
- while ((*p) && isdigit((int)*p))
- p++;
-
- if (strchr_m(c, *p) == NULL) {
- DEBUG(5, ("Atoic: no separator characters (%s) not found\n", c));
- return NULL;
- }
-
- return p;
-}
-
-/*************************************************************************
- Reads a list of numbers.
- *************************************************************************/
-
-const char *get_numlist(const char *p, uint32 **num, int *count)
-{
- int val;
-
- if (num == NULL || count == NULL)
- return NULL;
-
- (*count) = 0;
- (*num ) = NULL;
-
- while ((p = Atoic(p, &val, ":,")) != NULL && (*p) != ':') {
- uint32 *tn;
-
- tn = Realloc((*num), ((*count)+1) * sizeof(uint32));
- if (tn == NULL) {
- SAFE_FREE(*num);
- return NULL;
- } else
- (*num) = tn;
- (*num)[(*count)] = val;
- (*count)++;
- p++;
- }
-
- return p;
-}
-
/*******************************************************************
Check if a file exists - call vfs_file_exist for samba files.
********************************************************************/
@@ -414,7 +109,6 @@ BOOL directory_exist(char *dname,SMB_STRUCT_STAT *st)
/*******************************************************************
Returns the size in bytes of the named file.
********************************************************************/
-
SMB_OFF_T get_file_size(char *file_name)
{
SMB_STRUCT_STAT buf;
@@ -425,222 +119,8 @@ SMB_OFF_T get_file_size(char *file_name)
}
/*******************************************************************
- Return a string representing an attribute for a file.
-********************************************************************/
-
-char *attrib_string(uint16 mode)
-{
- static fstring attrstr;
-
- attrstr[0] = 0;
-
- if (mode & aVOLID) fstrcat(attrstr,"V");
- if (mode & aDIR) fstrcat(attrstr,"D");
- if (mode & aARCH) fstrcat(attrstr,"A");
- if (mode & aHIDDEN) fstrcat(attrstr,"H");
- if (mode & aSYSTEM) fstrcat(attrstr,"S");
- if (mode & aRONLY) fstrcat(attrstr,"R");
-
- return(attrstr);
-}
-
-/*******************************************************************
- Show a smb message structure.
-********************************************************************/
-
-void show_msg(char *buf)
-{
- int i;
- int bcc=0;
-
- if (!DEBUGLVL(5))
- return;
-
- DEBUG(5,("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\nsmb_flg=%d\nsmb_flg2=%d\n",
- smb_len(buf),
- (int)CVAL(buf,smb_com),
- (int)CVAL(buf,smb_rcls),
- (int)CVAL(buf,smb_reh),
- (int)SVAL(buf,smb_err),
- (int)CVAL(buf,smb_flg),
- (int)SVAL(buf,smb_flg2)));
- DEBUGADD(5,("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\n",
- (int)SVAL(buf,smb_tid),
- (int)SVAL(buf,smb_pid),
- (int)SVAL(buf,smb_uid),
- (int)SVAL(buf,smb_mid)));
- DEBUGADD(5,("smt_wct=%d\n",(int)CVAL(buf,smb_wct)));
-
- for (i=0;i<(int)CVAL(buf,smb_wct);i++)
- DEBUGADD(5,("smb_vwv[%2d]=%5d (0x%X)\n",i,
- SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i)));
-
- bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct)));
-
- DEBUGADD(5,("smb_bcc=%d\n",bcc));
-
- if (DEBUGLEVEL < 10)
- return;
-
- if (DEBUGLEVEL < 50)
- bcc = MIN(bcc, 512);
-
- dump_data(10, smb_buf(buf), bcc);
-}
-
-/*******************************************************************
- Set the length and marker of an smb packet.
-********************************************************************/
-
-void smb_setlen(char *buf,int len)
-{
- _smb_setlen(buf,len);
-
- SCVAL(buf,4,0xFF);
- SCVAL(buf,5,'S');
- SCVAL(buf,6,'M');
- SCVAL(buf,7,'B');
-}
-
-/*******************************************************************
- Setup the word count and byte count for a smb message.
-********************************************************************/
-
-int set_message(char *buf,int num_words,int num_bytes,BOOL zero)
-{
- if (zero)
- memset(buf + smb_size,'\0',num_words*2 + num_bytes);
- SCVAL(buf,smb_wct,num_words);
- SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
- smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
- return (smb_size + num_words*2 + num_bytes);
-}
-
-/*******************************************************************
- Setup only the byte count for a smb message.
-********************************************************************/
-
-int set_message_bcc(char *buf,int num_bytes)
-{
- int num_words = CVAL(buf,smb_wct);
- SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
- smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
- return (smb_size + num_words*2 + num_bytes);
-}
-
-/*******************************************************************
- Setup only the byte count for a smb message, using the end of the
- message as a marker.
-********************************************************************/
-
-int set_message_end(void *outbuf,void *end_ptr)
-{
- return set_message_bcc((char *)outbuf,PTR_DIFF(end_ptr,smb_buf((char *)outbuf)));
-}
-
-/*******************************************************************
- Reduce a file name, removing .. elements.
-********************************************************************/
-
-void dos_clean_name(char *s)
-{
- char *p=NULL;
-
- DEBUG(3,("dos_clean_name [%s]\n",s));
-
- /* remove any double slashes */
- all_string_sub(s, "\\\\", "\\", 0);
-
- while ((p = strstr_m(s,"\\..\\")) != NULL) {
- pstring s1;
-
- *p = 0;
- pstrcpy(s1,p+3);
-
- if ((p=strrchr_m(s,'\\')) != NULL)
- *p = 0;
- else
- *s = 0;
- pstrcat(s,s1);
- }
-
- trim_string(s,NULL,"\\..");
-
- all_string_sub(s, "\\.\\", "\\", 0);
-}
-
-/*******************************************************************
- Reduce a file name, removing .. elements.
-********************************************************************/
-
-void unix_clean_name(char *s)
-{
- char *p=NULL;
-
- DEBUG(3,("unix_clean_name [%s]\n",s));
-
- /* remove any double slashes */
- all_string_sub(s, "//","/", 0);
-
- /* Remove leading ./ characters */
- if(strncmp(s, "./", 2) == 0) {
- trim_string(s, "./", NULL);
- if(*s == 0)
- pstrcpy(s,"./");
- }
-
- while ((p = strstr_m(s,"/../")) != NULL) {
- pstring s1;
-
- *p = 0;
- pstrcpy(s1,p+3);
-
- if ((p=strrchr_m(s,'/')) != NULL)
- *p = 0;
- else
- *s = 0;
- pstrcat(s,s1);
- }
-
- trim_string(s,NULL,"/..");
-}
-
-/****************************************************************************
- Make a dir struct.
-****************************************************************************/
-
-void make_dir_struct(char *buf, const char *mask, const char *fname,SMB_OFF_T size,int mode,time_t date)
-{
- char *p;
- pstring mask2;
-
- pstrcpy(mask2,mask);
-
- if ((mode & aDIR) != 0)
- size = 0;
-
- memset(buf+1,' ',11);
- if ((p = strchr_m(mask2,'.')) != NULL) {
- *p = 0;
- push_ascii(buf+1,mask2,8, 0);
- push_ascii(buf+9,p+1,3, 0);
- *p = '.';
- } else
- push_ascii(buf+1,mask2,11, 0);
-
- memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
- SCVAL(buf,21,mode);
- put_dos_date(buf,22,date);
- SSVAL(buf,26,size & 0xFFFF);
- SSVAL(buf,28,(size >> 16)&0xFFFF);
- push_ascii(buf+30,fname,12, case_sensitive ? 0 : STR_UPPER);
- DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
-}
-
-/*******************************************************************
Close the low 3 fd's and open dev/null in their place.
********************************************************************/
-
void close_low_fds(BOOL stderr_too)
{
#ifndef VALGRIND
@@ -704,102 +184,20 @@ int set_blocking(int fd, BOOL set)
#undef FLAG_TO_SET
}
-/****************************************************************************
- Transfer some data between two fd's.
-****************************************************************************/
-
-#ifndef TRANSFER_BUF_SIZE
-#define TRANSFER_BUF_SIZE 65536
-#endif
-
-ssize_t transfer_file_internal(int infd, int outfd, size_t n, ssize_t (*read_fn)(int, void *, size_t),
- ssize_t (*write_fn)(int, const void *, size_t))
-{
- char *buf;
- size_t total = 0;
- ssize_t read_ret;
- ssize_t write_ret;
- size_t num_to_read_thistime;
- size_t num_written = 0;
-
- if ((buf = malloc(TRANSFER_BUF_SIZE)) == NULL)
- return -1;
-
- while (total < n) {
- num_to_read_thistime = MIN((n - total), TRANSFER_BUF_SIZE);
-
- read_ret = (*read_fn)(infd, buf, num_to_read_thistime);
- if (read_ret == -1) {
- DEBUG(0,("transfer_file_internal: read failure. Error = %s\n", strerror(errno) ));
- SAFE_FREE(buf);
- return -1;
- }
- if (read_ret == 0)
- break;
-
- num_written = 0;
-
- while (num_written < read_ret) {
- write_ret = (*write_fn)(outfd,buf + num_written, read_ret - num_written);
-
- if (write_ret == -1) {
- DEBUG(0,("transfer_file_internal: write failure. Error = %s\n", strerror(errno) ));
- SAFE_FREE(buf);
- return -1;
- }
- if (write_ret == 0)
- return (ssize_t)total;
-
- num_written += (size_t)write_ret;
- }
-
- total += (size_t)read_ret;
- }
-
- SAFE_FREE(buf);
- return (ssize_t)total;
-}
-
-SMB_OFF_T transfer_file(int infd,int outfd,SMB_OFF_T n)
-{
- return (SMB_OFF_T)transfer_file_internal(infd, outfd, (size_t)n, sys_read, sys_write);
-}
/*******************************************************************
Sleep for a specified number of milliseconds.
********************************************************************/
-void smb_msleep(unsigned int t)
+void msleep(unsigned int t)
{
- unsigned int tdiff=0;
- struct timeval tval,t1,t2;
- fd_set fds;
-
- GetTimeOfDay(&t1);
- GetTimeOfDay(&t2);
-
- while (tdiff < t) {
- tval.tv_sec = (t-tdiff)/1000;
- tval.tv_usec = 1000*((t-tdiff)%1000);
-
- /* Never wait for more than 1 sec. */
- if (tval.tv_sec > 1) {
- tval.tv_sec = 1;
- tval.tv_usec = 0;
- }
-
- FD_ZERO(&fds);
- errno = 0;
- sys_select_intr(0,&fds,NULL,NULL,&tval);
+ struct timeval tval;
- GetTimeOfDay(&t2);
- if (t2.tv_sec < t1.tv_sec) {
- /* Someone adjusted time... */
- t1 = t2;
- }
-
- tdiff = TvalDiff(&t1,&t2);
- }
+ tval.tv_sec = t/1000;
+ tval.tv_usec = 1000*(t%1000);
+ /* this should be the real select - do NOT replace
+ with sys_select() */
+ select(0,NULL,NULL,NULL,&tval);
}
/****************************************************************************
@@ -809,7 +207,7 @@ void smb_msleep(unsigned int t)
void become_daemon(BOOL Fork)
{
if (Fork) {
- if (sys_fork()) {
+ if (fork()) {
_exit(0);
}
}
@@ -832,23 +230,6 @@ void become_daemon(BOOL Fork)
attach it to the logfile */
}
-/****************************************************************************
- Put up a yes/no prompt.
-****************************************************************************/
-
-BOOL yesno(char *p)
-{
- pstring ans;
- printf("%s",p);
-
- if (!fgets(ans,sizeof(ans)-1,stdin))
- return(False);
-
- if (*ans == 'y' || *ans == 'Y')
- return(True);
-
- return(False);
-}
/****************************************************************************
Expand a pointer to be a particular size.
@@ -875,19 +256,6 @@ void *Realloc(void *p,size_t size)
return(ret);
}
-void *Realloc_zero(void *ptr, size_t size)
-{
- void *tptr = NULL;
-
- tptr = Realloc(ptr, size);
- if(tptr == NULL)
- return NULL;
-
- memset((char *)tptr,'\0',size);
-
- return tptr;
-}
-
/****************************************************************************
Free memory, checks for NULL.
Use directly SAFE_FREE()
@@ -899,66 +267,83 @@ void safe_free(void *p)
SAFE_FREE(p);
}
+
+/*
+ see if a string matches either our primary or one of our secondary
+ netbios aliases. do a case insensitive match
+*/
+BOOL is_myname(const char *name)
+{
+ const char **aliases;
+ int i;
+
+ if (strcasecmp(name, lp_netbios_name()) == 0) {
+ return True;
+ }
+
+ aliases = lp_netbios_aliases();
+ for (i=0; aliases && aliases[i]; i++) {
+ if (strcasecmp(name, aliases[i]) == 0) {
+ return True;
+ }
+ }
+
+ return False;
+}
+
+
/****************************************************************************
- Get my own name and IP.
+ Get my own name, return in malloc'ed storage.
****************************************************************************/
-BOOL get_myname(char *my_name)
+char* get_myname(void)
{
- pstring hostname;
+ char *hostname;
+ const int host_name_max = 255;
+ char *p;
+ hostname = malloc(host_name_max+1);
*hostname = 0;
/* get my host name */
- if (gethostname(hostname, sizeof(hostname)) == -1) {
+ if (gethostname(hostname, host_name_max+1) == -1) {
DEBUG(0,("gethostname failed\n"));
- return False;
+ return NULL;
}
/* Ensure null termination. */
- hostname[sizeof(hostname)-1] = '\0';
+ hostname[host_name_max] = '\0';
- if (my_name) {
- /* split off any parts after an initial . */
- char *p = strchr_m(hostname,'.');
+ /* split off any parts after an initial . */
+ p = strchr_m(hostname,'.');
- if (p)
- *p = 0;
-
- fstrcpy(my_name,hostname);
- }
+ if (p)
+ *p = 0;
- return(True);
+ return hostname;
}
/****************************************************************************
- Get my own canonical name, including domain.
+ Get my own name, including domain.
****************************************************************************/
-BOOL get_mydnsfullname(fstring my_dnsname)
+BOOL get_myfullname(char *my_name)
{
- static fstring dnshostname;
- struct hostent *hp;
+ pstring hostname;
- if (!*dnshostname) {
- /* get my host name */
- if (gethostname(dnshostname, sizeof(dnshostname)) == -1) {
- *dnshostname = '\0';
- DEBUG(0,("gethostname failed\n"));
- return False;
- }
-
- /* Ensure null termination. */
- dnshostname[sizeof(dnshostname)-1] = '\0';
-
- /* Ensure we get the cannonical name. */
- if (!(hp = sys_gethostbyname(dnshostname))) {
- *dnshostname = '\0';
- return False;
- }
- fstrcpy(dnshostname, hp->h_name);
- }
- fstrcpy(my_dnsname, dnshostname);
+ *hostname = 0;
+
+ /* get my host name */
+ if (gethostname(hostname, sizeof(hostname)) == -1) {
+ DEBUG(0,("gethostname failed\n"));
+ return False;
+ }
+
+ /* Ensure null termination. */
+ hostname[sizeof(hostname)-1] = '\0';
+
+ if (my_name)
+ fstrcpy(my_name, hostname);
return True;
}
@@ -966,29 +351,39 @@ BOOL get_mydnsfullname(fstring my_dnsname)
Get my own domain name.
****************************************************************************/
-BOOL get_mydnsdomname(fstring my_domname)
+BOOL get_mydomname(fstring my_domname)
{
- fstring domname;
+ pstring hostname;
char *p;
- *my_domname = '\0';
- if (!get_mydnsfullname(domname)) {
+ *hostname = 0;
+ /* get my host name */
+ if (gethostname(hostname, sizeof(hostname)) == -1) {
+ DEBUG(0,("gethostname failed\n"));
return False;
- }
- p = strchr_m(domname, '.');
- if (p) {
- p++;
+ }
+
+ /* Ensure null termination. */
+ hostname[sizeof(hostname)-1] = '\0';
+
+ p = strchr_m(hostname, '.');
+
+ if (!p)
+ return False;
+
+ p++;
+
+ if (my_domname)
fstrcpy(my_domname, p);
- }
- return False;
+ return True;
}
/****************************************************************************
Interpret a protocol description string, with a default.
****************************************************************************/
-int interpret_protocol(const char *str,int def)
+int interpret_protocol(char *str,int def)
{
if (strequal(str,"NT1"))
return(PROTOCOL_NT1);
@@ -1041,7 +436,7 @@ uint32 interpret_addr(const char *str)
if (strcmp(str,"255.255.255.255") == 0)
return(0xFFFFFFFF);
- /* if it's in the form of an IP address then get the lib to interpret it */
+ /* if it's in the form of an IP address then get the lib to interpret it */
if (is_ipaddress(str)) {
res = inet_addr(str);
} else {
@@ -1069,12 +464,15 @@ uint32 interpret_addr(const char *str)
A convenient addition to interpret_addr().
******************************************************************/
-struct in_addr *interpret_addr2(const char *str)
+struct in_addr *interpret_addr2(TALLOC_CTX *mem_ctx, const char *str)
{
- static struct in_addr ret;
+ struct in_addr *ret;
uint32 a = interpret_addr(str);
- ret.s_addr = a;
- return(&ret);
+
+ ret = talloc(mem_ctx, sizeof(struct in_addr));
+ if (!ret) return NULL;
+ ret->s_addr = a;
+ return(ret);
}
/*******************************************************************
@@ -1094,143 +492,10 @@ BOOL is_zero_ip(struct in_addr ip)
void zero_ip(struct in_addr *ip)
{
- static BOOL init;
- static struct in_addr ipzero;
-
- if (!init) {
- ipzero = *interpret_addr2("0.0.0.0");
- init = True;
- }
-
- *ip = ipzero;
-}
-
-#if (defined(HAVE_NETGROUP) && defined(WITH_AUTOMOUNT))
-/******************************************************************
- Remove any mount options such as -rsize=2048,wsize=2048 etc.
- Based on a fix from <Thomas.Hepper@icem.de>.
-*******************************************************************/
-
-static void strip_mount_options( pstring *str)
-{
- if (**str == '-') {
- char *p = *str;
- while(*p && !isspace(*p))
- p++;
- while(*p && isspace(*p))
- p++;
- if(*p) {
- pstring tmp_str;
-
- pstrcpy(tmp_str, p);
- pstrcpy(*str, tmp_str);
- }
- }
-}
-
-/*******************************************************************
- Patch from jkf@soton.ac.uk
- Split Luke's automount_server into YP lookup and string splitter
- so can easily implement automount_path().
- As we may end up doing both, cache the last YP result.
-*******************************************************************/
-
-#ifdef WITH_NISPLUS_HOME
-char *automount_lookup(const char *user_name)
-{
- static fstring last_key = "";
- static pstring last_value = "";
-
- char *nis_map = (char *)lp_nis_home_map_name();
-
- char buffer[NIS_MAXATTRVAL + 1];
- nis_result *result;
- nis_object *object;
- entry_obj *entry;
-
- if (strcmp(user_name, last_key)) {
- slprintf(buffer, sizeof(buffer)-1, "[key=%s],%s", user_name, nis_map);
- DEBUG(5, ("NIS+ querystring: %s\n", buffer));
-
- if (result = nis_list(buffer, FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP, NULL, NULL)) {
- if (result->status != NIS_SUCCESS) {
- DEBUG(3, ("NIS+ query failed: %s\n", nis_sperrno(result->status)));
- fstrcpy(last_key, ""); pstrcpy(last_value, "");
- } else {
- object = result->objects.objects_val;
- if (object->zo_data.zo_type == ENTRY_OBJ) {
- entry = &object->zo_data.objdata_u.en_data;
- DEBUG(5, ("NIS+ entry type: %s\n", entry->en_type));
- DEBUG(3, ("NIS+ result: %s\n", entry->en_cols.en_cols_val[1].ec_value.ec_value_val));
-
- pstrcpy(last_value, entry->en_cols.en_cols_val[1].ec_value.ec_value_val);
- pstring_sub(last_value, "&", user_name);
- fstrcpy(last_key, user_name);
- }
- }
- }
- nis_freeresult(result);
- }
-
- strip_mount_options(&last_value);
-
- DEBUG(4, ("NIS+ Lookup: %s resulted in %s\n", user_name, last_value));
- return last_value;
+ *ip = inet_makeaddr(0,0);
+ return;
}
-#else /* WITH_NISPLUS_HOME */
-
-char *automount_lookup(const char *user_name)
-{
- static fstring last_key = "";
- static pstring last_value = "";
-
- int nis_error; /* returned by yp all functions */
- char *nis_result; /* yp_match inits this */
- int nis_result_len; /* and set this */
- char *nis_domain; /* yp_get_default_domain inits this */
- char *nis_map = (char *)lp_nis_home_map_name();
-
- if ((nis_error = yp_get_default_domain(&nis_domain)) != 0) {
- DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error)));
- return last_value;
- }
- DEBUG(5, ("NIS Domain: %s\n", nis_domain));
-
- if (!strcmp(user_name, last_key)) {
- nis_result = last_value;
- nis_result_len = strlen(last_value);
- nis_error = 0;
- } else {
- if ((nis_error = yp_match(nis_domain, nis_map, user_name, strlen(user_name),
- &nis_result, &nis_result_len)) == 0) {
- if (!nis_error && nis_result_len >= sizeof(pstring)) {
- nis_result_len = sizeof(pstring)-1;
- }
- fstrcpy(last_key, user_name);
- strncpy(last_value, nis_result, nis_result_len);
- last_value[nis_result_len] = '\0';
- strip_mount_options(&last_value);
-
- } else if(nis_error == YPERR_KEY) {
-
- /* If Key lookup fails user home server is not in nis_map
- use default information for server, and home directory */
- last_value[0] = 0;
- DEBUG(3, ("YP Key not found: while looking up \"%s\" in map \"%s\"\n",
- user_name, nis_map));
- DEBUG(3, ("using defaults for server and home directory\n"));
- } else {
- DEBUG(3, ("YP Error: \"%s\" while looking up \"%s\" in map \"%s\"\n",
- yperr_string(nis_error), user_name, nis_map));
- }
- }
-
- DEBUG(4, ("YP Lookup: %s resulted in %s\n", user_name, last_value));
- return last_value;
-}
-#endif /* WITH_NISPLUS_HOME */
-#endif
/*******************************************************************
Are two IPs on the same subnet?
@@ -1261,64 +526,21 @@ BOOL process_exists(pid_t pid)
}
/*******************************************************************
- Convert a uid into a user name.
-********************************************************************/
-
-const char *uidtoname(uid_t uid)
-{
- static fstring name;
- struct passwd *pass;
-
- pass = getpwuid_alloc(uid);
- if (pass) {
- fstrcpy(name, pass->pw_name);
- passwd_free(&pass);
- } else {
- slprintf(name, sizeof(name) - 1, "%ld",(long int)uid);
- }
- return name;
-}
-
-
-/*******************************************************************
Convert a gid into a group name.
********************************************************************/
-char *gidtoname(gid_t gid)
+char *gidtoname(TALLOC_CTX *mem_ctx, gid_t gid)
{
- static fstring name;
+ char *name;
struct group *grp;
grp = getgrgid(gid);
if (grp)
return(grp->gr_name);
- slprintf(name,sizeof(name) - 1, "%d",(int)gid);
+ name = talloc_asprintf(mem_ctx, "%d",(int)gid);
return(name);
}
-/*******************************************************************
- Convert a user name into a uid.
-********************************************************************/
-
-uid_t nametouid(const char *name)
-{
- struct passwd *pass;
- char *p;
- uid_t u;
-
- pass = getpwnam_alloc(name);
- if (pass) {
- u = pass->pw_uid;
- passwd_free(&pass);
- return u;
- }
-
- u = (uid_t)strtol(name, &p, 0);
- if ((p != name) && (*p == '\0'))
- return u;
-
- return (uid_t)-1;
-}
/*******************************************************************
Convert a name to a gid_t if possible. Return -1 if not a group.
@@ -1341,308 +563,29 @@ gid_t nametogid(const char *name)
}
/*******************************************************************
- legacy wrapper for smb_panic2()
-********************************************************************/
-void smb_panic( const char *why )
-{
- smb_panic2( why, True );
-}
-
-/*******************************************************************
Something really nasty happened - panic !
********************************************************************/
-#ifdef HAVE_LIBEXC_H
-#include <libexc.h>
-#endif
-
-void smb_panic2(const char *why, BOOL decrement_pid_count )
+void smb_panic(const char *why)
{
- char *cmd;
+ char *cmd = lp_panic_action();
int result;
-#ifdef HAVE_BACKTRACE_SYMBOLS
- void *backtrace_stack[BACKTRACE_STACK_SIZE];
- size_t backtrace_size;
- char **backtrace_strings;
-#endif
-
-#ifdef DEVELOPER
- {
- extern char *global_clobber_region_function;
- extern unsigned int global_clobber_region_line;
-
- if (global_clobber_region_function) {
- DEBUG(0,("smb_panic: clobber_region() last called from [%s(%u)]\n",
- global_clobber_region_function,
- global_clobber_region_line));
- }
- }
-#endif
- /* only smbd needs to decrement the smbd counter in connections.tdb */
- if ( decrement_pid_count )
- decrement_smbd_process_count();
-
- cmd = lp_panic_action();
if (cmd && *cmd) {
DEBUG(0, ("smb_panic(): calling panic action [%s]\n", cmd));
result = system(cmd);
if (result == -1)
DEBUG(0, ("smb_panic(): fork failed in panic action: %s\n",
- strerror(errno)));
+ strerror(errno)));
else
DEBUG(0, ("smb_panic(): action returned status %d\n",
- WEXITSTATUS(result)));
+ WEXITSTATUS(result)));
}
DEBUG(0,("PANIC: %s\n", why));
-
-#ifdef HAVE_BACKTRACE_SYMBOLS
- /* get the backtrace (stack frames) */
- backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE);
- backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size);
-
- DEBUG(0, ("BACKTRACE: %lu stack frames:\n",
- (unsigned long)backtrace_size));
-
- if (backtrace_strings) {
- int i;
-
- for (i = 0; i < backtrace_size; i++)
- DEBUGADD(0, (" #%u %s\n", i, backtrace_strings[i]));
-
- /* Leak the backtrace_strings, rather than risk what free() might do */
- }
-
-#elif HAVE_LIBEXC
-
-#define NAMESIZE 32 /* Arbitrary */
-
- /* The IRIX libexc library provides an API for unwinding the stack. See
- * libexc(3) for details. Apparantly trace_back_stack leaks memory, but
- * since we are about to abort anyway, it hardly matters.
- *
- * Note that if we paniced due to a SIGSEGV or SIGBUS (or similar) this
- * will fail with a nasty message upon failing to open the /proc entry.
- */
- {
- __uint64_t addrs[BACKTRACE_STACK_SIZE];
- char * names[BACKTRACE_STACK_SIZE];
- char namebuf[BACKTRACE_STACK_SIZE * NAMESIZE];
-
- int i;
- int levels;
-
- ZERO_ARRAY(addrs);
- ZERO_ARRAY(names);
- ZERO_ARRAY(namebuf);
-
- for (i = 0; i < BACKTRACE_STACK_SIZE; i++) {
- names[i] = namebuf + (i * NAMESIZE);
- }
-
- levels = trace_back_stack(0, addrs, names,
- BACKTRACE_STACK_SIZE, NAMESIZE);
-
- DEBUG(0, ("BACKTRACE: %d stack frames:\n", levels));
- for (i = 0; i < levels; i++) {
- DEBUGADD(0, (" #%d 0x%llx %s\n", i, addrs[i], names[i]));
- }
- }
-#undef NAMESIZE
-#endif
-
- dbgflush();
abort();
}
-/*******************************************************************
- A readdir wrapper which just returns the file name.
- ********************************************************************/
-
-const char *readdirname(DIR *p)
-{
- SMB_STRUCT_DIRENT *ptr;
- char *dname;
-
- if (!p)
- return(NULL);
-
- ptr = (SMB_STRUCT_DIRENT *)sys_readdir(p);
- if (!ptr)
- return(NULL);
-
- dname = ptr->d_name;
-
-#ifdef NEXT2
- if (telldir(p) < 0)
- return(NULL);
-#endif
-
-#ifdef HAVE_BROKEN_READDIR
- /* using /usr/ucb/cc is BAD */
- dname = dname - 2;
-#endif
-
- {
- static pstring buf;
- int len = NAMLEN(ptr);
- memcpy(buf, dname, len);
- buf[len] = 0;
- dname = buf;
- }
-
- return(dname);
-}
-
-/*******************************************************************
- Utility function used to decide if the last component
- of a path matches a (possibly wildcarded) entry in a namelist.
-********************************************************************/
-
-BOOL is_in_path(const char *name, name_compare_entry *namelist)
-{
- pstring last_component;
- char *p;
-
- DEBUG(8, ("is_in_path: %s\n", name));
-
- /* if we have no list it's obviously not in the path */
- if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL))) {
- DEBUG(8,("is_in_path: no name list.\n"));
- return False;
- }
-
- /* Get the last component of the unix name. */
- p = strrchr_m(name, '/');
- strncpy(last_component, p ? ++p : name, sizeof(last_component)-1);
- last_component[sizeof(last_component)-1] = '\0';
-
- for(; namelist->name != NULL; namelist++) {
- if(namelist->is_wild) {
- if (mask_match(last_component, namelist->name, case_sensitive)) {
- DEBUG(8,("is_in_path: mask match succeeded\n"));
- return True;
- }
- } else {
- if((case_sensitive && (strcmp(last_component, namelist->name) == 0))||
- (!case_sensitive && (StrCaseCmp(last_component, namelist->name) == 0))) {
- DEBUG(8,("is_in_path: match succeeded\n"));
- return True;
- }
- }
- }
- DEBUG(8,("is_in_path: match not found\n"));
-
- return False;
-}
-
-/*******************************************************************
- Strip a '/' separated list into an array of
- name_compare_enties structures suitable for
- passing to is_in_path(). We do this for
- speed so we can pre-parse all the names in the list
- and don't do it for each call to is_in_path().
- namelist is modified here and is assumed to be
- a copy owned by the caller.
- We also check if the entry contains a wildcard to
- remove a potentially expensive call to mask_match
- if possible.
-********************************************************************/
-
-void set_namearray(name_compare_entry **ppname_array, char *namelist)
-{
- char *name_end;
- char *nameptr = namelist;
- int num_entries = 0;
- int i;
-
- (*ppname_array) = NULL;
-
- if((nameptr == NULL ) || ((nameptr != NULL) && (*nameptr == '\0')))
- return;
-
- /* We need to make two passes over the string. The
- first to count the number of elements, the second
- to split it.
- */
-
- while(*nameptr) {
- if ( *nameptr == '/' ) {
- /* cope with multiple (useless) /s) */
- nameptr++;
- continue;
- }
- /* find the next / */
- name_end = strchr_m(nameptr, '/');
-
- /* oops - the last check for a / didn't find one. */
- if (name_end == NULL)
- break;
-
- /* next segment please */
- nameptr = name_end + 1;
- num_entries++;
- }
-
- if(num_entries == 0)
- return;
-
- if(( (*ppname_array) = (name_compare_entry *)malloc(
- (num_entries + 1) * sizeof(name_compare_entry))) == NULL) {
- DEBUG(0,("set_namearray: malloc fail\n"));
- return;
- }
-
- /* Now copy out the names */
- nameptr = namelist;
- i = 0;
- while(*nameptr) {
- if ( *nameptr == '/' ) {
- /* cope with multiple (useless) /s) */
- nameptr++;
- continue;
- }
- /* find the next / */
- if ((name_end = strchr_m(nameptr, '/')) != NULL)
- *name_end = 0;
-
- /* oops - the last check for a / didn't find one. */
- if(name_end == NULL)
- break;
-
- (*ppname_array)[i].is_wild = ms_has_wild(nameptr);
- if(((*ppname_array)[i].name = strdup(nameptr)) == NULL) {
- DEBUG(0,("set_namearray: malloc fail (1)\n"));
- return;
- }
-
- /* next segment please */
- nameptr = name_end + 1;
- i++;
- }
-
- (*ppname_array)[i].name = NULL;
-
- return;
-}
-
-/****************************************************************************
- Routine to free a namearray.
-****************************************************************************/
-
-void free_namearray(name_compare_entry *name_array)
-{
- int i;
-
- if(name_array == NULL)
- return;
-
- for(i=0; name_array[i].name!=NULL; i++)
- SAFE_FREE(name_array[i].name);
- SAFE_FREE(name_array);
-}
-
/****************************************************************************
Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping
is dealt with in posix.c
@@ -1671,7 +614,7 @@ BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
if ((ret != -1) &&
(lock.l_type != F_UNLCK) &&
(lock.l_pid != 0) &&
- (lock.l_pid != sys_getpid())) {
+ (lock.l_pid != getpid())) {
DEBUG(3,("fcntl_lock: fd %d is locked by pid %d\n",fd,(int)lock.l_pid));
return(True);
}
@@ -1694,165 +637,51 @@ BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
}
/*******************************************************************
- Is the name specified one of my netbios names.
- Returns true if it is equal, false otherwise.
+ Set the remote_arch string based on an enum. This is used in places
+where we desperately need to distinguish client type.
********************************************************************/
-
-BOOL is_myname(const char *s)
+void set_remote_arch(struct server_context *smb, enum remote_arch_types type)
{
- int n;
- BOOL ret = False;
+ const char *arch;
- for (n=0; my_netbios_names(n); n++) {
- if (strequal(my_netbios_names(n), s)) {
- ret=True;
- break;
- }
- }
- DEBUG(8, ("is_myname(\"%s\") returns %d\n", s, ret));
- return(ret);
-}
-
-/********************************************************************
- Return only the first IP address of our configured interfaces
- as a string
- *******************************************************************/
-
-const char* get_my_primary_ip (void)
-{
- static fstring ip_string;
- int n;
- struct iface_struct nics[MAX_INTERFACES];
-
- if ((n=get_interfaces(nics, MAX_INTERFACES)) <= 0)
- return NULL;
-
- fstrcpy(ip_string, inet_ntoa(nics[0].ip));
- return ip_string;
-}
-
-BOOL is_myname_or_ipaddr(const char *s)
-{
- /* optimize for the common case */
- if (strequal(s, global_myname()))
- return True;
-
- /* maybe its an IP address? */
- if (is_ipaddress(s)) {
- struct iface_struct nics[MAX_INTERFACES];
- int i, n;
- uint32 ip;
-
- ip = interpret_addr(s);
- if ((ip==0) || (ip==0xffffffff))
- return False;
-
- n = get_interfaces(nics, MAX_INTERFACES);
- for (i=0; i<n; i++) {
- if (ip == nics[i].ip.s_addr)
- return True;
- }
- }
-
- /* check for an alias */
- if (is_myname(s))
- return True;
-
- /* no match */
- return False;
-}
-
-/*******************************************************************
- Is the name specified our workgroup/domain.
- Returns true if it is equal, false otherwise.
-********************************************************************/
-
-BOOL is_myworkgroup(const char *s)
-{
- BOOL ret = False;
-
- if (strequal(s, lp_workgroup())) {
- ret=True;
- }
-
- DEBUG(8, ("is_myworkgroup(\"%s\") returns %d\n", s, ret));
- return(ret);
-}
-
-/*******************************************************************
- we distinguish between 2K and XP by the "Native Lan Manager" string
- WinXP => "Windows 2002 5.1"
- Win2k => "Windows 2000 5.0"
- NT4 => "Windows NT 4.0"
- Win9x => "Windows 4.0"
- Windows 2003 doesn't set the native lan manager string but
- they do set the domain to "Windows 2003 5.2" (probably a bug).
-********************************************************************/
-
-void ra_lanman_string( const char *native_lanman )
-{
- if ( strcmp( native_lanman, "Windows 2002 5.1" ) == 0 )
- set_remote_arch( RA_WINXP );
- else if ( strcmp( native_lanman, "Windows Server 2003 5.2" ) == 0 )
- set_remote_arch( RA_WIN2K3 );
-}
-
-/*******************************************************************
- Set the horrid remote_arch string based on an enum.
-********************************************************************/
-
-void set_remote_arch(enum remote_arch_types type)
-{
- extern fstring remote_arch;
- ra_type = type;
- switch( type ) {
+ smb->negotiate.ra_type = type;
+ switch (type) {
case RA_WFWG:
- fstrcpy(remote_arch, "WfWg");
- break;
+ arch = "WfWg";
+ return;
case RA_OS2:
- fstrcpy(remote_arch, "OS2");
- break;
+ arch = "OS2";
+ return;
case RA_WIN95:
- fstrcpy(remote_arch, "Win95");
- break;
+ arch = "Win95";
+ return;
case RA_WINNT:
- fstrcpy(remote_arch, "WinNT");
- break;
+ arch = "WinNT";
+ return;
case RA_WIN2K:
- fstrcpy(remote_arch, "Win2K");
- break;
+ arch = "Win2K";
+ return;
case RA_WINXP:
- fstrcpy(remote_arch, "WinXP");
- break;
- case RA_WIN2K3:
- fstrcpy(remote_arch, "Win2K3");
- break;
+ arch = "WinXP";
+ return;
case RA_SAMBA:
- fstrcpy(remote_arch,"Samba");
- break;
+ arch = "Samba";
+ return;
default:
- ra_type = RA_UNKNOWN;
- fstrcpy(remote_arch, "UNKNOWN");
+ smb->negotiate.ra_type = RA_UNKNOWN;
+ arch = "UNKNOWN";
break;
}
- DEBUG(10,("set_remote_arch: Client arch is \'%s\'\n", remote_arch));
+ sub_set_remote_arch(arch);
}
-/*******************************************************************
- Get the remote_arch type.
-********************************************************************/
-
-enum remote_arch_types get_remote_arch(void)
-{
- return ra_type;
-}
void print_asc(int level, const unsigned char *buf,int len)
{
int i;
for (i=0;i<len;i++)
- DEBUG(level,("%c", isprint(buf[i])?buf[i]:'.'));
+ DEBUGADD(level,("%c", isprint(buf[i])?buf[i]:'.'));
}
void dump_data(int level, const char *buf1,int len)
@@ -1888,176 +717,6 @@ void dump_data(int level, const char *buf1,int len)
}
}
-void dump_data_pw(const char *msg, const uchar * data, size_t len)
-{
-#ifdef DEBUG_PASSWORD
- DEBUG(11, ("%s", msg));
- if (data != NULL && len > 0)
- {
- dump_data(11, data, len);
- }
-#endif
-}
-
-char *tab_depth(int depth)
-{
- static pstring spaces;
- memset(spaces, ' ', depth * 4);
- spaces[depth * 4] = 0;
- return spaces;
-}
-
-/*****************************************************************************
- Provide a checksum on a string
-
- Input: s - the null-terminated character string for which the checksum
- will be calculated.
-
- Output: The checksum value calculated for s.
-*****************************************************************************/
-
-int str_checksum(const char *s)
-{
- int res = 0;
- int c;
- int i=0;
-
- while(*s) {
- c = *s;
- res ^= (c << (i % 15)) ^ (c >> (15-(i%15)));
- s++;
- i++;
- }
- return(res);
-}
-
-/*****************************************************************
- Zero a memory area then free it. Used to catch bugs faster.
-*****************************************************************/
-
-void zero_free(void *p, size_t size)
-{
- memset(p, 0, size);
- SAFE_FREE(p);
-}
-
-/*****************************************************************
- Set our open file limit to a requested max and return the limit.
-*****************************************************************/
-
-int set_maxfiles(int requested_max)
-{
-#if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
- struct rlimit rlp;
- int saved_current_limit;
-
- if(getrlimit(RLIMIT_NOFILE, &rlp)) {
- DEBUG(0,("set_maxfiles: getrlimit (1) for RLIMIT_NOFILE failed with error %s\n",
- strerror(errno) ));
- /* just guess... */
- return requested_max;
- }
-
- /*
- * Set the fd limit to be real_max_open_files + MAX_OPEN_FUDGEFACTOR to
- * account for the extra fd we need
- * as well as the log files and standard
- * handles etc. Save the limit we want to set in case
- * we are running on an OS that doesn't support this limit (AIX)
- * which always returns RLIM_INFINITY for rlp.rlim_max.
- */
-
- /* Try raising the hard (max) limit to the requested amount. */
-
-#if defined(RLIM_INFINITY)
- if (rlp.rlim_max != RLIM_INFINITY) {
- int orig_max = rlp.rlim_max;
-
- if ( rlp.rlim_max < requested_max )
- rlp.rlim_max = requested_max;
-
- /* This failing is not an error - many systems (Linux) don't
- support our default request of 10,000 open files. JRA. */
-
- if(setrlimit(RLIMIT_NOFILE, &rlp)) {
- DEBUG(3,("set_maxfiles: setrlimit for RLIMIT_NOFILE for %d max files failed with error %s\n",
- (int)rlp.rlim_max, strerror(errno) ));
-
- /* Set failed - restore original value from get. */
- rlp.rlim_max = orig_max;
- }
- }
-#endif
-
- /* Now try setting the soft (current) limit. */
-
- saved_current_limit = rlp.rlim_cur = MIN(requested_max,rlp.rlim_max);
-
- if(setrlimit(RLIMIT_NOFILE, &rlp)) {
- DEBUG(0,("set_maxfiles: setrlimit for RLIMIT_NOFILE for %d files failed with error %s\n",
- (int)rlp.rlim_cur, strerror(errno) ));
- /* just guess... */
- return saved_current_limit;
- }
-
- if(getrlimit(RLIMIT_NOFILE, &rlp)) {
- DEBUG(0,("set_maxfiles: getrlimit (2) for RLIMIT_NOFILE failed with error %s\n",
- strerror(errno) ));
- /* just guess... */
- return saved_current_limit;
- }
-
-#if defined(RLIM_INFINITY)
- if(rlp.rlim_cur == RLIM_INFINITY)
- return saved_current_limit;
-#endif
-
- if((int)rlp.rlim_cur > saved_current_limit)
- return saved_current_limit;
-
- return rlp.rlim_cur;
-#else /* !defined(HAVE_GETRLIMIT) || !defined(RLIMIT_NOFILE) */
- /*
- * No way to know - just guess...
- */
- return requested_max;
-#endif
-}
-
-/*****************************************************************
- Splits out the start of the key (HKLM or HKU) and the rest of the key.
-*****************************************************************/
-
-BOOL reg_split_key(const char *full_keyname, uint32 *reg_type, char *key_name)
-{
- pstring tmp;
-
- if (!next_token(&full_keyname, tmp, "\\", sizeof(tmp)))
- return False;
-
- (*reg_type) = 0;
-
- DEBUG(10, ("reg_split_key: hive %s\n", tmp));
-
- if (strequal(tmp, "HKLM") || strequal(tmp, "HKEY_LOCAL_MACHINE"))
- (*reg_type) = HKEY_LOCAL_MACHINE;
- else if (strequal(tmp, "HKU") || strequal(tmp, "HKEY_USERS"))
- (*reg_type) = HKEY_USERS;
- else {
- DEBUG(10,("reg_split_key: unrecognised hive key %s\n", tmp));
- return False;
- }
-
- if (next_token(&full_keyname, tmp, "\n\r", sizeof(tmp)))
- fstrcpy(key_name, tmp);
- else
- key_name[0] = 0;
-
- DEBUG(10, ("reg_split_key: name %s\n", key_name));
-
- return True;
-}
-
/*****************************************************************
Possibly replace mkstemp if it is broken.
*****************************************************************/
@@ -2085,10 +744,8 @@ void *smb_xmalloc(size_t size)
void *p;
if (size == 0)
smb_panic("smb_xmalloc: called with zero size.\n");
- if ((p = malloc(size)) == NULL) {
- DEBUG(0, ("smb_xmalloc() failed to allocate %lu bytes\n", (unsigned long)size));
+ if ((p = malloc(size)) == NULL)
smb_panic("smb_xmalloc: malloc fail.\n");
- }
return p;
}
@@ -2116,17 +773,6 @@ char *smb_xstrdup(const char *s)
return s1;
}
-/**
- strndup that aborts on malloc fail.
-**/
-
-char *smb_xstrndup(const char *s, size_t n)
-{
- char *s1 = strndup(s, n);
- if (!s1)
- smb_panic("smb_xstrndup: malloc fail\n");
- return s1;
-}
/*
vasprintf that aborts on malloc fail
@@ -2165,50 +811,31 @@ void *memdup(const void *p, size_t size)
Get local hostname and cache result.
*****************************************************************/
-char *myhostname(void)
+char *myhostname(TALLOC_CTX *mem_ctx)
{
- static pstring ret;
- if (ret[0] == 0)
- get_myname(ret);
+ char *myname, *ret;
+ myname = get_myname();
+ ret = talloc_strdup(mem_ctx, myname);
+ free(myname);
return ret;
+
}
/*****************************************************************
A useful function for returning a path in the Samba lock directory.
*****************************************************************/
-char *lock_path(const char *name)
+char *lock_path(TALLOC_CTX* mem_ctx, const char *name)
{
- static pstring fname;
+ char *fname;
- pstrcpy(fname,lp_lockdir());
- trim_char(fname,'\0','/');
+ fname = talloc_strdup(mem_ctx, lp_lockdir());
+ trim_string(fname,"","/");
if (!directory_exist(fname,NULL))
mkdir(fname,0755);
- pstrcat(fname,"/");
- pstrcat(fname,name);
-
- return fname;
-}
-
-/*****************************************************************
- A useful function for returning a path in the Samba pid directory.
-*****************************************************************/
-
-char *pid_path(const char *name)
-{
- static pstring fname;
-
- pstrcpy(fname,lp_piddir());
- trim_char(fname,'\0','/');
-
- if (!directory_exist(fname,NULL))
- mkdir(fname,0755);
-
- pstrcat(fname,"/");
- pstrcat(fname,name);
+ fname = talloc_asprintf(mem_ctx, "%s/%s", fname, name);
return fname;
}
@@ -2218,13 +845,13 @@ char *pid_path(const char *name)
*
* @param name File to find, relative to LIBDIR.
*
- * @retval Pointer to a static #pstring containing the full path.
+ * @retval Pointer to a talloc'ed string containing the full path.
**/
-char *lib_path(const char *name)
+char *lib_path(TALLOC_CTX* mem_ctx, const char *name)
{
- static pstring fname;
- fstr_sprintf(fname, "%s/%s", dyn_LIBDIR, name);
+ char *fname;
+ fname = talloc_asprintf(mem_ctx, "%s/%s", dyn_LIBDIR, name);
return fname;
}
@@ -2239,108 +866,14 @@ const char *shlib_ext(void)
return dyn_SHLIBEXT;
}
-/*******************************************************************
- Given a filename - get its directory name
- NB: Returned in static storage. Caveats:
- o Not safe in thread environment.
- o Caller must not free.
- o If caller wishes to preserve, they should copy.
-********************************************************************/
-
-char *parent_dirname(const char *path)
-{
- static pstring dirpath;
- char *p;
-
- if (!path)
- return(NULL);
-
- pstrcpy(dirpath, path);
- p = strrchr_m(dirpath, '/'); /* Find final '/', if any */
- if (!p) {
- pstrcpy(dirpath, "."); /* No final "/", so dir is "." */
- } else {
- if (p == dirpath)
- ++p; /* For root "/", leave "/" in place */
- *p = '\0';
- }
- return dirpath;
-}
-
-
-/*******************************************************************
- Determine if a pattern contains any Microsoft wildcard characters.
-*******************************************************************/
-
-BOOL ms_has_wild(const char *s)
-{
- char c;
- while ((c = *s++)) {
- switch (c) {
- case '*':
- case '?':
- case '<':
- case '>':
- case '"':
- return True;
- }
- }
- return False;
-}
-
-BOOL ms_has_wild_w(const smb_ucs2_t *s)
-{
- smb_ucs2_t c;
- if (!s) return False;
- while ((c = *s++)) {
- switch (c) {
- case UCS2_CHAR('*'):
- case UCS2_CHAR('?'):
- case UCS2_CHAR('<'):
- case UCS2_CHAR('>'):
- case UCS2_CHAR('"'):
- return True;
- }
- }
- return False;
-}
-
-/*******************************************************************
- A wrapper that handles case sensitivity and the special handling
- of the ".." name.
-*******************************************************************/
-
-BOOL mask_match(const char *string, char *pattern, BOOL is_case_sensitive)
-{
- if (strcmp(string,"..") == 0)
- string = ".";
- if (strcmp(pattern,".") == 0)
- return False;
-
- return ms_fnmatch(pattern, string, Protocol, is_case_sensitive) == 0;
-}
-
-/*******************************************************************
- A wrapper that handles a list of patters and calls mask_match()
- on each. Returns True if any of the patterns match.
-*******************************************************************/
-
-BOOL mask_match_list(const char *string, char **list, int listLen, BOOL is_case_sensitive)
-{
- while (listLen-- > 0) {
- if (mask_match(string, *list++, is_case_sensitive))
- return True;
- }
- return False;
-}
/*********************************************************
Recursive routine that is called by unix_wild_match.
*********************************************************/
-static BOOL unix_do_match(const char *regexp, const char *str)
+static BOOL unix_do_match(char *regexp, char *str)
{
- const char *p;
+ char *p;
for( p = regexp; *p && *str; ) {
@@ -2435,67 +968,27 @@ static BOOL unix_do_match(const char *regexp, const char *str)
return False;
}
-/*******************************************************************
- Simple case insensitive interface to a UNIX wildcard matcher.
-*******************************************************************/
-
-BOOL unix_wild_match(const char *pattern, const char *string)
+void dump_data_pw(const char *msg, const uchar * data, size_t len)
{
- pstring p2, s2;
- char *p;
-
- pstrcpy(p2, pattern);
- pstrcpy(s2, string);
- strlower_m(p2);
- strlower_m(s2);
-
- /* Remove any *? and ** from the pattern as they are meaningless */
- for(p = p2; *p; p++)
- while( *p == '*' && (p[1] == '?' ||p[1] == '*'))
- pstrcpy( &p[1], &p[2]);
-
- if (strequal(p2,"*"))
- return True;
-
- return unix_do_match(p2, s2) == 0;
+#ifdef DEBUG_PASSWORD
+ DEBUG(11, ("%s", msg));
+ if (data != NULL && len > 0)
+ {
+ dump_data(11, data, len);
+ }
+#endif
}
-#ifdef __INSURE__
-
-/*******************************************************************
-This routine is a trick to immediately catch errors when debugging
-with insure. A xterm with a gdb is popped up when insure catches
-a error. It is Linux specific.
-********************************************************************/
-
-int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
+/* see if a range of memory is all zero. A NULL pointer is considered
+ to be all zero */
+BOOL all_zero(const char *ptr, unsigned size)
{
- static int (*fn)();
- int ret;
- char pidstr[10];
- /* you can get /usr/bin/backtrace from
- http://samba.org/ftp/unpacked/junkcode/backtrace */
- pstring cmd = "/usr/bin/backtrace %d";
-
- slprintf(pidstr, sizeof(pidstr)-1, "%d", sys_getpid());
- pstring_sub(cmd, "%d", pidstr);
-
- if (!fn) {
- static void *h;
- h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
- fn = dlsym(h, "_Insure_trap_error");
-
- if (!h || h == _Insure_trap_error) {
- h = dlopen("/usr/local/parasoft/lib.linux2/libinsure.so", RTLD_LAZY);
- fn = dlsym(h, "_Insure_trap_error");
- }
+ int i;
+ if (!ptr) return True;
+ for (i=0;i<size;i++) {
+ if (ptr[i]) return False;
}
-
- ret = fn(a1, a2, a3, a4, a5, a6);
-
- system(cmd);
-
- return ret;
+ return True;
}
-#endif
+
diff --git a/source/lib/util_file.c b/source/lib/util_file.c
index bd505ac921c..0eb80462275 100644
--- a/source/lib/util_file.c
+++ b/source/lib/util_file.c
@@ -20,11 +20,6 @@
#include "includes.h"
-#ifndef MAP_FAILED
-#define MAP_FAILED ((void *)-1)
-#endif
-
-
static int gotalarm;
/***************************************************************
@@ -114,76 +109,6 @@ BOOL file_unlock(int fd, int *plock_depth)
return ret;
}
-/***************************************************************
- locks a file for enumeration / modification.
- update to be set = True if modification is required.
-****************************************************************/
-
-void *startfilepwent(char *pfile, char *s_readbuf, int bufsize,
- int *file_lock_depth, BOOL update)
-{
- FILE *fp = NULL;
-
- if (!*pfile)
- {
- DEBUG(0, ("startfilepwent: No file set\n"));
- return (NULL);
- }
- DEBUG(10, ("startfilepwent: opening file %s\n", pfile));
-
- fp = sys_fopen(pfile, update ? "r+b" : "rb");
-
- if (fp == NULL) {
- DEBUG(0, ("startfilepwent: unable to open file %s\n", pfile));
- return NULL;
- }
-
- /* Set a buffer to do more efficient reads */
- setvbuf(fp, s_readbuf, _IOFBF, bufsize);
-
- if (!file_lock(fileno(fp), (update ? F_WRLCK : F_RDLCK), 5, file_lock_depth))
- {
- DEBUG(0, ("startfilepwent: unable to lock file %s\n", pfile));
- fclose(fp);
- return NULL;
- }
-
- /* Make sure it is only rw by the owner */
- chmod(pfile, 0600);
-
- /* We have a lock on the file. */
- return (void *)fp;
-}
-
-/***************************************************************
- End enumeration of the file.
-****************************************************************/
-void endfilepwent(void *vp, int *file_lock_depth)
-{
- FILE *fp = (FILE *)vp;
-
- file_unlock(fileno(fp), file_lock_depth);
- fclose(fp);
- DEBUG(7, ("endfilepwent: closed file.\n"));
-}
-
-/*************************************************************************
- Return the current position in the file list as an SMB_BIG_UINT.
- This must be treated as an opaque token.
-*************************************************************************/
-SMB_BIG_UINT getfilepwpos(void *vp)
-{
- return (SMB_BIG_UINT)sys_ftell((FILE *)vp);
-}
-
-/*************************************************************************
- Set the current position in the file list from an SMB_BIG_UINT.
- This must be treated as an opaque token.
-*************************************************************************/
-BOOL setfilepwpos(void *vp, SMB_BIG_UINT tok)
-{
- return !sys_fseek((FILE *)vp, (SMB_OFF_T)tok, SEEK_SET);
-}
/*************************************************************************
gets a line out of a file.
@@ -460,8 +385,8 @@ void *map_file(char *fname, size_t size)
p = file_load(fname, &s2);
if (!p) return NULL;
if (s2 != size) {
- DEBUG(1,("incorrect size for %s - got %lu expected %lu\n",
- fname, (unsigned long)s2, (unsigned long)size));
+ DEBUG(1,("incorrect size for %s - got %d expected %d\n",
+ fname, s2, size));
if (p) free(p);
return NULL;
}
diff --git a/source/lib/util_getent.c b/source/lib/util_getent.c
index 3544c1678cc..32641dbf83b 100644
--- a/source/lib/util_getent.c
+++ b/source/lib/util_getent.c
@@ -156,15 +156,15 @@ struct sys_pwent * getpwent_list(void)
pent->pw_uid = pwd->pw_uid;
pent->pw_gid = pwd->pw_gid;
if (pwd->pw_gecos) {
- if ((pent->pw_gecos = strdup(pwd->pw_gecos)) == NULL)
+ if ((pent->pw_name = strdup(pwd->pw_gecos)) == NULL)
goto err;
}
if (pwd->pw_dir) {
- if ((pent->pw_dir = strdup(pwd->pw_dir)) == NULL)
+ if ((pent->pw_name = strdup(pwd->pw_dir)) == NULL)
goto err;
}
if (pwd->pw_shell) {
- if ((pent->pw_shell = strdup(pwd->pw_shell)) == NULL)
+ if ((pent->pw_name = strdup(pwd->pw_shell)) == NULL)
goto err;
}
diff --git a/source/lib/util_seaccess.c b/source/lib/util_seaccess.c
index cb0f46e2f9d..9d56a0d8507 100644
--- a/source/lib/util_seaccess.c
+++ b/source/lib/util_seaccess.c
@@ -19,10 +19,30 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#error SAMBA4 clean up
+#error this file should be (re)moved
+#error and all unused stuff should go
+
#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).
@@ -316,6 +336,119 @@ BOOL se_access_check(const SEC_DESC *sd, const NT_USER_TOKEN *token,
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
@@ -350,7 +483,7 @@ NTSTATUS samr_make_sam_obj_sd(TALLOC_CTX *ctx, SEC_DESC **psd, size_t *sd_size)
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, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, psa, sd_size)) == NULL)
+ 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;
diff --git a/source/lib/util_sec.c b/source/lib/util_sec.c
deleted file mode 100644
index 26be27ea515..00000000000
--- a/source/lib/util_sec.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
- Copyright (C) Jeremy Allison 1998.
- rewritten for version 2.0.6 by Tridge
-
- 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 AUTOCONF_TEST
-#include "includes.h"
-#else
-/* we are running this code in autoconf test mode to see which type of setuid
- function works */
-#if defined(HAVE_UNISTD_H)
-#include <unistd.h>
-#endif
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <errno.h>
-
-#ifdef HAVE_SYS_PRIV_H
-#include <sys/priv.h>
-#endif
-#ifdef HAVE_SYS_ID_H
-#include <sys/id.h>
-#endif
-
-#define DEBUG(x, y) printf y
-#define smb_panic(x) exit(1)
-#define BOOL int
-#endif
-
-/* are we running as non-root? This is used by the regresison test code,
- and potentially also for sites that want non-root smbd */
-static uid_t initial_uid;
-static gid_t initial_gid;
-
-/****************************************************************************
-remember what uid we got started as - this allows us to run correctly
-as non-root while catching trapdoor systems
-****************************************************************************/
-void sec_init(void)
-{
- initial_uid = geteuid();
- initial_gid = getegid();
-}
-
-/****************************************************************************
-some code (eg. winbindd) needs to know what uid we started as
-****************************************************************************/
-uid_t sec_initial_uid(void)
-{
- return initial_uid;
-}
-
-/****************************************************************************
-some code (eg. winbindd, profiling shm) needs to know what gid we started as
-****************************************************************************/
-gid_t sec_initial_gid(void)
-{
- return initial_gid;
-}
-
-/****************************************************************************
-are we running in non-root mode?
-****************************************************************************/
-BOOL non_root_mode(void)
-{
- return (initial_uid != (uid_t)0);
-}
-
-/****************************************************************************
-abort if we haven't set the uid correctly
-****************************************************************************/
-static void assert_uid(uid_t ruid, uid_t euid)
-{
- if ((euid != (uid_t)-1 && geteuid() != euid) ||
- (ruid != (uid_t)-1 && getuid() != ruid)) {
- if (!non_root_mode()) {
- DEBUG(0,("Failed to set uid privileges to (%d,%d) now set to (%d,%d)\n",
- (int)ruid, (int)euid,
- (int)getuid(), (int)geteuid()));
- smb_panic("failed to set uid\n");
- exit(1);
- }
- }
-}
-
-/****************************************************************************
-abort if we haven't set the gid correctly
-****************************************************************************/
-static void assert_gid(gid_t rgid, gid_t egid)
-{
- if ((egid != (gid_t)-1 && getegid() != egid) ||
- (rgid != (gid_t)-1 && getgid() != rgid)) {
- if (!non_root_mode()) {
- DEBUG(0,("Failed to set gid privileges to (%d,%d) now set to (%d,%d) uid=(%d,%d)\n",
- (int)rgid, (int)egid,
- (int)getgid(), (int)getegid(),
- (int)getuid(), (int)geteuid()));
- smb_panic("failed to set gid\n");
- exit(1);
- }
- }
-}
-
-/****************************************************************************
- Gain root privilege before doing something.
- We want to end up with ruid==euid==0
-****************************************************************************/
-void gain_root_privilege(void)
-{
-#if USE_SETRESUID
- setresuid(0,0,0);
-#endif
-
-#if USE_SETEUID
- seteuid(0);
-#endif
-
-#if USE_SETREUID
- setreuid(0, 0);
-#endif
-
-#if USE_SETUIDX
- setuidx(ID_EFFECTIVE, 0);
- setuidx(ID_REAL, 0);
-#endif
-
- /* this is needed on some systems */
- setuid(0);
-
- assert_uid(0, 0);
-}
-
-
-/****************************************************************************
- Ensure our real and effective groups are zero.
- we want to end up with rgid==egid==0
-****************************************************************************/
-void gain_root_group_privilege(void)
-{
-#if USE_SETRESUID
- setresgid(0,0,0);
-#endif
-
-#if USE_SETREUID
- setregid(0,0);
-#endif
-
-#if USE_SETEUID
- setegid(0);
-#endif
-
-#if USE_SETUIDX
- setgidx(ID_EFFECTIVE, 0);
- setgidx(ID_REAL, 0);
-#endif
-
- setgid(0);
-
- assert_gid(0, 0);
-}
-
-
-/****************************************************************************
- Set effective uid, and possibly the real uid too.
- We want to end up with either:
-
- ruid==uid and euid==uid
-
- or
-
- ruid==0 and euid==uid
-
- depending on what the local OS will allow us to regain root from.
-****************************************************************************/
-void set_effective_uid(uid_t uid)
-{
-#if USE_SETRESUID
- /* Set the effective as well as the real uid. */
- setresuid(uid,uid,-1);
-#endif
-
-#if USE_SETREUID
- setreuid(-1,uid);
-#endif
-
-#if USE_SETEUID
- seteuid(uid);
-#endif
-
-#if USE_SETUIDX
- setuidx(ID_EFFECTIVE, uid);
-#endif
-
- assert_uid(-1, uid);
-}
-
-/****************************************************************************
- Set *only* the effective gid.
- we want to end up with rgid==0 and egid==gid
-****************************************************************************/
-void set_effective_gid(gid_t gid)
-{
-#if USE_SETRESUID
- setresgid(-1,gid,-1);
-#endif
-
-#if USE_SETREUID
- setregid(-1,gid);
-#endif
-
-#if USE_SETEUID
- setegid(gid);
-#endif
-
-#if USE_SETUIDX
- setgidx(ID_EFFECTIVE, gid);
-#endif
-
- assert_gid(-1, gid);
-}
-
-static uid_t saved_euid, saved_ruid;
-static gid_t saved_egid, saved_rgid;
-
-/****************************************************************************
- save the real and effective uid for later restoration. Used by the quotas
- code
-****************************************************************************/
-void save_re_uid(void)
-{
- saved_ruid = getuid();
- saved_euid = geteuid();
-}
-
-
-/****************************************************************************
- and restore them!
-****************************************************************************/
-void restore_re_uid(void)
-{
- set_effective_uid(0);
-
-#if USE_SETRESUID
- setresuid(saved_ruid, saved_euid, -1);
-#elif USE_SETREUID
- setreuid(saved_ruid, -1);
- setreuid(-1,saved_euid);
-#elif USE_SETUIDX
- setuidx(ID_REAL, saved_ruid);
- setuidx(ID_EFFECTIVE, saved_euid);
-#else
- set_effective_uid(saved_euid);
- if (getuid() != saved_ruid)
- setuid(saved_ruid);
- set_effective_uid(saved_euid);
-#endif
-
- assert_uid(saved_ruid, saved_euid);
-}
-
-
-/****************************************************************************
- save the real and effective gid for later restoration. Used by the
- getgroups code
-****************************************************************************/
-void save_re_gid(void)
-{
- saved_rgid = getgid();
- saved_egid = getegid();
-}
-
-/****************************************************************************
- and restore them!
-****************************************************************************/
-void restore_re_gid(void)
-{
-#if USE_SETRESUID
- setresgid(saved_rgid, saved_egid, -1);
-#elif USE_SETREUID
- setregid(saved_rgid, -1);
- setregid(-1,saved_egid);
-#elif USE_SETUIDX
- setgidx(ID_REAL, saved_rgid);
- setgidx(ID_EFFECTIVE, saved_egid);
-#else
- set_effective_gid(saved_egid);
- if (getgid() != saved_rgid)
- setgid(saved_rgid);
- set_effective_gid(saved_egid);
-#endif
-
- assert_gid(saved_rgid, saved_egid);
-}
-
-
-/****************************************************************************
- set the real AND effective uid to the current effective uid in a way that
- allows root to be regained.
- This is only possible on some platforms.
-****************************************************************************/
-int set_re_uid(void)
-{
- uid_t uid = geteuid();
-
-#if USE_SETRESUID
- setresuid(geteuid(), -1, -1);
-#endif
-
-#if USE_SETREUID
- setreuid(0, 0);
- setreuid(uid, -1);
- setreuid(-1, uid);
-#endif
-
-#if USE_SETEUID
- /* can't be done */
- return -1;
-#endif
-
-#if USE_SETUIDX
- /* can't be done */
- return -1;
-#endif
-
- assert_uid(uid, uid);
- return 0;
-}
-
-
-/****************************************************************************
- Become the specified uid and gid - permanently !
- there should be no way back if possible
-****************************************************************************/
-void become_user_permanently(uid_t uid, gid_t gid)
-{
- /*
- * First - gain root privilege. We do this to ensure
- * we can lose it again.
- */
-
- gain_root_privilege();
- gain_root_group_privilege();
-
-#if USE_SETRESUID
- setresgid(gid,gid,gid);
- setgid(gid);
- setresuid(uid,uid,uid);
- setuid(uid);
-#endif
-
-#if USE_SETREUID
- setregid(gid,gid);
- setgid(gid);
- setreuid(uid,uid);
- setuid(uid);
-#endif
-
-#if USE_SETEUID
- setegid(gid);
- setgid(gid);
- setuid(uid);
- seteuid(uid);
- setuid(uid);
-#endif
-
-#if USE_SETUIDX
- setgidx(ID_REAL, gid);
- setgidx(ID_EFFECTIVE, gid);
- setgid(gid);
- setuidx(ID_REAL, uid);
- setuidx(ID_EFFECTIVE, uid);
- setuid(uid);
-#endif
-
- assert_uid(uid, uid);
- assert_gid(gid, gid);
-}
-
-#ifdef AUTOCONF_TEST
-
-/****************************************************************************
-this function just checks that we don't get ENOSYS back
-****************************************************************************/
-static int have_syscall(void)
-{
- errno = 0;
-
-#if USE_SETRESUID
- setresuid(-1,-1,-1);
-#endif
-
-#if USE_SETREUID
- setreuid(-1,-1);
-#endif
-
-#if USE_SETEUID
- seteuid(-1);
-#endif
-
-#if USE_SETUIDX
- setuidx(ID_EFFECTIVE, -1);
-#endif
-
- if (errno == ENOSYS) return -1;
-
- return 0;
-}
-
-main()
-{
- if (getuid() != 0) {
-#if (defined(AIX) && defined(USE_SETREUID))
- /* setreuid is badly broken on AIX 4.1, we avoid it completely */
- fprintf(stderr,"avoiding possibly broken setreuid\n");
- exit(1);
-#endif
-
- /* if not running as root then at least check to see if we get ENOSYS - this
- handles Linux 2.0.x with glibc 2.1 */
- fprintf(stderr,"not running as root: checking for ENOSYS\n");
- exit(have_syscall());
- }
-
- gain_root_privilege();
- gain_root_group_privilege();
- set_effective_gid(1);
- set_effective_uid(1);
- save_re_uid();
- restore_re_uid();
- gain_root_privilege();
- gain_root_group_privilege();
- become_user_permanently(1, 1);
- setuid(0);
- if (getuid() == 0) {
- fprintf(stderr,"uid not set permanently\n");
- exit(1);
- }
-
- printf("OK\n");
-
- exit(0);
-}
-#endif
-
-/****************************************************************************
-Check if we are setuid root. Used in libsmb and smbpasswd paranoia checks.
-****************************************************************************/
-BOOL is_setuid_root(void)
-{
- return (geteuid() == (uid_t)0) && (getuid() != (uid_t)0);
-}
diff --git a/source/lib/util_sid.c b/source/lib/util_sid.c
index 2c0bd797859..44bb4cebb11 100644
--- a/source/lib/util_sid.c
+++ b/source/lib/util_sid.c
@@ -91,9 +91,8 @@ static const struct {
{SID_NAME_DELETED, "Deleted Account"},
{SID_NAME_INVALID, "Invalid Account"},
{SID_NAME_UNKNOWN, "UNKNOWN"},
- {SID_NAME_COMPUTER, "Computer"},
- {(enum SID_NAME_USE)0, NULL}
+ {SID_NAME_USE_NONE, NULL}
};
const char *sid_type_lookup(uint32 sid_type)
@@ -176,7 +175,7 @@ NT_USER_TOKEN *get_system_token(void)
/**************************************************************************
Splits a name of format \DOMAIN\name or name into its two components.
- Sets the DOMAIN name to global_myname() if it has not been specified.
+ 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)
@@ -201,7 +200,7 @@ void split_domain_name(const char *fullname, char *domain, char *name)
fstrcpy(domain, full_name);
fstrcpy(name, p+1);
} else {
- fstrcpy(domain, global_myname());
+ fstrcpy(domain, lp_netbios_name());
fstrcpy(name, full_name);
}
@@ -265,11 +264,11 @@ char *sid_to_string(fstring sidstr_out, const DOM_SID *sid)
Useful function for debug lines.
*****************************************************************/
-const char *sid_string_static(const DOM_SID *sid)
+const char *sid_string_talloc(TALLOC_CTX *mem_ctx, const DOM_SID *sid)
{
- static fstring sid_str;
- sid_to_string(sid_str, sid);
- return sid_str;
+ fstring tempSid;
+ sid_to_string(tempSid, sid);
+ return talloc_strdup(mem_ctx, tempSid);
}
/*****************************************************************
@@ -391,9 +390,6 @@ BOOL sid_peek_check_rid(const DOM_SID *exp_dom_sid, const DOM_SID *sid, uint32 *
if (!exp_dom_sid || !sid || !rid)
return False;
- if (sid->num_auths != (exp_dom_sid->num_auths+1)) {
- return False;
- }
if (sid_compare_domain(exp_dom_sid, sid)!=0){
*rid=(-1);
@@ -618,19 +614,15 @@ char *sid_binstring(const DOM_SID *sid)
}
/*******************************************************************
- Tallocs a duplicate SID.
-********************************************************************/
-
-DOM_SID *sid_dup_talloc(TALLOC_CTX *ctx, const DOM_SID *src)
+ Check if ACE has OBJECT type.
+********************************************************************/
+BOOL sec_ace_object(uint8 type)
{
- DOM_SID *dst;
-
- if(!src)
- return NULL;
-
- if((dst = talloc_zero(ctx, sizeof(DOM_SID))) != NULL) {
- sid_copy( dst, src);
+ if (type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
+ type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT ||
+ type == SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT ||
+ type == SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT) {
+ return True;
}
-
- return dst;
+ return False;
}
diff --git a/source/lib/util_smbd.c b/source/lib/util_smbd.c
deleted file mode 100644
index 071f20b4162..00000000000
--- a/source/lib/util_smbd.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- 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;
-}
diff --git a/source/lib/util_sock.c b/source/lib/util_sock.c
index 845aaa4b13a..95e0c5fe0cb 100644
--- a/source/lib/util_sock.c
+++ b/source/lib/util_sock.c
@@ -21,46 +21,15 @@
#include "includes.h"
-/* the last IP received from */
-struct in_addr lastip;
-
-/* the last port received from */
-int lastport=0;
-
-int smb_read_error = 0;
-
-static char *get_socket_addr(int fd)
-{
- struct sockaddr sa;
- struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
- int length = sizeof(sa);
- static fstring addr_buf;
-
- fstrcpy(addr_buf,"0.0.0.0");
-
- if (fd == -1) {
- return addr_buf;
- }
-
- if (getsockname(fd, &sa, &length) < 0) {
- DEBUG(0,("getpeername failed. Error was %s\n", strerror(errno) ));
- return addr_buf;
- }
-
- fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
-
- return addr_buf;
-}
/****************************************************************************
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);
+ return getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0;
}
enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
@@ -118,15 +87,11 @@ static void print_socket_options(int s)
int value, vlen = 4;
const smb_socket_option *p = &socket_options[0];
- /* wrapped in if statement to prevent streams leak in SCO Openserver 5.0 */
- /* reported on samba-technical --jerry */
- if ( DEBUGLEVEL >= 5 ) {
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));
- }
}
}
}
@@ -190,180 +155,44 @@ void set_socket_options(int fd, const char *options)
Read from a socket.
****************************************************************************/
-ssize_t read_udp_socket(int fd,char *buf,size_t len)
+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);
- memset((char *)&sock,'\0',socklen);
- memset((char *)&lastip,'\0',sizeof(lastip));
- ret = (ssize_t)sys_recvfrom(fd,buf,len,0,(struct sockaddr *)&sock,&socklen);
+ 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);
+ return 0;
}
- lastip = sock.sin_addr;
- lastport = ntohs(sock.sin_port);
-
- DEBUG(10,("read_udp_socket: lastip %s lastport %d read: %lu\n",
- inet_ntoa(lastip), lastport, (unsigned long)ret));
-
- return(ret);
-}
-
-/****************************************************************************
- Read data from a socket with a timout in msec.
- mincount = if timeout, minimum to read before returning
- maxcount = number to be read.
- time_out = timeout in milliseconds
-****************************************************************************/
-
-ssize_t read_socket_with_timeout(int fd,char *buf,size_t mincnt,size_t maxcnt,unsigned int time_out)
-{
- fd_set fds;
- int selrtn;
- ssize_t readret;
- size_t nread = 0;
- struct timeval timeout;
-
- /* just checking .... */
- if (maxcnt <= 0)
- return(0);
-
- smb_read_error = 0;
-
- /* Blocking read */
- if (time_out <= 0) {
- if (mincnt == 0) mincnt = maxcnt;
-
- while (nread < mincnt) {
- readret = sys_read(fd, buf + nread, maxcnt - nread);
-
- if (readret == 0) {
- DEBUG(5,("read_socket_with_timeout: blocking read. EOF from client.\n"));
- smb_read_error = READ_EOF;
- return -1;
- }
-
- if (readret == -1) {
- DEBUG(0,("read_socket_with_timeout: read error = %s.\n", strerror(errno) ));
- smb_read_error = READ_ERROR;
- return -1;
- }
- nread += readret;
- }
- return((ssize_t)nread);
+ if (from_addr) {
+ *from_addr = sock.sin_addr;
}
-
- /* Most difficult - timeout read */
- /* If this is ever called on a disk file and
- mincnt is greater then the filesize then
- system performance will suffer severely as
- select always returns true on disk files */
-
- /* Set initial timeout */
- timeout.tv_sec = (time_t)(time_out / 1000);
- timeout.tv_usec = (long)(1000 * (time_out % 1000));
-
- for (nread=0; nread < mincnt; ) {
- FD_ZERO(&fds);
- FD_SET(fd,&fds);
-
- selrtn = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout);
-
- /* Check if error */
- if (selrtn == -1) {
- /* something is wrong. Maybe the socket is dead? */
- DEBUG(0,("read_socket_with_timeout: timeout read. select error = %s.\n", strerror(errno) ));
- smb_read_error = READ_ERROR;
- return -1;
- }
-
- /* Did we timeout ? */
- if (selrtn == 0) {
- DEBUG(10,("read_socket_with_timeout: timeout read. select timed out.\n"));
- smb_read_error = READ_TIMEOUT;
- return -1;
- }
-
- readret = sys_read(fd, buf+nread, maxcnt-nread);
-
- if (readret == 0) {
- /* we got EOF on the file descriptor */
- DEBUG(5,("read_socket_with_timeout: timeout read. EOF from client.\n"));
- smb_read_error = READ_EOF;
- return -1;
- }
-
- if (readret == -1) {
- /* the descriptor is probably dead */
- DEBUG(0,("read_socket_with_timeout: timeout read. read error = %s.\n", strerror(errno) ));
- smb_read_error = READ_ERROR;
- return -1;
- }
-
- nread += readret;
+ if (from_port) {
+ *from_port = ntohs(sock.sin_port);
}
-
- /* Return the number we got */
- return (ssize_t)nread;
-}
-/****************************************************************************
- 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;
-
- smb_read_error = 0;
-
- while (total < N) {
- ret = sys_read(fd,buffer + total,N - total);
-
- if (ret == 0) {
- DEBUG(10,("read_data: read of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) ));
- smb_read_error = READ_EOF;
- return 0;
- }
-
- if (ret == -1) {
- DEBUG(0,("read_data: read failure for %d. Error = %s\n", (int)(N - total), strerror(errno) ));
- smb_read_error = READ_ERROR;
- return -1;
- }
- total += ret;
- }
- return (ssize_t)total;
+ return ret;
}
+
/****************************************************************************
- Read data from a socket, reading exactly N bytes.
+ read data from the client, reading exactly N bytes.
****************************************************************************/
-
-static ssize_t read_socket_data(int fd,char *buffer,size_t N)
+ssize_t read_data(int fd, char *buffer, size_t N)
{
ssize_t ret;
size_t total=0;
- smb_read_error = 0;
-
while (total < N) {
ret = sys_read(fd,buffer + total,N - total);
-
if (ret == 0) {
- DEBUG(10,("read_socket_data: recv of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) ));
- smb_read_error = READ_EOF;
return 0;
}
-
if (ret == -1) {
- DEBUG(0,("read_socket_data: recv failure for %d. Error = %s\n", (int)(N - total), strerror(errno) ));
- smb_read_error = READ_ERROR;
return -1;
}
total += ret;
@@ -371,44 +200,18 @@ static ssize_t read_socket_data(int fd,char *buffer,size_t N)
return (ssize_t)total;
}
-/****************************************************************************
- Write data to a fd.
-****************************************************************************/
-
-ssize_t write_data(int fd,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) {
- DEBUG(0,("write_data: write failure. Error = %s\n", strerror(errno) ));
- return -1;
- }
- if (ret == 0)
- return total;
-
- total += ret;
- }
- return (ssize_t)total;
-}
/****************************************************************************
- Write data to a socket - use send rather than write.
+ Write data to a fd.
****************************************************************************/
-
-static ssize_t write_socket_data(int fd,char *buffer,size_t N)
+ssize_t write_data(int fd, const char *buffer, size_t N)
{
size_t total=0;
ssize_t ret;
while (total < N) {
- ret = sys_send(fd,buffer + total,N - total,0);
-
+ ret = sys_write(fd, buffer + total, N - total);
if (ret == -1) {
- DEBUG(0,("write_socket_data: write failure. Error = %s\n", strerror(errno) ));
return -1;
}
if (ret == 0)
@@ -419,225 +222,24 @@ static ssize_t write_socket_data(int fd,char *buffer,size_t N)
return (ssize_t)total;
}
-/****************************************************************************
- Write to a socket.
-****************************************************************************/
-
-ssize_t write_socket(int fd,char *buf,size_t len)
-{
- ssize_t ret=0;
-
- DEBUG(6,("write_socket(%d,%d)\n",fd,(int)len));
- ret = write_socket_data(fd,buf,len);
-
- DEBUG(6,("write_socket(%d,%d) wrote %d\n",fd,(int)len,(int)ret));
- if(ret <= 0)
- DEBUG(0,("write_socket: Error writing %d bytes to socket %d: ERRNO = %s\n",
- (int)len, fd, strerror(errno) ));
-
- return(ret);
-}
/****************************************************************************
- Send a keepalive packet (rfc1002).
+send a keepalive packet (rfc1002)
****************************************************************************/
-
-BOOL send_keepalive(int client)
+BOOL send_nbt_keepalive(int sock_fd)
{
unsigned char buf[4];
buf[0] = SMBkeepalive;
buf[1] = buf[2] = buf[3] = 0;
- return(write_socket_data(client,(char *)buf,4) == 4);
-}
-
-
-/****************************************************************************
- Read 4 bytes of a smb packet and return the smb length of the packet.
- Store the result in the buffer.
- This version of the function will return a length of zero on receiving
- a keepalive packet.
- Timeout is in milliseconds.
-****************************************************************************/
-
-static ssize_t read_smb_length_return_keepalive(int fd,char *inbuf,unsigned int timeout)
-{
- ssize_t len=0;
- int msg_type;
- BOOL ok = False;
-
- while (!ok) {
- if (timeout > 0)
- ok = (read_socket_with_timeout(fd,inbuf,4,4,timeout) == 4);
- else
- ok = (read_socket_data(fd,inbuf,4) == 4);
-
- if (!ok)
- return(-1);
-
- len = smb_len(inbuf);
- msg_type = CVAL(inbuf,0);
-
- if (msg_type == SMBkeepalive)
- DEBUG(5,("Got keepalive packet\n"));
- }
-
- DEBUG(10,("got smb length of %lu\n",(unsigned long)len));
-
- return(len);
-}
-
-/****************************************************************************
- Read 4 bytes of a smb packet and return the smb length of the packet.
- Store the result in the buffer. This version of the function will
- never return a session keepalive (length of zero).
- Timeout is in milliseconds.
-****************************************************************************/
-
-ssize_t read_smb_length(int fd,char *inbuf,unsigned int timeout)
-{
- ssize_t len;
-
- for(;;) {
- len = read_smb_length_return_keepalive(fd, inbuf, timeout);
-
- if(len < 0)
- return len;
-
- /* Ignore session keepalives. */
- if(CVAL(inbuf,0) != SMBkeepalive)
- break;
- }
-
- DEBUG(10,("read_smb_length: got smb length of %lu\n",
- (unsigned long)len));
-
- return len;
-}
-
-/****************************************************************************
- Read an smb from a fd. Note that the buffer *MUST* be of size
- BUFFER_SIZE+SAFETY_MARGIN.
- The timeout is in milliseconds.
- This function will return on receipt of a session keepalive packet.
- Doesn't check the MAC on signed packets.
-****************************************************************************/
-
-BOOL receive_smb_raw(int fd,char *buffer, unsigned int timeout)
-{
- ssize_t len,ret;
-
- smb_read_error = 0;
-
- memset(buffer,'\0',smb_size + 100);
-
- len = read_smb_length_return_keepalive(fd,buffer,timeout);
- if (len < 0) {
- DEBUG(10,("receive_smb_raw: length < 0!\n"));
-
- /*
- * Correct fix. smb_read_error may have already been
- * set. Only set it here if not already set. Global
- * variables still suck :-). JRA.
- */
-
- if (smb_read_error == 0)
- smb_read_error = READ_ERROR;
- return False;
- }
-
- /*
- * A WRITEX with CAP_LARGE_WRITEX can be 64k worth of data plus 65 bytes
- * of header. Don't print the error if this fits.... JRA.
- */
-
- if (len > (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE)) {
- DEBUG(0,("Invalid packet length! (%lu bytes).\n",(unsigned long)len));
- if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) {
-
- /*
- * Correct fix. smb_read_error may have already been
- * set. Only set it here if not already set. Global
- * variables still suck :-). JRA.
- */
-
- if (smb_read_error == 0)
- smb_read_error = READ_ERROR;
- return False;
- }
- }
-
- if(len > 0) {
- ret = read_socket_data(fd,buffer+4,len);
- if (ret != len) {
- if (smb_read_error == 0)
- smb_read_error = READ_ERROR;
- return False;
- }
-
- /* not all of samba3 properly checks for packet-termination of strings. This
- ensures that we don't run off into empty space. */
- SSVAL(buffer+4,len, 0);
- }
-
- return True;
-}
-
-/****************************************************************************
- Wrapper for receive_smb_raw().
- Checks the MAC on signed packets.
-****************************************************************************/
-
-BOOL receive_smb(int fd,char *buffer, unsigned int timeout)
-{
- if (!receive_smb_raw(fd, buffer, timeout)) {
- return False;
- }
-
- /* Check the incoming SMB signature. */
- if (!srv_check_sign_mac(buffer, True)) {
- DEBUG(0, ("receive_smb: SMB Signature verification failed on incoming packet!\n"));
- if (smb_read_error == 0)
- smb_read_error = READ_BAD_SIG;
- return False;
- };
-
- return(True);
+ return write_data(sock_fd,(char *)buf,4) == 4;
}
-/****************************************************************************
- Send an smb to a fd.
-****************************************************************************/
-
-BOOL send_smb(int fd,char *buffer)
-{
- size_t len;
- size_t nwritten=0;
- ssize_t ret;
-
- /* Sign the outgoing packet if required. */
- srv_calculate_sign_mac(buffer);
-
- len = smb_len(buffer) + 4;
-
- while (nwritten < len) {
- ret = write_socket(fd,buffer+nwritten,len - nwritten);
- if (ret <= 0) {
- DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n",
- (int)len,(int)ret, strerror(errno) ));
- return False;
- }
- nwritten += ret;
- }
-
- return True;
-}
/****************************************************************************
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;
@@ -654,43 +256,22 @@ int open_socket_in( int type, int port, int dlevel, uint32 socket_addr, BOOL reb
res = socket( AF_INET, type, 0 );
if( res == -1 ) {
- if( DEBUGLVL(0) ) {
- dbgtext( "open_socket_in(): socket() call failed: " );
- dbgtext( "%s\n", strerror( errno ) );
- }
+ 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;
- if( setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val)) == -1 ) {
- if( DEBUGLVL( dlevel ) ) {
- dbgtext( "open_socket_in(): setsockopt: " );
- dbgtext( "SO_REUSEADDR = %s ", val?"True":"False" );
- dbgtext( "on port %d failed ", port );
- dbgtext( "with error = %s\n", strerror(errno) );
- }
- }
+ setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val));
#ifdef SO_REUSEPORT
- if( setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val)) == -1 ) {
- if( DEBUGLVL( dlevel ) ) {
- dbgtext( "open_socket_in(): setsockopt: ");
- dbgtext( "SO_REUSEPORT = %s ", val?"True":"False" );
- dbgtext( "on port %d failed ", port );
- dbgtext( "with error = %s\n", strerror(errno) );
- }
- }
-#endif /* 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 ) {
- if( DEBUGLVL(dlevel) && (port == SMB_PORT1 || port == SMB_PORT2 || port == NMB_PORT) ) {
- dbgtext( "bind failed on port %d ", port );
- dbgtext( "socket_addr = %s.\n", inet_ntoa( sock.sin_addr ) );
- dbgtext( "Error = %s\n", strerror(errno) );
- }
+ DEBUG(0,("bind failed on port %d - %s\n", port, strerror(errno)));
close( res );
return( -1 );
}
@@ -700,95 +281,89 @@ int open_socket_in( int type, int port, int dlevel, uint32 socket_addr, BOOL reb
return( res );
}
-/****************************************************************************
- Create an outgoing socket. timeout is in milliseconds.
-**************************************************************************/
-int open_socket_out(int type, struct in_addr *addr, int port ,int timeout)
+/****************************************************************************
+ 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 = 10;
- int increment = 10;
+ 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 (%s)\n", strerror(errno)));
- return -1;
- }
-
- if (type != SOCK_STREAM)
- return(res);
-
+ 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:
-
+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) && (connect_loop < timeout) ) {
- smb_msleep(connect_loop);
- connect_loop += increment;
- if (increment < 250) {
- /* After 8 rounds we end up at a max of 255 msec */
- increment *= 1.5;
- }
+ 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)));
+ 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
-**************************************************************************/
-
+/*
+ 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;
- addr = interpret_addr2(host);
+ 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) {
@@ -799,6 +374,8 @@ int open_udp_socket(const char *host, int port)
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);
@@ -809,50 +386,11 @@ int open_udp_socket(const char *host, int port)
}
-/* the following 3 client_*() functions are nasty ways of allowing
- some generic functions to get info that really should be hidden in
- particular modules */
-static int client_fd = -1;
-
-void client_setfd(int fd)
-{
- client_fd = fd;
-}
-
-char *client_name(void)
-{
- return get_peer_name(client_fd,False);
-}
-
-char *client_addr(void)
-{
- return get_peer_addr(client_fd);
-}
-
-char *client_socket_addr(void)
-{
- return get_socket_addr(client_fd);
-}
-
-struct in_addr *client_inaddr(struct sockaddr *sa)
-{
- struct sockaddr_in *sockin = (struct sockaddr_in *) (sa);
- int length = sizeof(*sa);
-
- if (getpeername(client_fd, sa, &length) < 0) {
- DEBUG(0,("getpeername failed. Error was %s\n", strerror(errno) ));
- return NULL;
- }
-
- return &sockin->sin_addr;
-}
-
/*******************************************************************
- 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)
+ 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;
@@ -870,8 +408,8 @@ static BOOL matchname(char *remotehost,struct in_addr addr)
* DNS is perverted). We always check the address list, though.
*/
- if (!strequal(remotehost, hp->h_name)
- && !strequal(remotehost, "localhost")) {
+ if (strcasecmp(remotehost, hp->h_name)
+ && strcasecmp(remotehost, "localhost")) {
DEBUG(0,("host name/name mismatch: %s != %s\n",
remotehost, hp->h_name));
return False;
@@ -894,15 +432,13 @@ static BOOL matchname(char *remotehost,struct in_addr addr)
return False;
}
+
/*******************************************************************
- Return the DNS name of the remote end of a socket.
-******************************************************************/
-
-char *get_peer_name(int fd, BOOL force_lookup)
+ return the DNS name of the remote end of a socket
+ ******************************************************************/
+char *get_socket_name(TALLOC_CTX *mem_ctx, int fd, BOOL force_lookup)
{
- static pstring name_buf;
- pstring tmp_name;
- static fstring addr_buf;
+ char *name_buf;
struct hostent *hp;
struct in_addr addr;
char *p;
@@ -912,167 +448,171 @@ char *get_peer_name(int fd, BOOL force_lookup)
with dns. To avoid the delay we avoid the lookup if
possible */
if (!lp_hostname_lookups() && (force_lookup == False)) {
- return get_peer_addr(fd);
+ return get_socket_addr(mem_ctx, fd);
}
- p = get_peer_addr(fd);
+ p = get_socket_addr(mem_ctx, fd);
- /* it might be the same as the last one - save some DNS work */
- if (strcmp(p, addr_buf) == 0)
- return name_buf;
+ name_buf = talloc_strdup(mem_ctx, "UNKNOWN");
+ if (fd == -1) return name_buf;
- pstrcpy(name_buf,"UNKNOWN");
- if (fd == -1)
- return name_buf;
-
- fstrcpy(addr_buf, p);
-
- addr = *interpret_addr2(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));
- pstrcpy(name_buf, p);
+ name_buf = talloc_strdup(mem_ctx, p);
} else {
- pstrcpy(name_buf,(char *)hp->h_name);
+ 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));
- pstrcpy(name_buf,"UNKNOWN");
+ name_buf = talloc_strdup(mem_ctx, "UNKNOWN");
}
}
- /* can't pass the same source and dest strings in when you
- use --enable-developer or the clobber_region() call will
- get you */
-
- pstrcpy( tmp_name, name_buf );
- alpha_strcpy(name_buf, tmp_name, "_-.", sizeof(name_buf));
+ alpha_strcpy(name_buf, name_buf, "_-.", strlen(name_buf)+1);
if (strstr(name_buf,"..")) {
- pstrcpy(name_buf, "UNKNOWN");
+ name_buf = talloc_strdup(mem_ctx, "UNKNOWN");
}
return name_buf;
}
/*******************************************************************
- Return the IP addr of the remote end of a socket as a string.
+ return the IP addr of the remote end of a socket as a string
******************************************************************/
-
-char *get_peer_addr(int fd)
+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);
- static fstring addr_buf;
-
- fstrcpy(addr_buf,"0.0.0.0");
- if (fd == -1) {
- return addr_buf;
+ if (fd == -1 || getpeername(fd, &sa, &length) == -1) {
+ return talloc_strdup(mem_ctx, "0.0.0.0");
}
- if (getpeername(fd, &sa, &length) < 0) {
- DEBUG(0,("getpeername failed. Error was %s\n", strerror(errno) ));
- return addr_buf;
- }
-
- fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
-
- return addr_buf;
+ return talloc_strdup(mem_ctx, (char *)inet_ntoa(sockin->sin_addr));
}
-/*******************************************************************
- Create protected unix domain socket.
- Some unixes cannot set permissions on a ux-dom-sock, so we
- have to make sure that the directory contains the protection
- permissions instead.
- ******************************************************************/
-int create_pipe_sock(const char *socket_dir,
- const char *socket_name,
- mode_t dir_perms)
+/*******************************************************************
+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])
{
-#ifdef HAVE_UNIXSOCKET
- struct sockaddr_un sunaddr;
- struct stat st;
- int sock;
- mode_t old_umask;
- pstring path;
-
- old_umask = umask(0);
-
- /* Create the socket directory or reuse the existing one */
-
- if (lstat(socket_dir, &st) == -1) {
- if (errno == ENOENT) {
- /* Create directory */
- if (mkdir(socket_dir, dir_perms) == -1) {
- DEBUG(0, ("error creating socket directory "
- "%s: %s\n", socket_dir,
- strerror(errno)));
- goto out_umask;
- }
- } else {
- DEBUG(0, ("lstat failed on socket directory %s: %s\n",
- socket_dir, strerror(errno)));
- goto out_umask;
- }
+ 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 {
- /* Check ownership and permission on existing directory */
- if (!S_ISDIR(st.st_mode)) {
- DEBUG(0, ("socket directory %s isn't a directory\n",
- socket_dir));
- goto out_umask;
- }
- if ((st.st_uid != sec_initial_uid()) ||
- ((st.st_mode & 0777) != dir_perms)) {
- DEBUG(0, ("invalid permissions on socket directory "
- "%s\n", socket_dir));
- goto out_umask;
- }
+ connect_done = 1;
}
-
- /* Create the socket file */
-
- sock = socket(AF_UNIX, SOCK_STREAM, 0);
-
- if (sock == -1) {
- perror("socket");
- goto out_umask;
+
+ 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;
}
-
- pstr_sprintf(path, "%s/%s", socket_dir, socket_name);
-
- unlink(path);
- memset(&sunaddr, 0, sizeof(sunaddr));
- sunaddr.sun_family = AF_UNIX;
- safe_strcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)-1);
-
- if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
- DEBUG(0, ("bind failed on pipe socket %s: %s\n", path,
- strerror(errno)));
- goto out_close;
+
+ 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 (listen(sock, 5) == -1) {
- DEBUG(0, ("listen failed on pipe socket %s: %s\n", path,
- strerror(errno)));
- goto out_close;
+ if (fork() == 0) {
+ close(fd[0]);
+ close(0);
+ close(1);
+ dup(fd[1]);
+ dup(fd[1]);
+ exit(system(prog));
}
-
- umask(old_umask);
- return sock;
+ close(fd[1]);
+ return fd[0];
+}
-out_close:
- close(sock);
-out_umask:
- umask(old_umask);
- return -1;
+/*
+ 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;
-#else
- DEBUG(0, ("create_pipe_sock: No Unix sockets on this system\n"));
- return -1;
-#endif /* HAVE_UNIXSOCKET */
+ /* 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;
}
diff --git a/source/lib/util_str.c b/source/lib/util_str.c
index be1e2ffeb1b..07fdf334fd0 100644
--- a/source/lib/util_str.c
+++ b/source/lib/util_str.c
@@ -1,10 +1,8 @@
/*
Unix SMB/CIFS implementation.
Samba utility functions
-
Copyright (C) Andrew Tridgell 1992-2001
Copyright (C) Simo Sorce 2001-2002
- Copyright (C) Martin Pool 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
@@ -24,11 +22,6 @@
#include "includes.h"
/**
- * @file
- * @brief String utilities.
- **/
-
-/**
* Get the next token from a string, return False if none found.
* Handles double-quotes.
*
@@ -37,15 +30,14 @@
**/
BOOL next_token(const char **ptr,char *buff, const char *sep, size_t bufsize)
{
- char *s;
- char *pbuf;
+ const char *s;
BOOL quoted;
size_t len=1;
if (!ptr)
return(False);
- s = (char *)*ptr;
+ s = *ptr;
/* default to simple separators */
if (!sep)
@@ -60,18 +52,17 @@ BOOL next_token(const char **ptr,char *buff, const char *sep, size_t bufsize)
return(False);
/* copy over the token */
- pbuf = buff;
for (quoted = False; len < bufsize && *s && (quoted || !strchr_m(sep,*s)); s++) {
- if (*s == '\"' || *s == '\'') {
+ if (*s == '\"') {
quoted = !quoted;
} else {
len++;
- *pbuf++ = *s;
+ *buff++ = *s;
}
}
*ptr = (*s) ? s+1 : s;
- *pbuf = 0;
+ *buff = 0;
return(True);
}
@@ -82,13 +73,13 @@ parameter so you can pass NULL. This is useful for user interface code
but beware the fact that it is not re-entrant!
**/
-static const char *last_ptr=NULL;
+static char *last_ptr=NULL;
-BOOL next_token_nr(const char **ptr,char *buff, const char *sep, size_t bufsize)
+BOOL next_token_nr(const char **ptr, char *buff, const char *sep, size_t bufsize)
{
BOOL ret;
if (!ptr)
- ptr = &last_ptr;
+ ptr = (const char **)&last_ptr;
ret = next_token(ptr, buff, sep, bufsize);
last_ptr = *ptr;
@@ -109,7 +100,7 @@ void set_first_token(char *ptr)
char **toktocliplist(int *ctok, const char *sep)
{
- char *s=(char *)last_ptr;
+ char *s=last_ptr;
int ictok=0;
char **ret, **iret;
@@ -132,7 +123,7 @@ char **toktocliplist(int *ctok, const char *sep)
} while(*s);
*ctok=ictok;
- s=(char *)last_ptr;
+ s=last_ptr;
if (!(ret=iret=malloc(ictok*sizeof(char *))))
return NULL;
@@ -149,90 +140,21 @@ char **toktocliplist(int *ctok, const char *sep)
}
/**
- * Case insensitive string compararison.
- *
- * iconv does not directly give us a way to compare strings in
- * arbitrary unix character sets -- all we can is convert and then
- * compare. This is expensive.
- *
- * As an optimization, we do a first pass that considers only the
- * prefix of the strings that is entirely 7-bit. Within this, we
- * check whether they have the same value.
- *
- * Hopefully this will often give the answer without needing to copy.
- * In particular it should speed comparisons to literal ascii strings
- * or comparisons of strings that are "obviously" different.
- *
- * If we find a non-ascii character we fall back to converting via
- * iconv.
- *
- * This should never be slower than convering the whole thing, and
- * often faster.
- *
- * A different optimization would be to compare for bitwise equality
- * in the binary encoding. (It would be possible thought hairy to do
- * both simultaneously.) But in that case if they turn out to be
- * different, we'd need to restart the whole thing.
- *
- * Even better is to implement strcasecmp for each encoding and use a
- * function pointer.
- **/
+ Case insensitive string compararison.
+**/
+
int StrCaseCmp(const char *s, const char *t)
{
-
- const char * ps, * pt;
- size_t size;
- smb_ucs2_t *buffer_s, *buffer_t;
- int ret;
-
- for (ps = s, pt = t; ; ps++, pt++) {
- char us, ut;
-
- if (!*ps && !*pt)
- return 0; /* both ended */
- else if (!*ps)
- return -1; /* s is a prefix */
- else if (!*pt)
- return +1; /* t is a prefix */
- else if ((*ps & 0x80) || (*pt & 0x80))
- /* not ascii anymore, do it the hard way from here on in */
- break;
-
- us = toupper(*ps);
- ut = toupper(*pt);
- if (us == ut)
- continue;
- else if (us < ut)
- return -1;
- else if (us > ut)
- return +1;
- }
-
- size = push_ucs2_allocate(&buffer_s, s);
- if (size == (size_t)-1) {
- return strcmp(s, t);
- /* Not quite the right answer, but finding the right one
- under this failure case is expensive, and it's pretty close */
- }
-
- size = push_ucs2_allocate(&buffer_t, t);
- if (size == (size_t)-1) {
- SAFE_FREE(buffer_s);
- return strcmp(s, t);
- /* Not quite the right answer, but finding the right one
- under this failure case is expensive, and it's pretty close */
- }
-
- ret = strcasecmp_w(buffer_s, buffer_t);
- SAFE_FREE(buffer_s);
- SAFE_FREE(buffer_t);
- return ret;
+ pstring buf1, buf2;
+ unix_strupper(s, strlen(s)+1, buf1, sizeof(buf1));
+ unix_strupper(t, strlen(t)+1, buf2, sizeof(buf2));
+ return strcmp(buf1,buf2);
}
-
/**
Case insensitive string compararison, length limited.
**/
+
int StrnCaseCmp(const char *s, const char *t, size_t n)
{
pstring buf1, buf2;
@@ -315,80 +237,33 @@ int strwicmp(const char *psz1, const char *psz2)
return (*psz1 - *psz2);
}
-
/**
Convert a string to upper case, but don't modify it.
**/
-char *strupper_static(const char *s)
+char *strupper_talloc(TALLOC_CTX *mem_ctx, const char *s)
{
- static pstring str;
+ char *str;
- pstrcpy(str, s);
- strupper_m(str);
+ str = talloc_strdup(mem_ctx, s);
+ strupper(str);
return str;
}
-/**
- Convert a string to "normal" form.
-**/
-
-void strnorm(char *s)
-{
- extern int case_default;
- if (case_default == CASE_UPPER)
- strupper_m(s);
- else
- strlower_m(s);
-}
-
-/**
- Check if a string is in "normal" case.
-**/
-
-BOOL strisnormal(const char *s)
-{
- extern int case_default;
- if (case_default == CASE_UPPER)
- return(!strhaslower(s));
-
- return(!strhasupper(s));
-}
-
/**
String replace.
NOTE: oldc and newc must be 7 bit characters
**/
-void string_replace(pstring s,char oldc,char newc)
+void string_replace(char *s,char oldc,char newc)
{
- unsigned char *p;
-
- /* this is quite a common operation, so we want it to be
- fast. We optimise for the ascii case, knowing that all our
- supported multi-byte character sets are ascii-compatible
- (ie. they match for the first 128 chars) */
-
- for (p = (unsigned char *)s; *p; p++) {
- if (*p & 0x80) /* mb string - slow path. */
- break;
- if (*p == oldc)
- *p = newc;
+ if (strchr(s, oldc)) {
+ push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+ string_replace_w(tmpbuf, UCS2_CHAR(oldc), UCS2_CHAR(newc));
+ pull_ucs2(NULL, s, tmpbuf, strlen(s)+1, sizeof(tmpbuf), STR_TERMINATE);
}
-
- if (!*p)
- return;
-
- /* Slow (mb) path. */
-#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
- /* With compose characters we must restart from the beginning. JRA. */
- p = s;
-#endif
- push_ucs2(NULL, tmpbuf, p, sizeof(tmpbuf), STR_TERMINATE);
- string_replace_w(tmpbuf, UCS2_CHAR(oldc), UCS2_CHAR(newc));
- pull_ucs2(NULL, p, tmpbuf, -1, sizeof(tmpbuf), STR_TERMINATE);
}
/**
@@ -428,59 +303,6 @@ size_t str_ascii_charnum(const char *s)
return strlen(tmpbuf2);
}
-BOOL trim_char(char *s,char cfront,char cback)
-{
- BOOL ret = False;
- char *ep;
- char *fp = s;
-
- /* Ignore null or empty strings. */
- if (!s || (s[0] == '\0'))
- return False;
-
- if (cfront) {
- while (*fp && *fp == cfront)
- fp++;
- if (!*fp) {
- /* We ate the string. */
- s[0] = '\0';
- return True;
- }
- if (fp != s)
- ret = True;
- }
-
- ep = fp + strlen(fp) - 1;
- if (cback) {
- /* Attempt ascii only. Bail for mb strings. */
- while ((ep >= fp) && (*ep == cback)) {
- ret = True;
- if ((ep > fp) && (((unsigned char)ep[-1]) & 0x80)) {
- /* Could be mb... bail back to tim_string. */
- char fs[2], bs[2];
- if (cfront) {
- fs[0] = cfront;
- fs[1] = '\0';
- }
- bs[0] = cback;
- bs[1] = '\0';
- return trim_string(s, cfront ? fs : NULL, bs);
- } else {
- ep--;
- }
- }
- if (ep < fp) {
- /* We ate the string. */
- s[0] = '\0';
- return True;
- }
- }
-
- ep[1] = '\0';
- memmove(s, fp, ep-fp+2);
- return ret;
-}
-
/**
Trim the specified elements off the front and back of a string.
**/
@@ -503,9 +325,7 @@ BOOL trim_string(char *s,const char *front,const char *back)
if (front_len) {
while (len && strncmp(s, front, front_len)==0) {
- /* Must use memmove here as src & dest can
- * easily overlap. Found by valgrind. JRA. */
- memmove(s, s+front_len, (len-front_len)+1);
+ memcpy(s, s+front_len, (len-front_len)+1);
len -= front_len;
ret=True;
}
@@ -557,36 +377,57 @@ size_t count_chars(const char *s,char c)
{
smb_ucs2_t *ptr;
int count;
- smb_ucs2_t *alloc_tmpbuf = NULL;
-
- if (push_ucs2_allocate(&alloc_tmpbuf, s) == (size_t)-1) {
- return 0;
- }
-
- for(count=0,ptr=alloc_tmpbuf;*ptr;ptr++)
+ push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+ for(count=0,ptr=tmpbuf;*ptr;ptr++)
if(*ptr==UCS2_CHAR(c))
count++;
-
- SAFE_FREE(alloc_tmpbuf);
return(count);
}
/**
+Return True if a string consists only of one particular character.
+**/
+
+BOOL str_is_all(const char *s,char c)
+{
+ smb_ucs2_t *ptr;
+
+ if(s == NULL)
+ return False;
+ if(!*s)
+ return False;
+
+ push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+ for(ptr=tmpbuf;*ptr;ptr++)
+ if(*ptr!=UCS2_CHAR(c))
+ return False;
+
+ return True;
+}
+
+/**
Safe string copy into a known length string. maxlength does not
include the terminating zero.
**/
-char *safe_strcpy_fn(const char *fn, int line, char *dest,const char *src, size_t maxlength)
+char *safe_strcpy(char *dest,const char *src, size_t maxlength)
{
size_t len;
if (!dest) {
- DEBUG(0,("ERROR: NULL dest in safe_strcpy, called from [%s][%d]\n", fn, line));
+ DEBUG(0,("ERROR: NULL dest in safe_strcpy\n"));
return NULL;
}
#ifdef DEVELOPER
- clobber_region(fn,line,dest, maxlength+1);
+ /* We intentionally write out at the extremity of the destination
+ * string. If the destination is too short (e.g. pstrcpy into mallocd
+ * or fstring) then this should cause an error under a memory
+ * checker. */
+ dest[maxlength] = '\0';
+ if (PTR_DIFF(&len, dest) > 0) { /* check if destination is on the stack, ok if so */
+ log_suspicious_usage("safe_strcpy", src);
+ }
#endif
if (!src) {
@@ -594,12 +435,11 @@ char *safe_strcpy_fn(const char *fn, int line, char *dest,const char *src, size_
return dest;
}
- len = strnlen(src, maxlength+1);
+ len = strlen(src);
if (len > maxlength) {
- DEBUG(0,("ERROR: string overflow by %lu (%lu - %lu) in safe_strcpy [%.50s]\n",
- (unsigned long)(len-maxlength), (unsigned long)len,
- (unsigned long)maxlength, src));
+ DEBUG(0,("ERROR: string overflow by %u (%u - %u) in safe_strcpy [%.50s]\n",
+ (unsigned int)(len-maxlength), len, maxlength, src));
len = maxlength;
}
@@ -612,24 +452,26 @@ char *safe_strcpy_fn(const char *fn, int line, char *dest,const char *src, size_
Safe string cat into a string. maxlength does not
include the terminating zero.
**/
-char *safe_strcat_fn(const char *fn, int line, char *dest, const char *src, size_t maxlength)
+
+char *safe_strcat(char *dest, const char *src, size_t maxlength)
{
size_t src_len, dest_len;
if (!dest) {
- DEBUG(0,("ERROR: NULL dest in safe_strcat, called from [%s][%d]\n", fn, line));
+ DEBUG(0,("ERROR: NULL dest in safe_strcat\n"));
return NULL;
}
if (!src)
return dest;
- src_len = strnlen(src, maxlength + 1);
- dest_len = strnlen(dest, maxlength + 1);
-
#ifdef DEVELOPER
- clobber_region(fn, line, dest + dest_len, maxlength + 1 - dest_len);
+ if (PTR_DIFF(&src_len, dest) > 0) { /* check if destination is on the stack, ok if so */
+ log_suspicious_usage("safe_strcat", src);
+ }
#endif
+ src_len = strlen(src);
+ dest_len = strlen(dest);
if (src_len + dest_len > maxlength) {
DEBUG(0,("ERROR: string overflow by %d in safe_strcat [%.50s]\n",
@@ -640,7 +482,7 @@ char *safe_strcat_fn(const char *fn, int line, char *dest, const char *src, size
dest[maxlength] = 0;
return NULL;
}
-
+
memcpy(&dest[dest_len], src, src_len);
dest[dest_len + src_len] = 0;
return dest;
@@ -652,16 +494,18 @@ char *safe_strcat_fn(const char *fn, int line, char *dest, const char *src, size
and replaces with '_'. Deliberately does *NOT* check for multibyte
characters. Don't change it !
**/
-char *alpha_strcpy_fn(const char *fn, int line, char *dest, const char *src, const char *other_safe_chars, size_t maxlength)
+
+char *alpha_strcpy(char *dest, const char *src, const char *other_safe_chars, size_t maxlength)
{
size_t len, i;
-#ifdef DEVELOPER
- clobber_region(fn, line, dest, maxlength);
-#endif
+ if (maxlength == 0) {
+ /* can't fit any bytes at all! */
+ return NULL;
+ }
if (!dest) {
- DEBUG(0,("ERROR: NULL dest in alpha_strcpy, called from [%s][%d]\n", fn, line));
+ DEBUG(0,("ERROR: NULL dest in alpha_strcpy\n"));
return NULL;
}
@@ -694,47 +538,32 @@ char *alpha_strcpy_fn(const char *fn, int line, char *dest, const char *src, con
Like strncpy but always null terminates. Make sure there is room!
The variable n should always be one less than the available size.
**/
-char *StrnCpy_fn(const char *fn, int line,char *dest,const char *src,size_t n)
+
+char *StrnCpy(char *dest,const char *src,size_t n)
{
char *d = dest;
-
-#ifdef DEVELOPER
- clobber_region(fn, line, dest, n+1);
-#endif
-
- if (!dest) {
- DEBUG(0,("ERROR: NULL dest in StrnCpy, called from [%s][%d]\n", fn, line));
+ if (!dest)
return(NULL);
- }
-
if (!src) {
*dest = 0;
return(dest);
}
-
- while (n-- && (*d = *src)) {
- d++;
- src++;
- }
-
+ while (n-- && (*d++ = *src++))
+ ;
*d = 0;
return(dest);
}
-#if 0
/**
Like strncpy but copies up to the character marker. always null terminates.
returns a pointer to the character marker in the source string (src).
**/
-static char *strncpyn(char *dest, const char *src, size_t n, char c)
+char *strncpyn(char *dest, const char *src, size_t n, char c)
{
char *p;
size_t str_len;
-#ifdef DEVELOPER
- clobber_region(dest, n+1);
-#endif
p = strchr_m(src, c);
if (p == NULL) {
DEBUG(5, ("strncpyn: separator character (%c) not found\n", c));
@@ -747,7 +576,6 @@ static char *strncpyn(char *dest, const char *src, size_t n, char c)
return p;
}
-#endif
/**
Routine to get hex characters and turn them into a 16 byte array.
@@ -795,26 +623,10 @@ size_t strhex_to_str(char *p, size_t len, const char *strhex)
}
/**
- * Routine to print a buffer as HEX digits, into an allocated string.
- */
-
-void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer)
-{
- int i;
- char *hex_buffer;
-
- *out_hex_buffer = smb_xmalloc((len*2)+1);
- hex_buffer = *out_hex_buffer;
-
- for (i = 0; i < len; i++)
- slprintf(&hex_buffer[i*2], 3, "%02X", buff_in[i]);
-}
-
-/**
Check if a string is part of a list.
**/
-BOOL in_list(char *s,char *list,BOOL casesensitive)
+BOOL in_list(const char *s, const char *list, BOOL casesensitive)
{
pstring tok;
const char *p=list;
@@ -834,62 +646,37 @@ BOOL in_list(char *s,char *list,BOOL casesensitive)
return(False);
}
-/* this is used to prevent lots of mallocs of size 1 */
-static char *null_string = NULL;
-
/**
Set a string value, allocing the space for the string
**/
-
static BOOL string_init(char **dest,const char *src)
{
- size_t l;
- if (!src)
- src = "";
-
- l = strlen(src);
+ if (!src) src = "";
- if (l == 0) {
- if (!null_string) {
- if((null_string = (char *)malloc(1)) == NULL) {
- DEBUG(0,("string_init: malloc fail for null_string.\n"));
- return False;
- }
- *null_string = 0;
- }
- *dest = null_string;
- } else {
- (*dest) = strdup(src);
- if ((*dest) == NULL) {
- DEBUG(0,("Out of memory in string_init\n"));
- return False;
- }
+ (*dest) = strdup(src);
+ if ((*dest) == NULL) {
+ DEBUG(0,("Out of memory in string_init\n"));
+ return False;
}
- return(True);
+ return True;
}
/**
Free a string value.
**/
-
void string_free(char **s)
{
- if (!s || !(*s))
- return;
- if (*s == null_string)
- *s = NULL;
- SAFE_FREE(*s);
+ if (s) SAFE_FREE(*s);
}
/**
Set a string value, deallocating any existing space, and allocing the space
for the string
**/
-
-BOOL string_set(char **dest,const char *src)
+BOOL string_set(char **dest, const char *src)
{
string_free(dest);
- return(string_init(dest,src));
+ return string_init(dest,src);
}
/**
@@ -919,7 +706,7 @@ void string_sub(char *s,const char *pattern, const char *insert, size_t len)
if (len == 0)
len = ls + 1; /* len is number of *bytes* */
- while (lp <= ls && (p = strstr_m(s,pattern))) {
+ while (lp <= ls && (p = strstr(s,pattern))) {
if (ls + (li-lp) >= len) {
DEBUG(0,("ERROR: string overflow by %d in string_sub(%.50s, %d)\n",
(int)(ls + (li-lp) - len),
@@ -950,11 +737,6 @@ void string_sub(char *s,const char *pattern, const char *insert, size_t len)
}
}
-void fstring_sub(char *s,const char *pattern,const char *insert)
-{
- string_sub(s, pattern, insert, sizeof(fstring));
-}
-
void pstring_sub(char *s,const char *pattern,const char *insert)
{
string_sub(s, pattern, insert, sizeof(pstring));
@@ -1004,9 +786,8 @@ char *realloc_string_sub(char *string, const char *pattern, const char *insert)
}
}
- while ((p = strstr_m(s,pattern))) {
+ while ((p = strstr(s,pattern))) {
if (ld > 0) {
- int offset = PTR_DIFF(s,string);
char *t = Realloc(string, ls + ld + 1);
if (!t) {
DEBUG(0, ("realloc_string_sub: out of memory!\n"));
@@ -1014,7 +795,7 @@ char *realloc_string_sub(char *string, const char *pattern, const char *insert)
return NULL;
}
string = t;
- p = t + offset + (p - s);
+ p = t + (p - s);
}
if (li != lp) {
memmove(p+li,p+lp,strlen(p+lp)+1);
@@ -1052,7 +833,7 @@ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
if (len == 0)
len = ls + 1; /* len is number of *bytes* */
- while (lp <= ls && (p = strstr_m(s,pattern))) {
+ while (lp <= ls && (p = strstr(s,pattern))) {
if (ls + (li-lp) >= len) {
DEBUG(0,("ERROR: string overflow by %d in all_string_sub(%.50s, %d)\n",
(int)(ls + (li-lp) - len),
@@ -1069,76 +850,10 @@ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
}
/**
- Similar to all_string_sub but for unicode strings.
- Return a new allocated unicode string.
- similar to string_sub() but allows for any character to be substituted.
- Use with caution!
-**/
-
-static smb_ucs2_t *all_string_sub_w(const smb_ucs2_t *s, const smb_ucs2_t *pattern,
- const smb_ucs2_t *insert)
-{
- smb_ucs2_t *r, *rp;
- const smb_ucs2_t *sp;
- size_t lr, lp, li, lt;
-
- if (!insert || !pattern || !*pattern || !s)
- return NULL;
-
- lt = (size_t)strlen_w(s);
- lp = (size_t)strlen_w(pattern);
- li = (size_t)strlen_w(insert);
-
- if (li > lp) {
- const smb_ucs2_t *st = s;
- int ld = li - lp;
- while ((sp = strstr_w(st, pattern))) {
- st = sp + lp;
- lt += ld;
- }
- }
-
- r = rp = (smb_ucs2_t *)malloc((lt + 1)*(sizeof(smb_ucs2_t)));
- if (!r) {
- DEBUG(0, ("all_string_sub_w: out of memory!\n"));
- return NULL;
- }
-
- while ((sp = strstr_w(s, pattern))) {
- memcpy(rp, s, (sp - s));
- rp += ((sp - s) / sizeof(smb_ucs2_t));
- memcpy(rp, insert, (li * sizeof(smb_ucs2_t)));
- s = sp + lp;
- rp += li;
- }
- lr = ((rp - r) / sizeof(smb_ucs2_t));
- if (lr < lt) {
- memcpy(rp, s, ((lt - lr) * sizeof(smb_ucs2_t)));
- rp += (lt - lr);
- }
- *rp = 0;
-
- return r;
-}
-
-smb_ucs2_t *all_string_sub_wa(smb_ucs2_t *s, const char *pattern,
- const char *insert)
-{
- wpstring p, i;
-
- if (!insert || !pattern || !s)
- return NULL;
- push_ucs2(NULL, p, pattern, sizeof(wpstring) - 1, STR_TERMINATE);
- push_ucs2(NULL, i, insert, sizeof(wpstring) - 1, STR_TERMINATE);
- return all_string_sub_w(s, p, i);
-}
-
-#if 0
-/**
Splits out the front and back at a separator.
**/
-static void split_at_last_component(char *path, char *front, char sep, char *back)
+void split_at_last_component(char *path, char *front, char sep, char *back)
{
char *p = strrchr_m(path, sep);
@@ -1157,7 +872,6 @@ static void split_at_last_component(char *path, char *front, char sep, char *bac
back[0] = 0;
}
}
-#endif
/**
Write an octal as a string.
@@ -1177,7 +891,7 @@ const char *octal_string(int i)
Truncate a string at a specified length.
**/
-char *string_truncate(char *s, unsigned int length)
+char *string_truncate(char *s, int length)
{
if (s && strlen(s) > length)
s[length] = 0;
@@ -1189,30 +903,11 @@ char *string_truncate(char *s, unsigned int length)
We convert via ucs2 for now.
**/
-char *strchr_m(const char *src, char c)
+char *strchr_m(const char *s, char c)
{
wpstring ws;
pstring s2;
smb_ucs2_t *p;
- const char *s;
-
- /* this is quite a common operation, so we want it to be
- fast. We optimise for the ascii case, knowing that all our
- supported multi-byte character sets are ascii-compatible
- (ie. they match for the first 128 chars) */
-
- for (s = src; *s && !(((unsigned char)s[0]) & 0x80); s++) {
- if (*s == c)
- return (char *)s;
- }
-
- if (!*s)
- return NULL;
-
-#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
- /* With compose characters we must restart from the beginning. JRA. */
- s = src;
-#endif
push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE);
p = strchr_w(ws, UCS2_CHAR(c));
@@ -1225,68 +920,12 @@ char *strchr_m(const char *src, char c)
char *strrchr_m(const char *s, char c)
{
- /* this is quite a common operation, so we want it to be
- fast. We optimise for the ascii case, knowing that all our
- supported multi-byte character sets are ascii-compatible
- (ie. they match for the first 128 chars). Also, in Samba
- we only search for ascii characters in 'c' and that
- in all mb character sets with a compound character
- containing c, if 'c' is not a match at position
- p, then p[-1] > 0x7f. JRA. */
-
- {
- size_t len = strlen(s);
- const char *cp = s;
- BOOL got_mb = False;
-
- if (len == 0)
- return NULL;
- cp += (len - 1);
- do {
- if (c == *cp) {
- /* Could be a match. Part of a multibyte ? */
- if ((cp > s) && (((unsigned char)cp[-1]) & 0x80)) {
- /* Yep - go slow :-( */
- got_mb = True;
- break;
- }
- /* No - we have a match ! */
- return (char *)cp;
- }
- } while (cp-- != s);
- if (!got_mb)
- return NULL;
- }
-
- /* String contained a non-ascii char. Slow path. */
- {
- wpstring ws;
- pstring s2;
- smb_ucs2_t *p;
-
- push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE);
- p = strrchr_w(ws, UCS2_CHAR(c));
- if (!p)
- return NULL;
- *p = 0;
- pull_ucs2_pstring(s2, ws);
- return (char *)(s+strlen(s2));
- }
-}
-
-/***********************************************************************
- Return the equivalent of doing strrchr 'n' times - always going
- backwards.
-***********************************************************************/
-
-char *strnrchr_m(const char *s, char c, unsigned int n)
-{
wpstring ws;
pstring s2;
smb_ucs2_t *p;
push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE);
- p = strnrchr_w(ws, UCS2_CHAR(c), n);
+ p = strrchr_w(ws, UCS2_CHAR(c));
if (!p)
return NULL;
*p = 0;
@@ -1294,101 +933,18 @@ char *strnrchr_m(const char *s, char c, unsigned int n)
return (char *)(s+strlen(s2));
}
-/***********************************************************************
- strstr_m - We convert via ucs2 for now.
-***********************************************************************/
-
-char *strstr_m(const char *src, const char *findstr)
-{
- smb_ucs2_t *p;
- smb_ucs2_t *src_w, *find_w;
- const char *s;
- char *s2;
- char *retp;
-
- size_t findstr_len = 0;
-
- /* for correctness */
- if (!findstr[0]) {
- return src;
- }
-
- /* Samba does single character findstr calls a *lot*. */
- if (findstr[1] == '\0')
- return strchr_m(src, *findstr);
-
- /* We optimise for the ascii case, knowing that all our
- supported multi-byte character sets are ascii-compatible
- (ie. they match for the first 128 chars) */
-
- for (s = src; *s && !(((unsigned char)s[0]) & 0x80); s++) {
- if (*s == *findstr) {
- if (!findstr_len)
- findstr_len = strlen(findstr);
-
- if (strncmp(s, findstr, findstr_len) == 0) {
- return (char *)s;
- }
- }
- }
-
- if (!*s)
- return NULL;
-
-#if 1 /* def BROKEN_UNICODE_COMPOSE_CHARACTERS */
- /* 'make check' fails unless we do this */
-
- /* With compose characters we must restart from the beginning. JRA. */
- s = src;
-#endif
-
- if (push_ucs2_allocate(&src_w, src) == (size_t)-1) {
- DEBUG(0,("strstr_m: src malloc fail\n"));
- return NULL;
- }
-
- if (push_ucs2_allocate(&find_w, findstr) == (size_t)-1) {
- SAFE_FREE(src_w);
- DEBUG(0,("strstr_m: find malloc fail\n"));
- return NULL;
- }
-
- p = strstr_w(src_w, find_w);
-
- if (!p) {
- SAFE_FREE(src_w);
- SAFE_FREE(find_w);
- return NULL;
- }
-
- *p = 0;
- if (pull_ucs2_allocate(&s2, src_w) == (size_t)-1) {
- SAFE_FREE(src_w);
- SAFE_FREE(find_w);
- DEBUG(0,("strstr_m: dest malloc fail\n"));
- return NULL;
- }
- retp = (char *)(s+strlen(s2));
- SAFE_FREE(src_w);
- SAFE_FREE(find_w);
- SAFE_FREE(s2);
- return retp;
-}
-
/**
Convert a string to lower case.
**/
void strlower_m(char *s)
{
- size_t len;
-
/* this is quite a common operation, so we want it to be
fast. We optimise for the ascii case, knowing that all our
supported multi-byte character sets are ascii-compatible
(ie. they match for the first 128 chars) */
- while (*s && !(((unsigned char)s[0]) & 0x80)) {
+ while (*s && !(((unsigned char)s[0]) & 0x7F)) {
*s = tolower((unsigned char)*s);
s++;
}
@@ -1398,12 +954,22 @@ void strlower_m(char *s)
/* I assume that lowercased string takes the same number of bytes
* as source string even in UTF-8 encoding. (VIV) */
- len = strlen(s) + 1;
- errno = 0;
- unix_strlower(s,len,s,len);
- /* Catch mb conversion errors that may not terminate. */
- if (errno)
- s[len-1] = '\0';
+ unix_strlower(s,strlen(s)+1,s,strlen(s)+1);
+}
+
+/**
+ Duplicate convert a string to lower case.
+**/
+
+char *strdup_lower(const char *s)
+{
+ char *t = strdup(s);
+ if (t == NULL) {
+ DEBUG(0, ("strdup_lower: Out of memory!\n"));
+ return NULL;
+ }
+ strlower_m(t);
+ return t;
}
/**
@@ -1412,14 +978,12 @@ void strlower_m(char *s)
void strupper_m(char *s)
{
- size_t len;
-
/* this is quite a common operation, so we want it to be
fast. We optimise for the ascii case, knowing that all our
supported multi-byte character sets are ascii-compatible
(ie. they match for the first 128 chars) */
- while (*s && !(((unsigned char)s[0]) & 0x80)) {
+ while (*s && !(((unsigned char)s[0]) & 0x7F)) {
*s = toupper((unsigned char)*s);
s++;
}
@@ -1429,12 +993,60 @@ void strupper_m(char *s)
/* I assume that lowercased string takes the same number of bytes
* as source string even in multibyte encoding. (VIV) */
- len = strlen(s) + 1;
- errno = 0;
- unix_strupper(s,len,s,len);
- /* Catch mb conversion errors that may not terminate. */
- if (errno)
- s[len-1] = '\0';
+ unix_strupper(s,strlen(s)+1,s,strlen(s)+1);
+}
+
+
+/**
+ work out the number of multibyte chars in a string
+**/
+size_t strlen_m(const char *s)
+{
+ size_t count = 0;
+
+ if (!s) {
+ return 0;
+ }
+
+ while (*s && !(((unsigned char)s[0]) & 0x7F)) {
+ s++;
+ count++;
+ }
+
+ if (!*s) {
+ return count;
+ }
+
+ push_ucs2(NULL,tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
+ return count + strlen_w(tmpbuf);
+}
+
+/**
+ Work out the number of multibyte chars in a string, including the NULL
+ terminator.
+**/
+size_t strlen_m_term(const char *s)
+{
+ if (!s) {
+ return 0;
+ }
+
+ return strlen_m(s) + 1;
+}
+
+/**
+ Convert a string to upper case.
+**/
+
+char *strdup_upper(const char *s)
+{
+ char *t = strdup(s);
+ if (t == NULL) {
+ DEBUG(0, ("strdup_upper: Out of memory!\n"));
+ return NULL;
+ }
+ strupper_m(t);
+ return t;
}
/**
@@ -1476,28 +1088,10 @@ char *binary_string(char *buf, int len)
return ret;
}
-
-/**
- Just a typesafety wrapper for snprintf into a fstring.
-**/
-
-int fstr_sprintf(fstring s, const char *fmt, ...)
-{
- va_list ap;
- int ret;
-
- va_start(ap, fmt);
- ret = vsnprintf(s, FSTRING_LEN, fmt, ap);
- va_end(ap);
- return ret;
-}
-
-
#ifndef HAVE_STRNDUP
/**
Some platforms don't have strndup.
**/
-
char *strndup(const char *s, size_t n)
{
char *ret;
@@ -1517,7 +1111,6 @@ int fstr_sprintf(fstring s, const char *fmt, ...)
/**
Some platforms don't have strnlen
**/
-
size_t strnlen(const char *s, size_t n)
{
int i;
@@ -1656,35 +1249,6 @@ void str_list_free(char ***list)
SAFE_FREE(*list);
}
-/******************************************************************************
- version of standard_sub_basic() for string lists; uses alloc_sub_basic()
- for the work
- *****************************************************************************/
-
-BOOL str_list_sub_basic( char **list, const char *smb_name )
-{
- char *s, *tmpstr;
-
- while ( *list ) {
- s = *list;
- tmpstr = alloc_sub_basic(smb_name, s);
- if ( !tmpstr ) {
- DEBUG(0,("str_list_sub_basic: alloc_sub_basic() return NULL!\n"));
- return False;
- }
-
- *list = tmpstr;
-
- list++;
- }
-
- return True;
-}
-
-/******************************************************************************
- substritute a specific pattern in a string list
- *****************************************************************************/
-
BOOL str_list_substitute(char **list, const char *pattern, const char *insert)
{
char *p, *s, *t;
@@ -1705,7 +1269,7 @@ BOOL str_list_substitute(char **list, const char *pattern, const char *insert)
s = *list;
ls = (ssize_t)strlen(s);
- while ((p = strstr_m(s, pattern))) {
+ while ((p = strstr(s, pattern))) {
t = *list;
d = p -t;
if (ld) {
@@ -1740,7 +1304,6 @@ BOOL str_list_substitute(char **list, const char *pattern, const char *insert)
}
}
-
list++;
}
@@ -1749,7 +1312,6 @@ BOOL str_list_substitute(char **list, const char *pattern, const char *insert)
#define IPSTR_LIST_SEP ","
-#define IPSTR_LIST_CHAR ','
/**
* Add ip string representation to ipstr list. Used also
@@ -1764,20 +1326,19 @@ BOOL str_list_substitute(char **list, const char *pattern, const char *insert)
* reallocated to new length
**/
-char* ipstr_list_add(char** ipstr_list, const struct ip_service *service)
+char* ipstr_list_add(char** ipstr_list, const struct in_addr *ip)
{
char* new_ipstr = NULL;
/* arguments checking */
- if (!ipstr_list || !service) return NULL;
+ if (!ipstr_list || !ip) return NULL;
/* attempt to convert ip to a string and append colon separator to it */
if (*ipstr_list) {
- asprintf(&new_ipstr, "%s%s%s:%d", *ipstr_list, IPSTR_LIST_SEP,
- inet_ntoa(service->ip), service->port);
+ asprintf(&new_ipstr, "%s%s%s", *ipstr_list, IPSTR_LIST_SEP,inet_ntoa(*ip));
SAFE_FREE(*ipstr_list);
} else {
- asprintf(&new_ipstr, "%s:%d", inet_ntoa(service->ip), service->port);
+ asprintf(&new_ipstr, "%s", inet_ntoa(*ip));
}
*ipstr_list = new_ipstr;
return *ipstr_list;
@@ -1794,7 +1355,7 @@ char* ipstr_list_add(char** ipstr_list, const struct ip_service *service)
* @return pointer to allocated ip string
**/
-char* ipstr_list_make(char** ipstr_list, const struct ip_service* ip_list, int ip_count)
+char* ipstr_list_make(char** ipstr_list, const struct in_addr* ip_list, int ip_count)
{
int i;
@@ -1813,8 +1374,7 @@ char* ipstr_list_make(char** ipstr_list, const struct ip_service* ip_list, int i
/**
* Parse given ip string list into array of ip addresses
- * (as ip_service structures)
- * e.g. 192.168.1.100:389,192.168.1.78, ...
+ * (as in_addr structures)
*
* @param ipstr ip string list to be parsed
* @param ip_list pointer to array of ip addresses which is
@@ -1822,40 +1382,28 @@ char* ipstr_list_make(char** ipstr_list, const struct ip_service* ip_list, int i
* @return number of succesfully parsed addresses
**/
-int ipstr_list_parse(const char* ipstr_list, struct ip_service **ip_list)
+int ipstr_list_parse(const char* ipstr_list, struct in_addr** ip_list)
{
fstring token_str;
- size_t count;
- int i;
+ int count;
- if (!ipstr_list || !ip_list)
- return 0;
-
- count = count_chars(ipstr_list, IPSTR_LIST_CHAR) + 1;
- if ( (*ip_list = (struct ip_service*)malloc(count * sizeof(struct ip_service))) == NULL ) {
- DEBUG(0,("ipstr_list_parse: malloc failed for %lu entries\n", (unsigned long)count));
- return 0;
- }
+ if (!ipstr_list || !ip_list) return 0;
- for ( i=0;
- next_token(&ipstr_list, token_str, IPSTR_LIST_SEP, FSTRING_LEN) && i<count;
- i++ )
- {
+ for (*ip_list = NULL, count = 0;
+ next_token(&ipstr_list, token_str, IPSTR_LIST_SEP, FSTRING_LEN);
+ count++) {
+
struct in_addr addr;
- unsigned port = 0;
- char *p = strchr(token_str, ':');
-
- if (p) {
- *p = 0;
- port = atoi(p+1);
- }
/* convert single token to ip address */
if ( (addr.s_addr = inet_addr(token_str)) == INADDR_NONE )
break;
-
- (*ip_list)[i].ip = addr;
- (*ip_list)[i].port = port;
+
+ /* prepare place for another in_addr structure */
+ *ip_list = Realloc(*ip_list, (count + 1) * sizeof(struct in_addr));
+ if (!*ip_list) return -1;
+
+ (*ip_list)[count] = addr;
}
return count;
@@ -1882,6 +1430,11 @@ void rfc1738_unescape(char *buf)
{
char *p=buf;
+ while ((p=strchr_m(p,'+')))
+ *p = ' ';
+
+ p = buf;
+
while (p && *p && (p=strchr_m(p,'%'))) {
int c1 = p[1];
int c2 = p[2];
@@ -1940,8 +1493,6 @@ DATA_BLOB base64_decode_data_blob(const char *s)
s++; i++;
}
- if (*s == '=') n -= 1;
-
/* fix up length */
decoded.length = n;
return decoded;
@@ -1954,10 +1505,10 @@ void base64_decode_inplace(char *s)
{
DATA_BLOB decoded = base64_decode_data_blob(s);
memcpy(s, decoded.data, decoded.length);
+ data_blob_free(&decoded);
+
/* null terminate */
s[decoded.length] = '\0';
-
- data_blob_free(&decoded);
}
/**
@@ -2005,43 +1556,12 @@ char * base64_encode_data_blob(DATA_BLOB data)
return result;
}
-/* read a SMB_BIG_UINT from a string */
-SMB_BIG_UINT STR_TO_SMB_BIG_UINT(const char *nptr, const char **entptr)
-{
-
- SMB_BIG_UINT val = -1;
- const char *p = nptr;
-
- while (p && *p && isspace(*p))
- p++;
-#ifdef LARGE_SMB_OFF_T
- sscanf(p,"%llu",&val);
-#else /* LARGE_SMB_OFF_T */
- sscanf(p,"%lu",&val);
-#endif /* LARGE_SMB_OFF_T */
- if (entptr) {
- while (p && *p && isdigit(*p))
- p++;
- *entptr = p;
- }
-
- return val;
-}
-
-void string_append(char **left, const char *right)
+#ifdef VALGRIND
+size_t valgrind_strlen(const char *s)
{
- int new_len = strlen(right) + 1;
-
- if (*left == NULL) {
- *left = malloc(new_len);
- *left[0] = '\0';
- } else {
- new_len += strlen(*left);
- *left = Realloc(*left, new_len);
- }
-
- if (*left == NULL)
- return;
-
- safe_strcat(*left, right, new_len-1);
+ size_t count;
+ for(count = 0; *s++; count++)
+ ;
+ return count;
}
+#endif
diff --git a/source/lib/util_unistr.c b/source/lib/util_unistr.c
index 005f10a4c0a..5e48d716b98 100644
--- a/source/lib/util_unistr.c
+++ b/source/lib/util_unistr.c
@@ -21,47 +21,41 @@
#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;
-/**
- * This table says which Unicode characters are valid dos
- * characters.
- *
- * Each value is just a single bit.
- **/
-static uint8 doschar_table[8192]; /* 65536 characters / 8 bits/byte */
-
-/**
- * Load or generate the case handling tables.
- *
- * The case tables are defined in UCS2 and don't depend on any
- * configured parameters, so they never need to be reloaded.
- **/
+/*******************************************************************
+load the case handling tables
+********************************************************************/
void load_case_tables(void)
{
static int initialised;
int i;
+ TALLOC_CTX *mem_ctx;
if (initialised) return;
initialised = 1;
- upcase_table = map_file(lib_path("upcase.dat"), 0x20000);
- lowcase_table = map_file(lib_path("lowcase.dat"), 0x20000);
-
+ 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);
@@ -77,6 +71,9 @@ void load_case_tables(void)
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);
@@ -94,53 +91,18 @@ void load_case_tables(void)
see if a ucs2 character can be mapped correctly to a dos character
and mapped back to the same character in ucs2
*/
-int check_dos_char(smb_ucs2_t c)
-{
- lazy_initialize_conv();
-
- /* Find the right byte, and right bit within the byte; return
- * 1 or 0 */
- return (doschar_table[(c & 0xffff) / 8] & (1 << (c & 7))) != 0;
-}
-
-
-static int check_dos_char_slowly(smb_ucs2_t c)
+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),False);
+ 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,False);
+ len2 = convert_string(CH_DOS, CH_UCS2, buf, len1, &c2, 2);
if (len2 != 2) return 0;
return (c == c2);
}
-
-/**
- * Fill out doschar table the hard way, by examining each character
- **/
-void init_doschar_table(void)
-{
- int i, j, byteval;
-
- /* For each byte of packed table */
-
- for (i = 0; i <= 0xffff; i += 8) {
- byteval = 0;
- for (j = 0; j <= 7; j++) {
- smb_ucs2_t c;
-
- c = i + j;
-
- if (check_dos_char_slowly(c))
- byteval |= 1 << j;
- }
- doschar_table[i/8] = byteval;
- }
-}
-
-
/**
* Load the valid character map table from <tt>valid.dat</tt> or
* create from the configured codepage.
@@ -155,13 +117,19 @@ void init_valid_table(void)
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;
}
- valid_file = map_file(lib_path("valid.dat"), 0x10000);
+ 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;
@@ -176,6 +144,9 @@ void init_valid_table(void)
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);
@@ -187,146 +158,11 @@ void init_valid_table(void)
}
-
-/*******************************************************************
- 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) {
- dest[0] = 0;
- 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);
-}
-
-/*******************************************************************
- Return a DOS codepage version of a little-endian unicode string.
- len is the filename length (ignoring any terminating zero) in uin16
- units. Always null terminates.
- Hack alert: uses fixed buffer(s).
-********************************************************************/
-char *dos_unistrn2(const uint16 *src, int len)
-{
- static char lbufs[8][MAXUNI];
- static int nexti;
- char *lbuf = lbufs[nexti];
- nexti = (nexti+1)%8;
- pull_ucs2(NULL, lbuf, src, MAXUNI-3, len*2, STR_NOALIGN);
- return lbuf;
-}
-
-/*******************************************************************
- 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(const UNISTR2 *str)
-{
- static pstring ret;
- unistr2_to_ascii(ret, str, sizeof(ret));
- return 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)
+static smb_ucs2_t toupper_w(smb_ucs2_t val)
{
return upcase_table[SVAL(&val,0)];
}
@@ -335,7 +171,7 @@ smb_ucs2_t toupper_w(smb_ucs2_t val)
Convert a wchar to lower case.
********************************************************************/
-smb_ucs2_t tolower_w( smb_ucs2_t val )
+static smb_ucs2_t tolower_w( smb_ucs2_t val )
{
return lowcase_table[SVAL(&val,0)];
@@ -359,21 +195,13 @@ BOOL isupper_w(smb_ucs2_t 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; *src++; len++) ;
+ for (len = 0; SVAL(src,0); len++, src++) ;
return len;
}
@@ -385,81 +213,61 @@ size_t strnlen_w(const smb_ucs2_t *src, size_t max)
{
size_t len;
- for(len = 0; *src++ && (len < max); len++) ;
+ for (len = 0; (len < max) && SVAL(src, 0); len++, src++) ;
return len;
}
/*******************************************************************
- Wide strchr().
+wide strchr()
********************************************************************/
-
-smb_ucs2_t *strchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
+const smb_ucs2_t *strchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
{
while (*s != 0) {
- if (c == *s) return (smb_ucs2_t *)s;
+ if (c == *s) return s;
s++;
}
- if (c == *s) return (smb_ucs2_t *)s;
+ if (c == *s) return s;
return NULL;
}
-smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c)
+const smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c)
{
return strchr_w(s, UCS2_CHAR(c));
}
-/*******************************************************************
- Wide strrchr().
-********************************************************************/
-
-smb_ucs2_t *strrchr_w(const smb_ucs2_t *s, smb_ucs2_t 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 (smb_ucs2_t *)p;
+ if (c == *p) return p;
} while (p-- != s);
return NULL;
}
-/*******************************************************************
- Wide version of strrchr that returns after doing strrchr 'n' times.
-********************************************************************/
-
-smb_ucs2_t *strnrchr_w(const smb_ucs2_t *s, smb_ucs2_t c, unsigned int n)
+static int strncmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len)
{
- const smb_ucs2_t *p = s;
- int len = strlen_w(s);
- if (len == 0 || !n)
- return NULL;
- p += (len - 1);
- do {
- if (c == *p)
- n--;
-
- if (!n)
- return (smb_ucs2_t *)p;
- } while (p-- != s);
- return NULL;
+ size_t n = 0;
+ while ((n < len) && *b && *a == *b) { a++; b++; n++;}
+ return (len - n)?(*a - *b):0;
}
+
/*******************************************************************
- Wide strstr().
+wide strstr()
********************************************************************/
-
-smb_ucs2_t *strstr_w(const smb_ucs2_t *s, const smb_ucs2_t *ins)
+const smb_ucs2_t *strstr_w(const smb_ucs2_t *s, const smb_ucs2_t *ins)
{
- smb_ucs2_t *r;
- size_t slen, inslen;
+ const smb_ucs2_t *r;
+ size_t inslen;
if (!s || !*s || !ins || !*ins) return NULL;
- slen = strlen_w(s);
inslen = strlen_w(ins);
- r = (smb_ucs2_t *)s;
+ r = s;
while ((r = strchr_w(r, *ins))) {
if (strncmp_w(r, ins, inslen) == 0) return r;
r++;
@@ -504,34 +312,6 @@ BOOL strupper_w(smb_ucs2_t *s)
}
/*******************************************************************
- convert a string to "normal" form
-********************************************************************/
-void strnorm_w(smb_ucs2_t *s)
-{
- extern int case_default;
- if (case_default == CASE_UPPER)
- strupper_w(s);
- else
- strlower_w(s);
-}
-
-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)
@@ -541,64 +321,6 @@ int strcasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *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
********************************************************************/
@@ -618,43 +340,6 @@ smb_ucs2_t *strncpy_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
/*******************************************************************
-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
********************************************************************/
@@ -665,40 +350,6 @@ void string_replace_w(smb_ucs2_t *s, smb_ucs2_t oldc, smb_ucs2_t 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
@@ -724,124 +375,15 @@ int strcmp_wa(const smb_ucs2_t *a, const char *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;
-}
-
-smb_ucs2_t *strpbrk_wa(const smb_ucs2_t *s, const char *p)
+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 (smb_ucs2_t *)s;
+ if (p[i]) return s;
s++;
}
return NULL;
}
-smb_ucs2_t *strstr_wa(const smb_ucs2_t *s, const char *ins)
-{
- smb_ucs2_t *r;
- size_t slen, inslen;
-
- if (!s || !*s || !ins || !*ins) return NULL;
- slen = strlen_w(s);
- inslen = strlen(ins);
- r = (smb_ucs2_t *)s;
- while ((r = strchr_w(r, UCS2_CHAR(*ins)))) {
- if (strncmp_wa(r, ins, inslen) == 0) return r;
- r++;
- }
- return NULL;
-}
-
-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->offset = 0;
- dst->uni_str_len = len;
-
- /* copy the actual unicode string */
- strncpy_w(dst->buffer, src, dst->uni_max_len);
-
- return dst;
-}
diff --git a/source/lib/util_uuid.c b/source/lib/util_uuid.c
index 4c35236c902..6a705a4f309 100644
--- a/source/lib/util_uuid.c
+++ b/source/lib/util_uuid.c
@@ -2,7 +2,8 @@
* Unix SMB/CIFS implementation.
* UUID server routines
* Copyright (C) Theodore Ts'o 1996, 1997,
- * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002, 2003
+ * Copyright (C) Jim McDonough 2002.
+ * 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
@@ -21,154 +22,41 @@
#include "includes.h"
-/*
- * Offset between 15-Oct-1582 and 1-Jan-70
- */
-#define TIME_OFFSET_HIGH 0x01B21DD2
-#define TIME_OFFSET_LOW 0x13814000
-
-void smb_uuid_pack(const struct uuid uu, UUID_FLAT *ptr)
-{
- SIVAL(ptr, 0, uu.time_low);
- SSVAL(ptr, 4, uu.time_mid);
- SSVAL(ptr, 6, uu.time_hi_and_version);
- memcpy(ptr+8, uu.clock_seq, 2);
- memcpy(ptr+10, uu.node, 6);
-}
-
-void smb_uuid_unpack(const UUID_FLAT in, struct uuid *uu)
+void uuid_generate_random(struct GUID *out)
{
- uu->time_low = IVAL(in.info, 0);
- uu->time_mid = SVAL(in.info, 4);
- uu->time_hi_and_version = SVAL(in.info, 6);
- memcpy(uu->clock_seq, in.info+8, 2);
- memcpy(uu->node, in.info+10, 6);
+ generate_random_buffer(out, sizeof(struct GUID), False);
+ out->clock_seq[0] = (out->clock_seq[0] & 0x3F) | 0x80;
+ out->time_hi_and_version = (out->time_hi_and_version & 0x0FFF) | 0x4000;
}
-const struct uuid smb_uuid_unpack_static(const UUID_FLAT in)
+BOOL uuid_all_zero(const struct GUID *u)
{
- static struct uuid uu;
-
- smb_uuid_unpack(in, &uu);
- return uu;
-}
-
-void smb_uuid_generate_random(struct uuid *uu)
-{
- UUID_FLAT tmp;
-
- generate_random_buffer(tmp.info, sizeof(tmp.info), True);
- smb_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;
+ if (u->time_low != 0 ||
+ u->time_mid != 0 ||
+ u->time_hi_and_version != 0 ||
+ u->clock_seq[0] != 0 ||
+ u->clock_seq[1] != 0 ||
+ !all_zero(u->node, 6)) {
+ return False;
+ }
+ return True;
}
-char *smb_uuid_to_string(const struct uuid uu)
+BOOL uuid_equal(const struct GUID *u1, const struct GUID *u2)
{
- char *out;
-
- 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;
+ if (u1->time_low != u2->time_low ||
+ u1->time_mid != u2->time_mid ||
+ u1->time_hi_and_version != u2->time_hi_and_version ||
+ u1->clock_seq[0] != u2->clock_seq[0] ||
+ u1->clock_seq[1] != u2->clock_seq[1] ||
+ memcmp(u1->node, u2->node, 6) != 0) {
+ return False;
+ }
+ return True;
}
-const char *smb_uuid_string_static(const struct uuid uu)
+BOOL policy_handle_empty(struct policy_handle *h)
{
- static char out[37];
-
- slprintf(out, sizeof(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;
+ return (h->handle_type == 0 && uuid_all_zero(&h->uuid));
}
-BOOL smb_string_to_uuid(const char *in, struct uuid* uu)
-{
- BOOL ret = False;
- const char *ptr = in;
- char *end = (char *)in;
- int i;
-
- if (!in || !uu) goto out;
-
- uu->time_low = strtoul(ptr, &end, 16);
- if ((end - ptr) != 8 || *end != '-') goto out;
- ptr = (end + 1);
-
- uu->time_mid = strtoul(ptr, &end, 16);
- if ((end - ptr) != 4 || *end != '-') goto out;
- ptr = (end + 1);
-
- uu->time_hi_and_version = strtoul(ptr, &end, 16);
- if ((end - ptr) != 4 || *end != '-') goto out;
- ptr = (end + 1);
-
- for (i = 0; i < 2; i++) {
- int adj = 0;
- if (*ptr >= '0' && *ptr <= '9') {
- adj = '0';
- } else if (*ptr >= 'a' && *ptr <= 'f') {
- adj = 'a';
- } else if (*ptr >= 'A' && *ptr <= 'F') {
- adj = 'A';
- } else {
- goto out;
- }
- uu->clock_seq[i] = (*ptr - adj) << 4;
- ptr++;
-
- if (*ptr >= '0' && *ptr <= '9') {
- adj = '0';
- } else if (*ptr >= 'a' && *ptr <= 'f') {
- adj = 'a';
- } else if (*ptr >= 'A' && *ptr <= 'F') {
- adj = 'A';
- } else {
- goto out;
- }
- uu->clock_seq[i] |= (*ptr - adj);
- ptr++;
- }
-
- if (*ptr != '-') goto out;
- ptr++;
-
- for (i = 0; i < 6; i++) {
- int adj = 0;
- if (*ptr >= '0' && *ptr <= '9') {
- adj = '0';
- } else if (*ptr >= 'a' && *ptr <= 'f') {
- adj = 'a';
- } else if (*ptr >= 'A' && *ptr <= 'F') {
- adj = 'A';
- } else {
- goto out;
- }
- uu->node[i] = (*ptr - adj) << 4;
- ptr++;
-
- if (*ptr >= '0' && *ptr <= '9') {
- adj = '0';
- } else if (*ptr >= 'a' && *ptr <= 'f') {
- adj = 'a';
- } else if (*ptr >= 'A' && *ptr <= 'F') {
- adj = 'A';
- } else {
- goto out;
- }
- uu->node[i] |= (*ptr - adj);
- ptr++;
- }
-
- ret = True;
-out:
- return ret;
-}
diff --git a/source/lib/wins_srv.c b/source/lib/wins_srv.c
index 4a54762fde7..30e81b08aba 100644
--- a/source/lib/wins_srv.c
+++ b/source/lib/wins_srv.c
@@ -70,24 +70,14 @@
static char *wins_srv_keystr(struct in_addr wins_ip, struct in_addr src_ip)
{
- char *keystr = NULL, *wins_ip_addr = NULL, *src_ip_addr = NULL;
-
- wins_ip_addr = strdup(inet_ntoa(wins_ip));
- src_ip_addr = strdup(inet_ntoa(src_ip));
-
- if ( !wins_ip_addr || !src_ip_addr ) {
- DEBUG(0,("wins_srv_keystr: malloc error\n"));
- goto done;
- }
+ char *keystr;
- if (asprintf(&keystr, WINS_SRV_FMT, wins_ip_addr, src_ip_addr) == -1) {
- DEBUG(0, (": ns_srv_keystr: malloc error for key string\n"));
+ 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;
}
-done:
- SAFE_FREE(wins_ip_addr);
- SAFE_FREE(src_ip_addr);
-
return keystr;
}
@@ -179,16 +169,16 @@ struct tagged_ip {
and the ip in in_addr format. If there is no tag then
use the tag '*'
*/
-static void parse_ip(struct tagged_ip *ip, const char *str)
+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(str);
+ ip->ip = *interpret_addr2(mem_ctx, str);
return;
}
- ip->ip = *interpret_addr2(s+1);
+ ip->ip = *interpret_addr2(mem_ctx, s+1);
fstrcpy(ip->tag, str);
s = strchr(ip->tag, ':');
if (s) *s = 0;
@@ -208,6 +198,7 @@ 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
@@ -223,11 +214,15 @@ char **wins_srv_tags(void)
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(&t_ip, list[i]);
+ parse_ip(mem_ctx, &t_ip, list[i]);
/* see if we already have it */
for (j=0;j<count;j++) {
@@ -277,6 +272,7 @@ 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()) {
@@ -291,35 +287,38 @@ struct in_addr wins_srv_ip_tag(const char *tag, struct in_addr src_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(&t_ip, list[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)) {
- fstring src_name;
- fstrcpy(src_name, inet_ntoa(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)));
- return t_ip.ip;
+ goto exit;
}
}
/* they're all dead - try the first one until they revive */
for (i=0; list[i]; i++) {
- parse_ip(&t_ip, list[i]);
+ parse_ip(mem_ctx, &t_ip, list[i]);
if (strcmp(tag, t_ip.tag) != 0) {
continue;
}
- return t_ip.ip;
+ goto exit;
}
/* this can't happen?? */
zero_ip(&t_ip.ip);
+exit:
+ talloc_destroy(mem_ctx);
return t_ip.ip;
}
@@ -332,6 +331,7 @@ 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()) {
@@ -344,13 +344,18 @@ unsigned wins_srv_count_tag(const char *tag)
}
/* 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(&t_ip, list[i]);
+ parse_ip(mem_ctx, &t_ip, list[i]);
if (strcmp(tag, t_ip.tag) == 0) {
count++;
}
}
+ talloc_destroy(mem_ctx);
return count;
}