diff options
Diffstat (limited to 'ldap/servers/slapd/util.c')
-rw-r--r-- | ldap/servers/slapd/util.c | 601 |
1 files changed, 601 insertions, 0 deletions
diff --git a/ldap/servers/slapd/util.c b/ldap/servers/slapd/util.c new file mode 100644 index 00000000..6b6a5b0c --- /dev/null +++ b/ldap/servers/slapd/util.c @@ -0,0 +1,601 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* util.c -- utility functions -- functions available form libslapd */ +#ifdef _WIN32 +#include <direct.h> /* for getcwd */ +#else +#include <sys/socket.h> +#include <sys/param.h> +#include <unistd.h> +#include <pwd.h> +#endif +#include <pk11func.h> +#include "slap.h" +#include "prtime.h" +#include "prinrval.h" + +#define UTIL_ESCAPE_NONE 0 +#define UTIL_ESCAPE_HEX 1 +#define UTIL_ESCAPE_BACKSLASH 2 + +static int special_np(unsigned char c) +{ + if(c < 32 || c > 126) { + return UTIL_ESCAPE_HEX; + } else if ((c== '"') || (c=='\\')) + { + return UTIL_ESCAPE_HEX; + } + return UTIL_ESCAPE_NONE; +} + +static int special_np_and_punct(unsigned char c) +{ + if (c < 32 || c > 126 || c == '*') return UTIL_ESCAPE_HEX; + if (c == '\\' || c == '"') return UTIL_ESCAPE_BACKSLASH; + return UTIL_ESCAPE_NONE; +} + +static int special_filter(unsigned char c) +{ + /* + * Escape all non-printing chars and double-quotes in addition + * to those required by RFC 2254 so that we can use the string + * in log files. + */ + return (c < 32 || + c > 126 || + c == '*' || + c == '(' || + c == ')' || + c == '\\' || + c == '"') ? UTIL_ESCAPE_HEX : UTIL_ESCAPE_NONE; +} + +static const char* +do_escape_string ( + const char* str, + int len, /* -1 means str is nul-terminated */ + char buf[BUFSIZ], + int (*special)(unsigned char) +) +{ + const char* s; + const char* last; + int esc; + + if (str == NULL) { + *buf = '\0'; + return buf; + } + + if (len == -1) len = strlen (str); + if (len == 0) return str; + + last = str + len - 1; + for (s = str; s <= last; ++s) { + if ( esc = (*special)((unsigned char)*s)) { + const char* first = str; + char* bufNext = buf; + int bufSpace = BUFSIZ - 4; + while (1) { + if (bufSpace < (s - first)) s = first + bufSpace - 1; + if (s > first) { + memcpy (bufNext, first, s - first); + bufNext += (s - first); + bufSpace -= (s - first); + } + if (s > last) { + break; + } + do { + *bufNext++ = '\\'; --bufSpace; + if (bufSpace < 2) { + memcpy (bufNext, "..", 2); + bufNext += 2; + goto bail; + } + if (esc == UTIL_ESCAPE_BACKSLASH) { + *bufNext++ = *s; --bufSpace; + } else { /* UTIL_ESCAPE_HEX */ + sprintf (bufNext, "%02x", (unsigned)*(unsigned char*)s); + bufNext += 2; bufSpace -= 2; + } + } while (++s <= last && + (esc = (*special)((unsigned char)*s))); + if (s > last) break; + first = s; + while ( (esc = (*special)((unsigned char)*s)) == UTIL_ESCAPE_NONE && s <= last) ++s; + } + bail: + *bufNext = '\0'; + return buf; + } + } + return str; +} + +/* + * Function: escape_string + * Arguments: str: string + * buf: a char array of BUFSIZ length, in which the escaped string will + * be returned. + * Returns: a pointer to buf, if str==NULL or it needed to be escaped, or + * str itself otherwise. + * + * This function should only be used for generating loggable strings. + */ +const char* +escape_string (const char* str, char buf[BUFSIZ]) +{ + return do_escape_string(str,-1,buf,special_np); +} + +const char* +escape_string_with_punctuation(const char* str, char buf[BUFSIZ]) +{ + return do_escape_string(str,-1,buf,special_np_and_punct); +} + +const char* +escape_filter_value(const char* str, int len, char buf[BUFSIZ]) +{ + return do_escape_string(str,len,buf,special_filter); +} + +/* functions to convert between an entry and a set of mods */ +int slapi_mods2entry (Slapi_Entry **e, const char *idn, LDAPMod **iattrs) +{ + int i, rc = LDAP_SUCCESS; + LDAPMod **attrs= NULL; + + PR_ASSERT (idn); + PR_ASSERT (iattrs); + PR_ASSERT (e); + + attrs = normalize_mods2bvals((const LDAPMod **)iattrs); + PR_ASSERT (attrs); + + /* Construct an entry */ + *e = slapi_entry_alloc(); + PR_ASSERT (*e); + slapi_entry_init(*e, slapi_ch_strdup(idn), NULL); + + for (i = 0; rc==LDAP_SUCCESS && attrs[ i ]!=NULL; i++) + { + char *normtype; + Slapi_Value **vals; + + normtype = slapi_attr_syntax_normalize(attrs[ i ]->mod_type); + valuearray_init_bervalarray(attrs[ i ]->mod_bvalues, &vals); + if (strcasecmp(normtype, SLAPI_USERPWD_ATTR) == 0) + { + pw_encodevals(vals); + } + + /* set entry uniqueid - also adds attribute to the list */ + if (strcasecmp(normtype, SLAPI_ATTR_UNIQUEID) == 0) + slapi_entry_set_uniqueid (*e, slapi_ch_strdup (slapi_value_get_string(vals[0]))); + else + rc = slapi_entry_add_values_sv(*e, normtype, vals); + + valuearray_free(&vals); + if (rc != LDAP_SUCCESS) + { + LDAPDebug(LDAP_DEBUG_ANY, "slapi_add_internal: add_values for type %s failed\n", normtype, 0, 0 ); + slapi_entry_free (*e); + *e = NULL; + } + slapi_ch_free((void **) &normtype); + } + freepmods(attrs); + + return rc; +} + +int slapi_entry2mods (const Slapi_Entry *e, char **dn, LDAPMod ***attrs) +{ + Slapi_Mods smods; + Slapi_Attr *attr; + Slapi_Value **va; + char *type; + int rc; + + PR_ASSERT (e && attrs); + + if (dn) + *dn = slapi_ch_strdup (slapi_entry_get_dn ((Slapi_Entry *)e)); + slapi_mods_init (&smods, 0); + + rc = slapi_entry_first_attr(e, &attr); + while (rc == 0) + { + if ( NULL != ( va = attr_get_present_values( attr ))) { + slapi_attr_get_type(attr, &type); + slapi_mods_add_mod_values(&smods, LDAP_MOD_ADD, type, va ); + } + rc = slapi_entry_next_attr(e, attr, &attr); + } + + *attrs = slapi_mods_get_ldapmods_passout (&smods); + slapi_mods_done (&smods); + + return 0; +} + +/****************************************************************************** +* +* normalize_mods2bvals +* +* +* +* +*******************************************************************************/ + +LDAPMod ** +normalize_mods2bvals(const LDAPMod **mods) +{ + int w, x, vlen, num_values, num_mods; + LDAPMod **normalized_mods; + + if (mods == NULL) + { + return NULL; + } + + /* first normalize the mods so they are bvalues */ + /* count the number of mods -- sucks but should be small */ + num_mods = 1; + for (w=0; mods[w] != NULL; w++) num_mods++; + + normalized_mods = (LDAPMod **) slapi_ch_calloc(num_mods, sizeof(LDAPMod *)); + + for (w = 0; mods[w] != NULL; w++) + { + /* copy each mod into a normalized modbvalue */ + normalized_mods[w] = (LDAPMod *) slapi_ch_calloc(1, sizeof(LDAPMod)); + normalized_mods[w]->mod_op = mods[w]->mod_op | LDAP_MOD_BVALUES; + + normalized_mods[w]->mod_type = slapi_ch_strdup(mods[w]->mod_type); + + /* + * count the number of values -- kinda sucks but probably + * less expensive then reallocing, and num_values + * should typically be very small + */ + num_values = 0; + if (mods[w]->mod_op & LDAP_MOD_BVALUES) + { + for (x = 0; mods[w]->mod_bvalues != NULL && + mods[w]->mod_bvalues[x] != NULL; x++) + { + num_values++; + } + } else { + for (x = 0; mods[w]->mod_values[x] != NULL && + mods[w]->mod_values[x] != NULL; x++) + { + num_values++; + } + } + + if (num_values > 0) + { + normalized_mods[w]->mod_bvalues = (struct berval **) + slapi_ch_calloc(num_values + 1, sizeof(struct berval *)); + } else { + normalized_mods[w]->mod_bvalues = NULL; + } + + if (mods[w]->mod_op & LDAP_MOD_BVALUES) + { + for (x = 0; mods[w]->mod_bvalues != NULL && + mods[w]->mod_bvalues[x] != NULL; x++) + { + normalized_mods[w]->mod_bvalues[x] = ber_bvdup(mods[w]->mod_bvalues[x]); + } + } else { + for (x = 0; mods[w]->mod_values != NULL && + mods[w]->mod_values[x] != NULL; x++) + { + normalized_mods[w]->mod_bvalues[ x ] = (struct berval *) + slapi_ch_calloc(1, sizeof(struct berval)); + + vlen = strlen(mods[w]->mod_values[x]); + normalized_mods[w]->mod_bvalues[ x ]->bv_val = + slapi_ch_calloc(vlen + 1, sizeof(char)); + memcpy(normalized_mods[w]->mod_bvalues[ x ]->bv_val, + mods[w]->mod_values[x], vlen); + normalized_mods[w]->mod_bvalues[ x ]->bv_val[vlen] = '\0'; + normalized_mods[w]->mod_bvalues[ x ]->bv_len = vlen; + } + } + + /* don't forget to null terminate it */ + if (num_values > 0) + { + normalized_mods[w]->mod_bvalues[ x ] = NULL; + } + } + + /* don't forget to null terminate the normalize list of mods */ + normalized_mods[w] = NULL; + + return(normalized_mods); +} + +/* + * Return true if the given path is an absolute path, false otherwise + */ +int +is_abspath(const char *path) +{ + if (path == NULL || *path == '\0') { + return 0; /* empty path is not absolute? */ + } + +#if defined( XP_WIN32 ) + if (path[0] == '/' || path[0] == '\\' || + (isalpha(path[0]) && (path[1] == ':'))) { + return 1; /* Windows abs path */ + } +#else + if (path[0] == '/') { + return 1; /* unix abs path */ + } +#endif + + return 0; /* not an abs path */ +} + + +/* + * Take "relpath" and prepend the current working directory to it + * if it isn't an absolute pathname already. The caller is responsible + * for freeing the returned string. + */ +char * +rel2abspath( char *relpath ) +{ + char abspath[ MAXPATHLEN + 1 ]; + +#if defined( _WIN32 ) + CHAR szDrive[_MAX_DRIVE]; + CHAR szDir[_MAX_DIR]; + CHAR szFname[_MAX_FNAME]; + CHAR szExt[_MAX_EXT]; +#define _PSEP "\\" +#else +#define _PSEP "/" +#endif + + if ( relpath == NULL ) { + return NULL; + } + +#if defined( _WIN32 ) + memset (&szDrive, 0, sizeof (szDrive)); + memset (&szDir, 0, sizeof (szDir)); + memset (&szFname, 0, sizeof (szFname)); + memset (&szExt, 0, sizeof (szExt)); + _splitpath( relpath, szDrive, szDir, szFname, szExt ); + if( szDrive[0] && szDir[0] ) + return( slapi_ch_strdup( relpath )); + if ( relpath[ 0 ] == '/' || relpath[ 0 ] == '\\' ) { + return( slapi_ch_strdup( relpath )); +#else + if ( relpath[ 0 ] == '/' ) { + return( slapi_ch_strdup( relpath )); + } +#endif + + if ( getcwd( abspath, MAXPATHLEN ) == NULL ) { + perror( "getcwd" ); + LDAPDebug( LDAP_DEBUG_ANY, "Cannot determine current directory\n", + 0, 0, 0 ); + exit( 1 ); + } + + if ( strlen( relpath ) + strlen( abspath ) + 1 > MAXPATHLEN ) { + LDAPDebug( LDAP_DEBUG_ANY, "Pathname \"%s" _PSEP "%s\" too long\n", + abspath, relpath, 0 ); + exit( 1 ); + } + + if ( strcmp( relpath, "." )) { +#if defined( _WIN32 ) + if ( abspath[ 0 ] != '\0' && abspath[ strlen( abspath ) - 1 ] != '/' && abspath[ strlen( abspath ) - 1 ] != '\\' ) +#else + if ( abspath[ 0 ] != '\0' && abspath[ strlen( abspath ) - 1 ] != '/' ) { +#endif + strcat( abspath, "/" ); + } + strcat( abspath, relpath ); + } + return( slapi_ch_strdup( abspath )); +} + + +/* + * Allocate a buffer large enough to hold a berval's + * value and a terminating null byte. The returned buffer + * is null-terminated. Returns NULL if bval is NULL or if + * bval->bv_val is NULL. + */ +char * +slapi_berval_get_string_copy(const struct berval *bval) +{ + char *return_value = NULL; + if (NULL != bval && NULL != bval->bv_val) + { + return_value = slapi_ch_malloc(bval->bv_len + 1); + memcpy(return_value, bval->bv_val, bval->bv_len); + return_value[bval->bv_len] = '\0'; + } + return return_value; +} + + + /* Takes a return code supposed to be errno or from a plugin + which we don't expect to see and prints a handy log message */ +void slapd_nasty(char* str, int c, int err) +{ + char *msg = NULL; + char buffer[100]; + sprintf(buffer,"%s BAD %d",str,c); + LDAPDebug(LDAP_DEBUG_ANY,"%s, err=%d %s\n",buffer,err,(msg = strerror( err )) ? msg : ""); +} + +/* *************************************************** + Random function (very similar to rand_r()) + *************************************************** */ +int +slapi_rand_r(unsigned int *randx) +{ + if (*randx) + { + PK11_RandomUpdate(randx, sizeof(*randx)); + } + PK11_GenerateRandom((unsigned char *)randx, (int)sizeof(*randx)); + return (int)(*randx & 0x7FFFFFFF); +} + +/* *************************************************** + Random function (very similar to rand_r() but takes and returns an array) + Note: there is an identical function in plugins/pwdstorage/ssha_pwd.c. + That module can't use a libslapd function because the module is included + in libds_admin, which doesn't link to libslapd. Eventually, shared + functions should be moved to a shared library. + *************************************************** */ +void +slapi_rand_array(void *randx, size_t len) +{ + PK11_RandomUpdate(randx, len); + PK11_GenerateRandom((unsigned char *)randx, (int)len); +} + +/* *************************************************** + Random function (very similar to rand()...) + *************************************************** */ +int +slapi_rand() +{ + unsigned int randx = 0; + return slapi_rand_r(&randx); +} + + + +/************************************************************************ +Function: DS_Sleep(PRIntervalTime ticks) + +Purpose: To replace PR_Sleep() + +Author: Scott Hopson <shopson@netscape.com> + +Description: + Causes the current thread to wait for ticks number of intervals. + + In UNIX this is accomplished by using select() + which should be supported across all UNIX platforms. + + In WIN32 we simply use the Sleep() function which yields + for the number of milliseconds specified. + +************************************************************************/ + + +#if defined(_WIN32) + +#include "windows.h" + + +void DS_Sleep(PRIntervalTime ticks) +{ +DWORD mSecs = PR_IntervalToMilliseconds(ticks); + + Sleep(mSecs); +} + +#else /*** UNIX ***/ + + +#include <sys/time.h> + + +void DS_Sleep(PRIntervalTime ticks) +{ +long mSecs = PR_IntervalToMilliseconds(ticks); +struct timeval tm; + + tm.tv_sec = mSecs / 1000; + tm.tv_usec = (mSecs % 1000) * 1000; + + select(0,NULL,NULL,NULL,&tm); +} + +#endif + + +/***************************************************************************** + * strarray2str(): convert the array of strings in "a" into a single + * space-separated string like: + * str1 str2 str3 + * If buf is too small, the result will be truncated and end with "...". + * If include_quotes is non-zero, double quote marks are included around + * the string, e.g., + * "str2 str2 str3" + * + * Returns: 0 if completely successful and -1 if result is truncated. + */ +int +strarray2str( char **a, char *buf, size_t buflen, int include_quotes ) +{ + int rc = 0; /* optimistic */ + char *p = buf; + size_t totlen = 0; + + + if ( include_quotes ) { + if ( buflen < 3 ) { + return -1; /* not enough room for the quote marks! */ + } + *p++ = '"'; + ++totlen; + } + + if ( NULL != a ) { + int ii; + size_t len = 0; + for ( ii = 0; a[ ii ] != NULL; ii++ ) { + if ( ii > 0 ) { + *p++ = ' '; + totlen++; + } + len = strlen( a[ ii ]); + if ( totlen + len > buflen - 5 ) { + strcpy ( p, "..." ); + p += 3; + totlen += 3; + rc = -1; + break; /* result truncated */ + } else { + strcpy( p, a[ ii ]); + p += len; + totlen += len; + } + } + } + + if ( include_quotes ) { + *p++ = '"'; + ++totlen; + } + buf[ totlen ] = '\0'; + + return( rc ); +} +/*****************************************************************************/ |