diff options
author | CVS Import User <samba-bugs@samba.org> | 2004-04-04 11:51:10 +0000 |
---|---|---|
committer | CVS Import User <samba-bugs@samba.org> | 2004-04-04 11:51:10 +0000 |
commit | e3d2dbdff6711b0bc768fb6b08f41240f21d5fba (patch) | |
tree | 159ef54b59b18e9b950f5c6af105915214244912 /source/lib | |
parent | 139b1658ca30692835c1a7203c7cd003e587ac12 (diff) | |
download | samba-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')
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(¶ms); - return True; - } else { - str_list_free(¶ms); - 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 = <db_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"AS_DENY_DISK)||(qflags"AS_ENABLED)) { - if (ret == 0) { - char *quota_file = NULL; - - asprintf("a_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"AS_DENY_DISK)||(qflags"AS_ENABLED)) { - if (ret == 0) { - char *quota_file = NULL; - - asprintf("a_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; } |