diff options
Diffstat (limited to 'ldap/admin/lib')
-rw-r--r-- | ldap/admin/lib/Makefile | 108 | ||||
-rw-r--r-- | ldap/admin/lib/dsalib_conf.c | 213 | ||||
-rw-r--r-- | ldap/admin/lib/dsalib_confs.c | 130 | ||||
-rw-r--r-- | ldap/admin/lib/dsalib_db.c | 374 | ||||
-rw-r--r-- | ldap/admin/lib/dsalib_debug.c | 73 | ||||
-rw-r--r-- | ldap/admin/lib/dsalib_dn.c | 465 | ||||
-rw-r--r-- | ldap/admin/lib/dsalib_filename.c | 95 | ||||
-rw-r--r-- | ldap/admin/lib/dsalib_html.c | 201 | ||||
-rw-r--r-- | ldap/admin/lib/dsalib_ldif.c | 374 | ||||
-rw-r--r-- | ldap/admin/lib/dsalib_location.c | 142 | ||||
-rw-r--r-- | ldap/admin/lib/dsalib_pw.c | 29 | ||||
-rw-r--r-- | ldap/admin/lib/dsalib_tailf.c | 206 | ||||
-rw-r--r-- | ldap/admin/lib/dsalib_updown.c | 702 | ||||
-rw-r--r-- | ldap/admin/lib/dsalib_util.c | 1123 |
14 files changed, 4235 insertions, 0 deletions
diff --git a/ldap/admin/lib/Makefile b/ldap/admin/lib/Makefile new file mode 100644 index 00000000..8aa9a705 --- /dev/null +++ b/ldap/admin/lib/Makefile @@ -0,0 +1,108 @@ +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +# +# GNU Makefile for Directory Server Admin DLL/SO. +# + +LDAP_SRC = ../.. +MCOM_ROOT = ../../../.. + +NOSTDCLEAN=true # don't let nsconfig.mk define target clean +NOSTDSTRIP=true # don't let nsconfig.mk define target strip +NSPR20=true # probably should be defined somewhere else (not sure where) + +OBJDEST = $(LDAP_ADMOBJDIR) +LIBDIR = $(LDAP_LIBDIR) +ALIBDIR = $(LDAP_ADMLIBDIR) +BINDIR=$(LDAP_ADMIN_BIN_RELDIR) + +include $(MCOM_ROOT)/ldapserver/nsdefs.mk +include $(MCOM_ROOT)/ldapserver/nsconfig.mk +include $(LDAP_SRC)/nsldap.mk + +SRCS = dsalib_location.c dsalib_debug.c dsalib_updown.c dsalib_tailf.c \ + dsalib_ldif.c dsalib_db.c dsalib_conf.c dsalib_html.c \ + dsalib_filename.c dsalib_util.c dsalib_dn.c dsalib_confs.c dsalib_pw.c + +PWDOBJ=$(OBJDIR)/lib/libpwdstorage/ssha_pwd.o + +OBJS1 = $(addprefix $(OBJDEST)/, $(subst .c,.o,$(SRCS))) +OBJS = $(OBJS1) $(PWDOBJ) + +INCLUDES += -I$(LDAP_SRC)/admin/include +ifdef FORTEZZA +INCLUDES += -I$(MCOM_ROOT)/lib +endif + +EXTRA_LIBS += $(LDAP_COMMON_LIBS) $(SECURITYLINK) $(NSPRLINK) + +LIBS= $(LDAP_ADMDLLDIR)/libds_admin$(DLL_PRESUF).$(DLL_SUFFIX) +ifeq ($(ARCH), WINNT) +IMPLIB= /IMPLIB:$(LDAP_ADMLIBDIR)/libds_admin.lib +MAPFILE= /MAP:$(LDAP_ADMLIBDIR)/libds_admin.map +EXTRA_LIBS_DEP += $(LDAP_COMMON_LIBS_DEP) $(LDAP_LIBLDIF_DEP) +#EXTRA_LIBS += $(LDAP_COMMON_LIBS) $(LDAP_LIBLDIF) $(LDAP_SDK_LIBLDAP_DLL) \ +# $(ADMINUTIL_LINK) $(SECURITYLINK) $(NSPRLINK) +else # WINNT +ifdef FORTEZZA +# libci.a needs to be recompiled with the -Z option on HPUX, until then, +# we'll link libci.a with the executables which need it -atom +ifneq ($(ARCH), HPUX) +EXTRA_LIBS_DEP += $(FORTEZZA_DRIVER) +EXTRA_LIBS += $(FORTEZZA_DRIVER) +endif # !HPUX +endif # FORTEZZA +endif # WINNT + +ifeq ($(ARCH), Linux) +# XXXsspitzer: we do this so that cgi's the link against libds_admin.so +# will be able to find libns-dshttpd.so at run time. Only platforms that +# build with gcc need to do this. +RPATHFLAG_EXTRAS+=:../..:.. +endif # Linux + +ifeq ($(ARCH), AIX) +EXTRA_LIBS_DEP += $(LDAPSDK_DEP) +#EXTRA_LIBS += $(LDAP_SDK_LIBLDAP_DLL) $(SECURITYLINK) $(ADMINUTIL_LINK) $(NSPRLINK) $(DBMLINK) +LD=ld -noquiet +endif + +# for Solaris, our most common unix build platform, we check for undefined symbols +# at link time so we don't catch them at run time. To do this, we set the -z defs +# flag. We also have to add -lc to the end because, even though ld and cc link with +# it implicitly, -z defs will throw errors if we do not link with it explicitly +ifeq ($(ARCH), SOLARIS) +LINK_DLL += -z defs +EXTRA_LIBS += -lc +endif + +all: $(LIBS) $(LDAP_ADMDLL_RELDLLS) + +$(LIBS): $(OBJDEST) $(LDAP_ADMDLLDIR) $(LDAP_ADMLIBDIR) $(OBJS) $(EXTRA_LIBS_DEP) + $(LINK_DLL) $(IMPLIB) $(MAPFILE) $(EXTRA_LIBS) + +ifeq ($(ARCH), WINNT) +$(LDAP_ADMDLL_RELDLLS): $(LIBS) $(LDAP_ADMDLL_RELDIRS) + cp $< $@ + +endif + +veryclean: clean + +clean: + -$(RM) $(OBJS1) + -$(RM) $(LIBS) +ifeq ($(ARCH), WINNT) + -$(RM) $(IMPLIB) +endif + +$(OBJS1): $(OBJDEST)/%.o: %.c + $(CC) -c $(NONSHARED) $(CFLAGS) $(MCC_INCLUDE) $(OFFLAG)$(OBJDEST)/$*.o $*.c +ifdef USE_LINT + $(LINT) $(LINTCCFLAGS) $(DEFS) $(MCC_SERVER) $(INCLUDES) $(MCC_INCLUDE) $*.c > $(OBJDEST)/$*.ln 2>&1 +endif diff --git a/ldap/admin/lib/dsalib_conf.c b/ldap/admin/lib/dsalib_conf.c new file mode 100644 index 00000000..cc331619 --- /dev/null +++ b/ldap/admin/lib/dsalib_conf.c @@ -0,0 +1,213 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#if defined( XP_WIN32 ) +#include <windows.h> +#include <process.h> +#endif +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "dsalib.h" +#include <ldaplog.h> +#include "portable.h" +#include <ctype.h> + +#define CONF_FILE_NAME "config/dse.ldif" +#define CONF_SUFFIX "cn=config" + +DS_EXPORT_SYMBOL char * +ds_get_var_name(int varnum) +{ + if ( (varnum >= DS_CFG_MAX) || (varnum < 0) ) + return(NULL); /* failure */ + return(ds_cfg_info[varnum].dci_varname); +} + +/* + * Get config info. + */ +DS_EXPORT_SYMBOL char ** +ds_get_config(int type) +{ + char conffile[PATH_MAX]; + char *root; + FILE *sf = NULL; + char **conf_list = NULL; + + if ( (type != DS_REAL_CONFIG) && (type != DS_TMP_CONFIG) ) { + ds_send_error("Invalid config file type.", 0); + return(NULL); + } + + if ( (root = ds_get_install_root()) == NULL ) { + ds_send_error("Cannot find server root directory.", 0); + return(NULL); + } + + sprintf(conffile, "%s/%s", root, CONF_FILE_NAME); + + if ( !(sf = fopen(conffile, "r")) ) { + ds_send_error("could not read config file.", 1); + return(NULL); + } + + conf_list = ds_get_conf_from_file(sf); + + fclose(sf); + if (!conf_list) { + ds_send_error("failed to read the config file successfully.", 0); + return(NULL); + } + return(conf_list); +} + +/* + * NOTE: the ordering of the following array elements must be kept in sync + * with the ordering of the #defines in ../include/dsalib.h. + */ +struct ds_cfg_info ds_cfg_info[] = { +{"nsslapd-errorlog-level" }, +{"nsslapd-referral" }, +{"nsslapd-auditlog" }, +{"nsslapd-localhost" }, +{"nsslapd-port" }, +{"nsslapd-security" }, +{"nsslapd-secureport" }, +{"nsslapd-ssl3ciphers"}, +{"passwordstoragescheme"}, +{"nsslapd-accesslog"}, +{"nsslapd-errorlog"}, +{"nsslapd-rootdn"}, +{"nsslapd-rootpwstoragescheme"}, +{"nsslapd-suffix"}, +{"nsslapd-localuser"}, +{0} +}; + +/* + * Open the config file and look for option "option". Return its + * value, or NULL if the option was not found. + */ +DS_EXPORT_SYMBOL char * +ds_get_config_value( int option ) +{ + char **all, *value; + int i; + char *attr = ds_get_var_name(option); + + if (attr == NULL) + return NULL; + + all = ds_get_config( DS_REAL_CONFIG ); + if ( all == NULL ) { + return NULL; + } + for ( i = 0; all[ i ] != NULL; i++ ) { + if (( value = strchr( all[ i ], ':' )) != NULL ) { + *value = '\0'; + ++value; + while (*value && isspace(*value)) + ++value; + } + if ( !strcasecmp( attr, all[ i ] )) { + return strdup( value ); + } + } + return NULL; +} + +static size_t +count_quotes (const char* s) +{ + size_t count = 0; + const char* t = s; + if (t) while ((t = strpbrk (t, "\"\\")) != NULL) { + ++count; + ++t; + } + return count; +} + +DS_EXPORT_SYMBOL char* +ds_enquote_config_value (int paramnum, char* s) +{ + char* result; + char* brkcharset = "\"\\ \t\r\n"; + char *encoded_quote = "22"; /* replace quote with \22 */ + int encoded_quote_len = strlen(encoded_quote); + char *begin = s; + if (*s && ! strpbrk (s, brkcharset) && + ! (paramnum == DS_AUDITFILE || paramnum == DS_ACCESSLOG || +#if defined( XP_WIN32 ) + paramnum == DS_SUFFIX || +#endif + paramnum == DS_ERRORLOG)) { + result = s; + } else { + char* t = malloc (strlen (s) + count_quotes (s) + 3); + result = t; + *t++ = '"'; + while (*s) { + switch (*s) { + + case '"': + /* convert escaped quotes by replacing the quote with + escape code e.g. 22 so that \" is converted to \22 "*/ + if ((s > begin) && (*(s - 1) == '\\')) + { + strcpy(t, encoded_quote); + t += encoded_quote_len; + } + else /* unescaped ", just replace with \22 "*/ + { + *t++ = '\\'; + strcpy(t, encoded_quote); + t += encoded_quote_len; + } + ++s; + break; + + default: + *t++ = *s++; /* just copy it */ + break; + } + } + *t++ = '"'; + *t = '\0'; + } + return result; +} + +DS_EXPORT_SYMBOL char* +ds_DNS_to_DN (char* DNS) +{ + static const char* const RDN = "dc="; + char* DN; + char* dot; + size_t components; + if (DNS == NULL || *DNS == '\0') { + return strdup (""); + } + components = 1; + for (dot = strchr (DNS, '.'); dot != NULL; dot = strchr (dot + 1, '.')) { + ++components; + } + DN = malloc (strlen (DNS) + (components * strlen(RDN)) + 1); + strcpy (DN, RDN); + for (dot = strchr (DNS, '.'); dot != NULL; dot = strchr (dot + 1, '.')) { + *dot = '\0'; + strcat (DN, DNS); + strcat (DN, ","); + strcat (DN, RDN); + DNS = dot + 1; + *dot = '.'; + } + strcat (DN, DNS); + dn_normalize (DN); + return DN; +} diff --git a/ldap/admin/lib/dsalib_confs.c b/ldap/admin/lib/dsalib_confs.c new file mode 100644 index 00000000..ccaf8bd9 --- /dev/null +++ b/ldap/admin/lib/dsalib_confs.c @@ -0,0 +1,130 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * Some of the simple conf stuff here. Must not call any + * libadmin functions! This is needed by ds_config.c + */ +#if defined( XP_WIN32 ) +#include <windows.h> +#endif +#include "dsalib.h" +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ldif.h> +#include <ctype.h> +#include "plstr.h" + +/* + * Read the configuration info into a null-terminated list of strings. + */ +DS_EXPORT_SYMBOL char ** +ds_get_conf_from_file(FILE *conf) +{ + static char config_entry[] = "dn: cn=config"; + static int cfg_ent_len = sizeof(config_entry)-1; + int listsize = 0; + char **conf_list = NULL; + char *entry = 0; + int lineno = 0; + + while (entry = ldif_get_entry(conf, &lineno)) { + char *begin = entry; + if (!PL_strncasecmp(entry, config_entry, cfg_ent_len)) { + char *line = entry; + while (line = ldif_getline(&entry)) { + listsize++; + conf_list = (char **) realloc(conf_list, + ((listsize + 1) * sizeof(char *))); + conf_list[listsize - 1] = strdup(line); + conf_list[listsize] = NULL; /* always null terminated */ + } + } + free(begin); + } + + return(conf_list); +} + +/* + * Returns 1 if parm is in confline else 0 + */ +static int +ds_parm_in_line(char *confline, char *parm) +{ + int parm_size; + + if ( confline == NULL ) + return(0); + if ( parm == NULL ) + return(0); + parm_size = strlen(parm); + if ( parm_size == (int)NULL ) + return(0); + if ( PL_strncasecmp(confline, parm, parm_size) == 0 ) + if ( ((int) strlen(confline)) > parm_size ) + if ( confline[parm_size] == ':' ) + return(1); + return(0); +} + +/* + * Gets the string that corresponds to the parameter supplied from the + * list of config lines. Returns a malloc'd string. + */ +DS_EXPORT_SYMBOL char * +ds_get_value(char **ds_config, char *parm, int phase, int occurance) +{ + char *line; + int line_num = 0; + int cur_phase = 0; + int cur_occurance = 0; + + if ( (parm == NULL) || (ds_config == NULL) ) + return(NULL); + if ( (phase < 0) || (occurance < 1) ) + return(NULL); + line = ds_config[line_num]; + while ( line != NULL ) { + if ( ds_parm_in_line(line, "database") ) + cur_phase++; + if ( ds_parm_in_line(line, parm) ) { /* found it */ + if ( phase == cur_phase ) + if ( ++cur_occurance == occurance ) { + /* + * Use ldif_parse_line() so continuation markers are + * handled correctly, etc. + */ + char *errmsg, *type = NULL, *value = NULL, *tmpvalue = NULL; + int ldif_rc, tmpvlen = 0; + char *tmpline = strdup(line); + + if ( NULL == tmpline ) { + ds_send_error( + "ds_get_value() failed: strdup() returned NULL\n", + 1 /* print errno */ ); + return(NULL); + } + + ldif_rc = ldif_parse_line( tmpline, &type, &tmpvalue, + &tmpvlen, &errmsg ); + if (ldif_rc < 0) { + ds_send_error(errmsg, 0 /* do not print errno */); + } else if (ldif_rc == 0) { /* value returned in place */ + value = strdup(tmpvalue); + } else { /* malloc'd value */ + value = tmpvalue; + } + free(tmpline); + return value; + } + } + line_num++; + line = ds_config[line_num]; + } + return(NULL); +} diff --git a/ldap/admin/lib/dsalib_db.c b/ldap/admin/lib/dsalib_db.c new file mode 100644 index 00000000..02d9498f --- /dev/null +++ b/ldap/admin/lib/dsalib_db.c @@ -0,0 +1,374 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#if defined( XP_WIN32 ) +#include <windows.h> +#include <process.h> +#include <io.h> +#endif +#include "dsalib.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#if !defined( XP_WIN32 ) +#include <dirent.h> +#include <unistd.h> +#else +#define popen _popen +#define pclose _pclose +#endif +#include "portable.h" + +/* + * Get a listing of backup directories + * Return NULL for errors and a NULL list for an empty list. + */ + +DS_EXPORT_SYMBOL char ** +ds_get_bak_dirs() +{ + char format_str[PATH_MAX]; + char *root; + int i = 0; + char **bak_dirs = NULL; + + if ( (root = ds_get_install_root()) == NULL ) + { + ds_send_error("Cannot find server root directory.", 0); + return(bak_dirs); + } + + sprintf( format_str, "%s%cbak", root, FILE_SEP ); + bak_dirs = ds_get_file_list( format_str ); + if( bak_dirs ) + { + while( bak_dirs[i] != NULL ) + { + /* Prepend the filename with the install root */ + char filename[PATH_MAX]; + sprintf( filename, "%s%cbak%c%s", root, FILE_SEP, + FILE_SEP, bak_dirs[i] ); + free( bak_dirs[i] ); + bak_dirs[i] = strdup( filename ); +#if defined( XP_WIN32 ) + ds_dostounixpath( bak_dirs[i] ); +#endif + i++; + } + } + + return(bak_dirs); +} + +/* + * Restore a database based on a backup directory name. + * 0: success + * anything else: failure + */ +DS_EXPORT_SYMBOL int +ds_bak2db(char *file) +{ + char startup_line[BIG_LINE]; + char statfile[PATH_MAX]; + char *tmp_dir; + char *root; + int haderror = 0; + int error = -1; + int status; + FILE *sf = NULL; + struct stat fstats; + + if ( file == NULL ) { + return DS_NULL_PARAMETER; + } + status = ds_get_updown_status(); + if ( status == DS_SERVER_UP ) { + return DS_SERVER_MUST_BE_DOWN; + } + if ( (root = ds_get_install_root()) == NULL ) { + return DS_NO_SERVER_ROOT; + } + + if ( file[strlen(file) - 1] == '\n' ) /* strip out returns */ + file[strlen(file) - 1] = '\0'; + + if( stat( file, &fstats ) == -1 && errno == ENOENT ) { + return DS_CANNOT_OPEN_BACKUP_FILE; + } else if( !(fstats.st_mode & S_IFDIR) ) { + return DS_NOT_A_DIRECTORY; + } + + tmp_dir = ds_get_tmp_dir(); + sprintf(statfile, "%s%cbak2db.%d", tmp_dir, FILE_SEP, (int)getpid()); + sprintf(startup_line, + "%s%cbak2db " + "%s%s%s > " + "%s%s%s 2>&1", + root, FILE_SEP, + ENQUOTE, file, ENQUOTE, + ENQUOTE, statfile, ENQUOTE ); + alter_startup_line(startup_line); + fflush(0); + error = system(startup_line); + fflush(0); + if ( error == -1 ) { + return DS_CANNOT_EXEC; + } + fflush(0); + if( !(sf = fopen(statfile, "r")) ) { + return DS_CANNOT_OPEN_STAT_FILE; + } + + while ( fgets(startup_line, BIG_LINE, sf) ) { + if ((strstr(startup_line, "- Restoring file")) || + (strstr(startup_line, "- Checkpointing"))) { + ds_show_message(startup_line); + } else { + haderror = 1; + ds_send_error(startup_line, 0); + } + } + + fclose(sf); + unlink(statfile); + + if ( haderror ) + return DS_UNKNOWN_ERROR; + return 0; +} + +/* + * Create a backup based on a file name. + * 0: success + * anything else: failure + */ +DS_EXPORT_SYMBOL int +ds_db2bak(char *file) +{ + char startup_line[BIG_LINE]; + char statfile[PATH_MAX]; + char *tmp_dir; + char *root; + int haderror = 0; + int error = -1; + FILE *sf = NULL; + int lite = 0; +#ifdef XP_WIN32 + time_t ltime; +#endif + + if ( (root = ds_get_install_root()) == NULL ) { + return DS_NO_SERVER_ROOT; + } + + if ( (file == NULL) || (strlen(file) == 0) ) + file = NULL; + + tmp_dir = ds_get_tmp_dir(); + sprintf(statfile, "%s%cdb2bak.%d", tmp_dir, FILE_SEP, (int)getpid()); + + +#if defined( XP_WIN32 ) + if( file == NULL ) + { + file = malloc( BIG_LINE ); + + time( <ime ); + sprintf( file, "%s", ctime( <ime ) ); + ds_timetofname( file ); + } + + /* Check if the directory exists or can be created */ + if ( !ds_file_exists( file ) ) { + char *errmsg = ds_mkdir_p( file, NEWDIR_MODE ); + if( errmsg != NULL ) { +/* ds_send_error(errmsg, 10); + */ + return DS_CANNOT_CREATE_DIRECTORY; + } + } +#endif + +/* DBDB: note on the following line. + * Originally this had quotes round the directory name. + * I found that this made the script not work becuase + * a path of the form "foo"/bar/"baz" was passed to slapd. + * the c runtime didn't like this. Perhaps there's a simple + * solution, but for now I've modified this line here to + * not quote the directory name. This means that backup + * directories can't have spaces in them. + */ + + + sprintf(startup_line, + "%s%cdb2bak " + "%s%s%s > " + "%s%s%s 2>&1", + root, FILE_SEP, + ENQUOTE, + (file == NULL) ? "" : file, + ENQUOTE, + ENQUOTE, statfile, ENQUOTE); + + PATH_FOR_PLATFORM( startup_line ); + alter_startup_line(startup_line); + fflush(0); + error = system(startup_line); + if ( error == -1 ) { + return DS_CANNOT_EXEC; + } + if( !(sf = fopen(statfile, "r")) ) { + return DS_CANNOT_OPEN_STAT_FILE; + } + + while ( fgets(startup_line, BIG_LINE, sf) ) { + if (strstr(startup_line, " - Backing up file") || + strstr(startup_line, " - Checkpointing database")) { + ds_show_message(startup_line); + } else { + haderror = 1; + if (strstr ( startup_line, "restricted mode")) { + lite = 1; + } + ds_send_error(startup_line, 0); + } + } + fclose(sf); + unlink(statfile); + + if ( lite && haderror ) + return DS_HAS_TOBE_READONLY_MODE; + + if ( haderror ) + return DS_UNKNOWN_ERROR; + return 0; +} + +static void +process_and_report( char *line, int line_size, FILE *cmd ) +{ + while(fgets(line, line_size, cmd)) { + /* Strip off line feeds */ + int ind = strlen( line ) - 1; + while ( (ind >= 0) && + ((line[ind] == '\n') || + (line[ind] == '\r')) ) { + line[ind] = 0; + ind--; + } + if ( ind < 1 ) { + continue; + } + ds_send_status(line); + } +} + +static int exec_and_report( char *startup_line ) +{ + FILE *cmd = NULL; + char line[BIG_LINE]; + int haderror = 0; + + PATH_FOR_PLATFORM( startup_line ); + alter_startup_line(startup_line); + + /* + fprintf( stdout, "Launching <%s>\n", startup_line ); + */ + + fflush(0); + cmd = popen(startup_line, "r"); + if(!cmd) { + return DS_CANNOT_EXEC; + } + process_and_report( line, sizeof(line), cmd ); + pclose(cmd); + + /* + ** The VLV indexing code prints OK, + ** if the index was successfully created. + */ + if (strcmp(line,"OK")==0) { + haderror = 0; + } else { + haderror = DS_UNKNOWN_ERROR; + } + + return haderror; +} + +/* + * Create a vlv index + * 0: success + * anything else: failure + */ +DS_EXPORT_SYMBOL int +ds_vlvindex(char **backendList, char **vlvList) +{ + char startup_line[BIG_LINE]; + char *root; + char *instroot; + char **vlvc = NULL; + + + root = ds_get_server_root(); + instroot = ds_get_install_root(); + if ( (root == NULL) || (instroot == NULL) ) { + return DS_NO_SERVER_ROOT; + } + + sprintf(startup_line, "%s/bin/slapd/server/%s db2index " + "-D %s%s/%s " + "-n %s ", + root, SLAPD_NAME, + ENQUOTE, instroot, ENQUOTE, + backendList[0]); + + + /* Create vlv TAG */ + vlvc=vlvList; + while( *vlvc != NULL ) { + sprintf( startup_line, "%s -T %s%s%s", startup_line,"\"",*vlvc,"\"" ); + vlvc++; + } + + return exec_and_report( startup_line ); +} + +/* + * Create one or more indexes + * 0: success + * anything else: failure + */ +DS_EXPORT_SYMBOL int +ds_addindex(char **attrList, char *backendName) +{ + char startup_line[BIG_LINE]; + char *root; + char *instroot; + + root = ds_get_server_root(); + instroot = ds_get_install_root(); + + if ( (root == NULL) || (instroot == NULL) ) { + return DS_NO_SERVER_ROOT; + } + + sprintf(startup_line, "%s/bin/slapd/server/%s db2index " + "-D %s%s%s " + "-n %s", + root, SLAPD_NAME, + ENQUOTE, instroot, ENQUOTE, + backendName); + + while( *attrList != NULL ) { + sprintf( startup_line, "%s -t %s", startup_line, *attrList ); + attrList++; + } + + return exec_and_report( startup_line ); +} diff --git a/ldap/admin/lib/dsalib_debug.c b/ldap/admin/lib/dsalib_debug.c new file mode 100644 index 00000000..4819a94d --- /dev/null +++ b/ldap/admin/lib/dsalib_debug.c @@ -0,0 +1,73 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#if defined( XP_WIN32 ) +#include <windows.h> +#endif +#include "dsalib.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#if defined( XP_WIN32 ) +int ldap_debug = 0; +#endif + +DS_EXPORT_SYMBOL void +ds_log_env(char **envp) +{ + FILE *file; + char admin_logfile[PATH_MAX], *tmp_dir; + + tmp_dir = ds_get_tmp_dir(); + memset( admin_logfile, 0, sizeof( admin_logfile ) ); + strcat( admin_logfile, tmp_dir ); +#if defined( XP_WIN32 ) + if( tmp_dir ) + { + free( tmp_dir ); + tmp_dir = NULL; + } +#endif + strcat( admin_logfile, "/admin.log"); + + file = fopen(admin_logfile, "a+"); + if (file != NULL) { + int i; + for ( i = 0; envp[i] != (char *) 0; i++ ) { + char envstr[200]; + + sprintf(envstr, "%s\n", envp[i]); + fwrite(envstr, strlen(envstr), 1, file); + } + fclose(file); + } +} + +DS_EXPORT_SYMBOL void +ds_log_debug_message(char *msg) +{ + FILE *file; + char admin_logfile[PATH_MAX], *tmp_dir; + + tmp_dir = ds_get_tmp_dir(); + memset( admin_logfile, 0, sizeof( admin_logfile ) ); + strcat( admin_logfile, tmp_dir ); +#if defined( XP_WIN32 ) + if( tmp_dir ) + { + free( tmp_dir ); + tmp_dir = NULL; + } +#endif + strcat( admin_logfile, "/admin.log"); + + file = fopen(admin_logfile, "a+"); + if (file != NULL) { + fwrite(msg, strlen(msg), 1, file); + fclose(file); + } +} + diff --git a/ldap/admin/lib/dsalib_dn.c b/ldap/admin/lib/dsalib_dn.c new file mode 100644 index 00000000..d7de36d9 --- /dev/null +++ b/ldap/admin/lib/dsalib_dn.c @@ -0,0 +1,465 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +#if defined( XP_WIN32 ) +#include <windows.h> +#else +#include <sys/types.h> +#endif +#include <string.h> +#include "dsalib.h" +#include "portable.h" +#include <stdlib.h> + +#define DNSEPARATOR(c) (c == ',' || c == ';') +#define SEPARATOR(c) (c == ',' || c == ';' || c == '+') +#define SPACE(c) (c == ' ' || c == '\n') +#define NEEDSESCAPE(c) (c == '\\' || c == '"') +#define B4TYPE 0 +#define INTYPE 1 +#define B4EQUAL 2 +#define B4VALUE 3 +#define INVALUE 4 +#define INQUOTEDVALUE 5 +#define B4SEPARATOR 6 + +DS_EXPORT_SYMBOL char* +dn_normalize( char *dn ) +{ + char *d, *s; + int state, gotesc; + + /* Debug( LDAP_DEBUG_TRACE, "=> dn_normalize \"%s\"\n", dn, 0, 0 ); */ + + gotesc = 0; + state = B4TYPE; + for ( d = s = dn; *s; s++ ) { + switch ( state ) { + case B4TYPE: + if ( ! SPACE( *s ) ) { + state = INTYPE; + *d++ = *s; + } + break; + case INTYPE: + if ( *s == '=' ) { + state = B4VALUE; + *d++ = *s; + } else if ( SPACE( *s ) ) { + state = B4EQUAL; + } else { + *d++ = *s; + } + break; + case B4EQUAL: + if ( *s == '=' ) { + state = B4VALUE; + *d++ = *s; + } else if ( ! SPACE( *s ) ) { + /* not a valid dn - but what can we do here? */ + *d++ = *s; + } + break; + case B4VALUE: + if ( *s == '"' ) { + state = INQUOTEDVALUE; + *d++ = *s; + } else if ( ! SPACE( *s ) ) { + state = INVALUE; + *d++ = *s; + } + break; + case INVALUE: + if ( !gotesc && SEPARATOR( *s ) ) { + while ( SPACE( *(d - 1) ) ) + d--; + state = B4TYPE; + if ( *s == '+' ) { + *d++ = *s; + } else { + *d++ = ','; + } + } else if ( gotesc && !NEEDSESCAPE( *s ) && + !SEPARATOR( *s ) ) { + *--d = *s; + d++; + } else { + *d++ = *s; + } + break; + case INQUOTEDVALUE: + if ( !gotesc && *s == '"' ) { + state = B4SEPARATOR; + *d++ = *s; + } else if ( gotesc && !NEEDSESCAPE( *s ) ) { + *--d = *s; + d++; + } else { + *d++ = *s; + } + break; + case B4SEPARATOR: + if ( SEPARATOR( *s ) ) { + state = B4TYPE; + if ( *s == '+' ) { + *d++ = *s; + } else { + *d++ = ','; + } + } + break; + default: + break; + } + if ( *s == '\\' ) { + gotesc = 1; + } else { + gotesc = 0; + } + } + *d = '\0'; + + /* Debug( LDAP_DEBUG_TRACE, "<= dn_normalize \"%s\"\n", dn, 0, 0 ); */ + return( dn ); +} + +DS_EXPORT_SYMBOL int +dn_issuffix( + char *dn, + char *suffix +) +{ + int dnlen, suffixlen; + + if ( dn == NULL ) { + return( 0 ); + } + + suffixlen = strlen( suffix ); + dnlen = strlen( dn ); + + if ( suffixlen > dnlen ) { + return( 0 ); + } + + return( strcasecmp( dn + dnlen - suffixlen, suffix ) == 0 ); +} + +DS_EXPORT_SYMBOL char* +ds_dn_expand (char* dn) +{ + char* edn; + size_t i = 0; + char* s; + int state = B4TYPE; + int gotesc = 0; + + if (dn == NULL) return NULL; + edn = strdup (dn); + for (s = dn; *s != '\0'; ++s, ++i) { + switch (state) { + case B4TYPE: + if ( ! SPACE (*s)) { + state = INTYPE; + } + break; + case INTYPE: + if (*s == '=') { + state = B4VALUE; + } else if (SPACE (*s)) { + state = B4EQUAL; + } + break; + case B4EQUAL: + if (*s == '=') { + state = B4VALUE; + } + break; + case B4VALUE: + if (*s == '"') { + state = INQUOTEDVALUE; + } else if ( ! SPACE (*s)) { + state = INVALUE; + } + break; + case INQUOTEDVALUE: + if (gotesc) { + if ( ! NEEDSESCAPE (*s)) { + --i; + memmove (edn+i, edn+i+1, strlen (edn+i)); + } + } else { + if (*s == '"') { + state = B4SEPARATOR; + } + } + break; + case INVALUE: + if (gotesc) { + if ( ! NEEDSESCAPE (*s) && ! SEPARATOR (*s)) { + --i; + memmove (edn+i, edn+i+1, strlen (edn+i)); + } + break; + } + case B4SEPARATOR: + if (SEPARATOR (*s)) { + state = B4TYPE; + if ( ! SPACE (s[1])) { + /* insert a space following edn[i] */ + edn = (char*) realloc (edn, strlen (edn)+2); + ++i; + memmove (edn+i+1, edn+i, strlen (edn+i)+1); + edn[i] = ' '; + } + } + break; + default: + break; + } + gotesc = (*s == '\\'); + } + return edn; +} + +int +hexchar2int( char c ) +{ + if ( '0' <= c && c <= '9' ) { + return( c - '0' ); + } + if ( 'a' <= c && c <= 'f' ) { + return( c - 'a' + 10 ); + } + if ( 'A' <= c && c <= 'F' ) { + return( c - 'A' + 10 ); + } + return( -1 ); +} + +/* + * substr_dn_normalize - map a DN to a canonical form. + * The DN is read from *dn through *(end-1) and normalized in place. + * The new end is returned; that is, the canonical form is in + * *dn through *(the_return_value-1). + */ + +/* The goals of this function are: + * 1. be compatible with previous implementations. Especially, enable + * a server running this code to find database index keys that were + * computed by Directory Server 3.0 with a prior version of this code. + * 2. Normalize in place; that is, avoid allocating memory to contain + * the canonical form. + * 3. eliminate insignificant differences; that is, any two DNs are + * not significantly different if and only if their canonical forms + * are identical (ignoring upper/lower case). + * 4. handle a DN in the syntax defined by RFC 2253. + * 5. handle a DN in the syntax defined by RFC 1779. + * + * Goals 3 through 5 are not entirely achieved by this implementation, + * because it can't be done without violating goal 1. Specifically, + * DNs like cn="a,b" and cn=a\,b are not mapped to the same canonical form, + * although they're not significantly different. Likewise for any pair + * of DNs that differ only in their choice of quoting convention. + * A previous version of this code changed all DNs to the most compact + * quoting convention, but that violated goal 1, since Directory Server + * 3.0 did not. + * + * Also, this implementation handles the \xx convention of RFC 2253 and + * consequently violates RFC 1779, according to which this type of quoting + * would be interpreted as a sequence of 2 numerals (not a single byte). + */ + +DS_EXPORT_SYMBOL char * +dn_normalize_convert( char *dn ) +{ + /* \xx is changed to \c. + \c is changed to c, unless this would change its meaning. + All values that contain 2 or more separators are "enquoted"; + all other values are not enquoted. + */ + char *value, *value_separator; + char *d, *s; + char *end; + + int gotesc = 0; + int state = B4TYPE; + if (NULL == dn) + return dn; + + end = dn + strlen(dn); + for ( d = s = dn; s != end; s++ ) { + switch ( state ) { + case B4TYPE: + if ( ! SPACE( *s ) ) { + state = INTYPE; + *d++ = *s; + } + break; + case INTYPE: + if ( *s == '=' ) { + state = B4VALUE; + *d++ = *s; + } else if ( SPACE( *s ) ) { + state = B4EQUAL; + } else { + *d++ = *s; + } + break; + case B4EQUAL: + if ( *s == '=' ) { + state = B4VALUE; + *d++ = *s; + } else if ( ! SPACE( *s ) ) { + /* not a valid dn - but what can we do here? */ + *d++ = *s; + } + break; + case B4VALUE: + if ( *s == '"' || ! SPACE( *s ) ) { + value_separator = NULL; + value = d; + state = ( *s == '"' ) ? INQUOTEDVALUE : INVALUE; + *d++ = *s; + } + break; + case INVALUE: + if ( gotesc ) { + if ( SEPARATOR( *s ) ) { + if ( value_separator ) value_separator = dn; + else value_separator = d; + } else if ( ! NEEDSESCAPE( *s ) ) { + --d; /* eliminate the \ */ + } + } else if ( SEPARATOR( *s ) ) { + while ( SPACE( *(d - 1) ) ) + d--; + if ( value_separator == dn ) { /* 2 or more separators */ + /* convert to quoted value: */ + auto char *L = NULL; + auto char *R; + for ( R = value; (R = strchr( R, '\\' )) && (R < d); L = ++R ) { + if ( SEPARATOR( R[1] )) { + if ( L == NULL ) { + auto const size_t len = R - value; + if ( len > 0 ) memmove( value+1, value, len ); + *value = '"'; /* opening quote */ + value = R + 1; + } else { + auto const size_t len = R - L; + if ( len > 0 ) { + memmove( value, L, len ); + value += len; + } + --d; + } + } + } + memmove( value, L, d - L + 1 ); + *d++ = '"'; /* closing quote */ + } + state = B4TYPE; + *d++ = (*s == '+') ? '+' : ','; + break; + } + *d++ = *s; + break; + case INQUOTEDVALUE: + if ( gotesc ) { + if ( ! NEEDSESCAPE( *s ) ) { + --d; /* eliminate the \ */ + } + } else if ( *s == '"' ) { + state = B4SEPARATOR; + if ( value_separator == dn /* 2 or more separators */ + || SPACE( value[1] ) || SPACE( d[-1] ) ) { + *d++ = *s; + } else { + /* convert to non-quoted value: */ + if ( value_separator == NULL ) { /* no separators */ + memmove ( value, value+1, (d-value)-1 ); + --d; + } else { /* 1 separator */ + memmove ( value, value+1, (value_separator-value)-1 ); + *(value_separator - 1) = '\\'; + } + } + break; + } + if ( SEPARATOR( *s )) { + if ( value_separator ) value_separator = dn; + else value_separator = d; + } + *d++ = *s; + break; + case B4SEPARATOR: + if ( SEPARATOR( *s ) ) { + state = B4TYPE; + *d++ = (*s == '+') ? '+' : ','; + } + break; + default: +/* LDAPDebug( LDAP_DEBUG_ANY, + "slapi_dn_normalize - unknown state %d\n", state, 0, 0 );*/ + break; + } + if ( *s != '\\' ) { + gotesc = 0; + } else { + gotesc = 1; + if ( s+2 < end ) { + auto int n = hexchar2int( s[1] ); + if ( n >= 0 ) { + auto int n2 = hexchar2int( s[2] ); + if ( n2 >= 0 ) { + n = (n << 4) + n2; + if (n == 0) { /* don't change \00 */ + *d++ = *++s; + *d++ = *++s; + gotesc = 0; + } else { /* change \xx to a single char */ + ++s; + *(unsigned char*)(s+1) = n; + } + } + } + } + } + } + + /* Trim trailing spaces */ + while ( d != dn && *(d - 1) == ' ' ) d--; + + *d = 0; + + return( dn ); +} + +/* if dn contains an unescaped quote return true */ +DS_EXPORT_SYMBOL int +ds_dn_uses_LDAPv2_quoting(const char *dn) +{ + const char ESC = '\\'; + const char Q = '"'; + int ret = 0; + const char *p = 0; + + /* check dn for a even number (incl. 0) of ESC followed by Q */ + if (!dn) + return ret; + + p = strchr(dn, Q); + if (p) + { + int nESC = 0; + for (--p; (p >= dn) && (*p == ESC); --p) + ++nESC; + if (!(nESC % 2)) + ret = 1; + } + + return ret; +} diff --git a/ldap/admin/lib/dsalib_filename.c b/ldap/admin/lib/dsalib_filename.c new file mode 100644 index 00000000..e7ecfb12 --- /dev/null +++ b/ldap/admin/lib/dsalib_filename.c @@ -0,0 +1,95 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#if defined( XP_WIN32 ) +#include <windows.h> +#endif +#include "dsalib.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> + +static char * +get_month_str(int month) +{ + static char *month_str[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", + "Nov", "Dec"}; + + if ( (month < 1) || (month > 12) ) + return("Unknown month"); + return(month_str[month - 1]); +} + +/* + * Returns a string describing the meaning of the filename. + * Two different formats are supported. + */ +DS_EXPORT_SYMBOL char * +ds_get_file_meaning(char *file) +{ + static char meaning[BIG_LINE]; +#define FILE_EXPECTED_SIZE1 14 +#define FILE_EXPECTED_SIZE2 17 + char *name; + char *tmp; + int i; + int month; + int day; + int hour; + int minute; + int sec; + int year; + + /* + * Expect a file name in format 06041996123401 (FILE_EXPECTED_SIZE1) + * which should return "Jun 4 12:34:01 1996" + * OR 1996_06_04_123401 + * which should return "Jun 4 12:34:01 1996" + */ + + if ( file == NULL ) + return(NULL); + name = malloc(strlen(file) + 1); + if ( name == NULL ) + return(NULL); + strcpy(name, file); + if ( (tmp = strrchr(name, '.')) != NULL ) + *tmp = '\0'; + if ( strlen(name) == FILE_EXPECTED_SIZE1 ) { + for ( i = 0; i < FILE_EXPECTED_SIZE1; i++ ) + if ( !isdigit(name[i]) ) + return(NULL); + if ( (sscanf(name, "%2d%2d%4d%2d%2d%2d", &month, &day, &year, &hour, + &minute, &sec)) == -1 ) + return(NULL); + } else if ( strlen(name) == FILE_EXPECTED_SIZE2 ) { + for ( i = 0; i < FILE_EXPECTED_SIZE2; i++ ) + if ( !isdigit(name[i]) ) + if ( name[i] != '_' ) + return(NULL); + if ( (sscanf(name, "%4d_%2d_%2d_%2d%2d%2d", &year, &month, &day, &hour, + &minute, &sec)) == -1 ) + return(NULL); + } else + return(NULL); + + if ( (month < 1) || (month > 12) ) + return(NULL); + if ( (day < 1) || (day > 31) ) + return(NULL); + if ( (year < 1000) || (year > 2100) ) + return(NULL); + if ( (hour < 0) || (hour > 24) ) + return(NULL); + if ( (minute < 0) || (minute > 60) ) + return(NULL); + if ( (sec < 0) || (sec > 60) ) + return(NULL); + sprintf(meaning, "%s % 2d %02d:%02d:%02d %4d", get_month_str(month), + day, hour, minute, sec, year); + return(meaning); +} diff --git a/ldap/admin/lib/dsalib_html.c b/ldap/admin/lib/dsalib_html.c new file mode 100644 index 00000000..cffae406 --- /dev/null +++ b/ldap/admin/lib/dsalib_html.c @@ -0,0 +1,201 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#if defined( XP_WIN32 ) +#include <windows.h> +#endif + +#include "dsalib.h" +#include "prprf.h" +#include <sys/types.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +/* holds the contents of the POSTed data from stdin as an array +of key/value pairs parsed from the key=value input */ +static char **input = 0; + +/* This variable is true if the program should assume stdout is connected + to an HTML context e.g. if this is being run as a normal CGI. It is + false to indicate that output should not contain HTML formatting, + Javascript, etc. put plain ol' ASCII only +*/ +static int formattedOutput = 1; + +/* This is the separator string to use when outputting key/value pairs + to be read by the non-HTML front end (Java console) +*/ +static const char *SEPARATOR = ":"; /* from AdmTask.java */ + +DS_EXPORT_SYMBOL int +ds_get_formatted_output(void) +{ + return formattedOutput; +} + +DS_EXPORT_SYMBOL void +ds_set_formatted_output(int val) +{ + formattedOutput = val; +} + +DS_EXPORT_SYMBOL void +ds_print_file_name(char *fileptr) +{ + char *meaning; + + fprintf(stdout, "%s", fileptr); + if ( (meaning = ds_get_file_meaning(fileptr)) != NULL ) { + fprintf(stdout, " (%s)", meaning); + } +} + +/* + * Get a CGI variable. + */ +DS_EXPORT_SYMBOL char * +ds_get_cgi_var(char *cgi_var_name) +{ + char *cgi_var_value; + + cgi_var_value = (char *) ds_a_get_cgi_var(cgi_var_name, NULL, NULL); + if ( cgi_var_value == NULL ) { + /* + * The ds_a_get_cgi_var() lies! It gives a NULL even if the + * value is "". So assume the variable is there and + * return an empty string. + */ + return(""); + } + return(cgi_var_value); +} + +/* parse POST input to a CGI program */ +DS_EXPORT_SYMBOL int +ds_post_begin(FILE *in) +{ + char *vars = NULL, *tmp = NULL, *decoded_vars = NULL; + int cl; + + if(!(tmp = getenv("CONTENT_LENGTH"))) + { + ds_report_error(DS_INCORRECT_USAGE, "Browser Error", "Your browser" + " sent no content length with a POST command." + " Please be sure to use a fully compliant browser."); + return 1; + } + + cl = atoi(tmp); + + vars = (char *)malloc(cl+1); + + if( !(fread(vars, 1, cl, in)) ) + { + ds_report_error(DS_SYSTEM_ERROR, "CGI error", + "The POST variables could not be read from stdin."); + return 1; + } + + vars[cl] = '\0'; + + decoded_vars = ds_URL_decode(vars); + free(vars); + + input = ds_string_to_vec(decoded_vars); + free(decoded_vars); +/* + for (cl = 0; input[cl]; ++cl) + printf("ds_post_begin: read cgi var=[%s]\n", input[cl]); +*/ + return 0; +} + +/* parse GET input to a CGI program */ +DS_EXPORT_SYMBOL void +ds_get_begin(char *query_string) +{ + char *decoded_input = ds_URL_decode(query_string); + input = ds_string_to_vec(decoded_input); + free(decoded_input); +} + +/* + Borrowed from libadmin/form_post.c +*/ +DS_EXPORT_SYMBOL char * +ds_a_get_cgi_var(char *varname, char *elem_id, char *bongmsg) +{ + register int x = 0; + int len = strlen(varname); + char *ans = NULL; + + while(input[x]) { + /* We want to get rid of the =, so len, len+1 */ + if((!strncmp(input[x], varname, len)) && (*(input[x]+len) == '=')) { + ans = strdup(input[x] + len + 1); + if(!strcmp(ans, "")) + ans = NULL; + break; + } else + x++; + } + if(ans == NULL) { + if ((bongmsg) && strlen(bongmsg)) + { + /* prefix error with varname so output interpreters can determine */ + /* which parameter is in error */ + char *msg; + if (!ds_get_formatted_output() && (varname != NULL)) + { + msg = PR_smprintf("%s.error: %s %s", varname, elem_id, bongmsg); + } + else + { + msg = PR_smprintf("error: %s %s", elem_id, bongmsg); + } + ds_show_message(msg); + PR_smprintf_free(msg); + } + else + return NULL; + } + else + return(ans); + /* shut up gcc */ + return NULL; +} + +DS_EXPORT_SYMBOL char ** +ds_string_to_vec(char *in) +{ + char **ans; + int vars = 0; + register int x = 0; + char *tmp; + + in = strdup(in); + + while(in[x]) + if(in[x++]=='=') + vars++; + + + ans = (char **)calloc(vars+1, sizeof(char *)); + + x=0; + /* strtok() is not MT safe, but it is okay to call here because it is used in monothreaded env */ + tmp = strtok(in, "&"); + ans[x++]=strdup(tmp); + + while((tmp = strtok(NULL, "&"))) { + ans[x++] = strdup(tmp); + } + + free(in); + + return(ans); +} diff --git a/ldap/admin/lib/dsalib_ldif.c b/ldap/admin/lib/dsalib_ldif.c new file mode 100644 index 00000000..94c0d77f --- /dev/null +++ b/ldap/admin/lib/dsalib_ldif.c @@ -0,0 +1,374 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#if defined( XP_WIN32 ) +#include <windows.h> +#include <process.h> +#include <malloc.h> +#define popen _popen +#define pclose _pclose +#else +#include <unistd.h> +#endif +#include "dsalib.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#ifndef XP_WIN32 +#define SCRIPT_SUFFIX "" /* shell scripts have no suffix */ +#else +#define SCRIPT_SUFFIX ".bat" /* batch file suffix */ +#endif + + +static int +process_and_report( char *line, int line_size, FILE *cmd ) +{ + int err = 0; + while(fgets(line, line_size, cmd)) { + /* Strip off line feeds */ + int ind = strlen( line ) - 1; +#ifdef DEBUG_CGI + fprintf(stderr, "read line=[%s] ind=%d\n", line, ind); +#endif /* DEBUG_CGI */ + fprintf( stdout, ": %s", line ); + fflush(0); + while ( (ind >= 0) && + ((line[ind] == '\n') || + (line[ind] == '\r')) ) { + line[ind] = 0; + ind--; + } + if ( ind < 1 ) { + continue; + } + ds_send_status(line); + if ( (strstr(line, "bad LDIF") != NULL) ) { +#ifdef DEBUG_CGI + fprintf(stderr, "invalid ldif file\n"); +#endif /* DEBUG_CGI */ + err = DS_INVALID_LDIF_FILE; + } else if ( 0 == err ) { + if ( (strstr(line, "err=") != NULL) ) { +#ifdef DEBUG_CGI + fprintf(stderr, "unknown error\n"); +#endif /* DEBUG_CGI */ + err = DS_UNKNOWN_ERROR; + } + } + } +#ifdef DEBUG_CGI + fprintf(stderr, "process_and_report finished err=%d\n", err); +#endif /* DEBUG_CGI */ + return err; +} + +static int exec_and_report( char *startup_line ) +{ + FILE *cmd = NULL; + char line[BIG_LINE]; + int haderror = 0; + + PATH_FOR_PLATFORM( startup_line ); + alter_startup_line(startup_line); + + fflush(stdout); + cmd = popen(startup_line, "r"); + if(!cmd) { + printf("could not open pipe [%s]: %d\n", + startup_line, errno); +#ifdef DEBUG_CGI + fprintf(stderr, "could not open pipe [%s]: %d\n", + startup_line, errno); +#endif /* DEBUG_CGI */ + return DS_CANNOT_EXEC; + } + haderror = process_and_report( line, sizeof(line), cmd ); + pclose(cmd); + + return haderror; +} + +/* + * Execute a shell command. + * 0: success + * anything else: failure + */ +DS_EXPORT_SYMBOL int +ds_exec_and_report( char *startup_line ) +{ + return exec_and_report( startup_line ); +} + +/* + * Create a database based on a file name. + * 0: success + * anything else: failure + */ +static int +importldif(char *file, int preserve, char *backend, char *subtree) +{ + char startup_line[BIG_LINE]; + char *root; + int haderror = 0; + int i = 0, error = -1; + int status; + struct stat fstats; + char errbuf[ BIG_LINE ]; + char **db_files = NULL, *changelogdir = NULL; + int rc; + + errbuf[ 0 ] = '\0'; + + if ( file == NULL ) { +#ifdef DEBUG_CGI + fprintf(stderr, "importldif: null file\n"); +#endif /* DEBUG_CGI */ + return DS_NULL_PARAMETER; + } + status = ds_get_updown_status(); + if ( status == DS_SERVER_UP ) { +#ifdef DEBUG_CGI + fprintf(stderr, "importldif: server is not down\n"); +#endif /* DEBUG_CGI */ + return DS_SERVER_MUST_BE_DOWN; + } + if ( (root = ds_get_install_root()) == NULL ) { +#ifdef DEBUG_CGI + fprintf(stderr, "importldif: could not get server root\n"); +#endif /* DEBUG_CGI */ + return DS_NO_SERVER_ROOT; + } + + if ( file[strlen(file) - 1] == '\n' ) /* strip out returns */ + file[strlen(file) - 1] = '\0'; + + /* Make sure the file exists and is not a directory: 34347 */ + if( stat( file, &fstats ) == -1 && errno == ENOENT ) { +#ifdef DEBUG_CGI + fprintf(stderr, "importldif: could not open %s\n", file); +#endif /* DEBUG_CGI */ + return DS_CANNOT_OPEN_LDIF_FILE; + } else if( fstats.st_mode & S_IFDIR ) { +#ifdef DEBUG_CGI + fprintf(stderr, "importldif: not a file %s\n", file); +#endif /* DEBUG_CGI */ + return DS_IS_A_DIRECTORY; + } + + if ( preserve ) { + sprintf(startup_line, "%s%cldif2db%s -i %s%s%s", + root, FILE_SEP, SCRIPT_SUFFIX, + ENQUOTE, file, ENQUOTE); + } else if (backend) { + sprintf(startup_line, "%s%cldif2db%s -n %s%s%s -i %s%s%s", + root, FILE_SEP, SCRIPT_SUFFIX, + ENQUOTE, backend, ENQUOTE, + ENQUOTE, file, ENQUOTE); + } else if (subtree) { + sprintf(startup_line, "%s%cldif2db%s -s %s%s%s -i %s%s%s", + root, FILE_SEP, SCRIPT_SUFFIX, + ENQUOTE, subtree, ENQUOTE, + ENQUOTE, file, ENQUOTE); + } else { + sprintf(startup_line, "%s%cldif2db%s -i %s%s%s -noconfig", + root, FILE_SEP, SCRIPT_SUFFIX, + ENQUOTE, file, ENQUOTE); + } + alter_startup_line(startup_line); + fflush(stdout); +#ifdef DEBUG_CGI + fprintf(stderr, "importldif: executing %s\n", startup_line); +#endif /* DEBUG_CGI */ + error = exec_and_report(startup_line); + /*error = system(startup_line);*/ + if ( error != 0 ) { +#ifdef DEBUG_CGI + fprintf(stderr, "importldif: error=%d\n", error); +#endif /* DEBUG_CGI */ + return error; + } + + /* Remove the changelog database, if present */ + changelogdir = ds_get_config_value(0xdeadbeef); + if ( changelogdir != NULL ) { + db_files = ds_get_file_list( changelogdir ); + if ( db_files != NULL ) { + ds_send_status("Removing changelog database..."); + } + for ( i = 0; db_files != NULL && db_files[ i ] != NULL; i++ ) { + char sbuf[ BIG_LINE ]; + char filename[ BIG_LINE ]; + if ( strlen( db_files[ i ]) > 0 ) { + sprintf( filename, "%s%c%s", changelogdir, + FILE_SEP, db_files[ i ]); + sprintf(sbuf, "Removing %s", filename); + ds_send_status( sbuf ); + rc = unlink( filename); + if ( rc != 0 ) { + sprintf( errbuf, "Warning: some files in %s could not " + "be removed\n", changelogdir ); + haderror++; + } + } + } + } + if ( strlen( errbuf ) > 0 ) { + ds_send_error( errbuf, 0 ); + } + + return error; +} + +/* + * Create a database based on a file name. + * 0: success + * anything else: failure + */ +DS_EXPORT_SYMBOL int +ds_ldif2db(char *file) +{ + return importldif( file, 0, NULL, NULL ); +} + +/* + * Create a database based on a file name. + * 0: success + * anything else: failure + */ +DS_EXPORT_SYMBOL int +ds_ldif2db_preserve(char *file) +{ + return importldif( file, 1, NULL, NULL ); +} + +/* + * import an ldif file into a named backend or subtree + * 0: success + * anything else: failure + */ +DS_EXPORT_SYMBOL int +ds_ldif2db_backend_subtree(char *file, char *backend, char *subtree) +{ + return importldif( file, 0, backend, subtree ); +} + +/* + * Create a LDIF file based on a file name. + * 0: success + * anything else: failure + */ +DS_EXPORT_SYMBOL int +ds_db2ldif_subtree(char *file, char *subtree) +{ + char startup_line[BIG_LINE]; + char statfile[PATH_MAX]; + char outfile[PATH_MAX]; + char scriptfile[PATH_MAX]; + char *tmp_dir; + char *root; + int haderror = 0; + int error = -1; + FILE *sf = NULL; + + if ( (root = ds_get_install_root()) == NULL ) { + return DS_NO_SERVER_ROOT; + } + + if ( (file == NULL) || (strlen(file) == 0) ) + file = NULL; + + tmp_dir = ds_get_tmp_dir(); + sprintf(statfile, "%s%cdb2ldif.%d", tmp_dir, FILE_SEP, (int) getpid()); + +#if defined( XP_WIN32 ) + if( file == NULL ) + { + time_t ltime; + file = malloc( BIG_LINE ); + + time( <ime ); + sprintf( file, "%s", ctime( <ime ) ); + ds_timetofname( file ); + } +#endif + + if ( file == NULL ) + *outfile = 0; + else + strcpy( outfile, file ); + + sprintf(scriptfile, "%s%cdb2ldif", root, FILE_SEP); + + PATH_FOR_PLATFORM( outfile ); + PATH_FOR_PLATFORM( scriptfile ); + + if ( subtree == NULL ) { + sprintf(startup_line, + "%s " + "%s%s%s > " + "%s%s%s 2>&1", + scriptfile, + ENQUOTE, outfile, ENQUOTE, + ENQUOTE, statfile, ENQUOTE); + } else { + sprintf(startup_line, + "%s " + "%s%s%s " + "-s \"%s\" > " + "%s%s%s 2>&1", + scriptfile, + ENQUOTE, outfile, ENQUOTE, + subtree, + ENQUOTE, statfile, ENQUOTE); + } + + fflush(0); + alter_startup_line(startup_line); + error = system(startup_line); + if ( error == -1 ) { + return DS_CANNOT_EXEC; + } + sf = fopen(statfile, "r"); + if( sf ) { + while ( fgets(startup_line, BIG_LINE, sf) ) { + /* + The db2ldif process will usually print out a summary at the + end, but that is not an error + */ + char *ptr = strstr(startup_line, "Processed"); + if (ptr && strstr(ptr, "entries.")) + { + ds_show_message(startup_line); + } + else + { + haderror = 1; + ds_send_error(startup_line, 0); + } + } + fclose(sf); + unlink(statfile); + } + + if ( haderror ) + return DS_UNKNOWN_ERROR; + return 0; +} + +/* + * Create a LDIF file based on a file name. + * 0: success + * anything else: failure + */ +DS_EXPORT_SYMBOL int +ds_db2ldif(char *file) +{ + return ds_db2ldif_subtree(file, NULL); +} diff --git a/ldap/admin/lib/dsalib_location.c b/ldap/admin/lib/dsalib_location.c new file mode 100644 index 00000000..06cbafb5 --- /dev/null +++ b/ldap/admin/lib/dsalib_location.c @@ -0,0 +1,142 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#if defined( XP_WIN32 ) +#include <windows.h> +#endif +#include "dsalib.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +/* + * Returns the server root. Info is + * returned in a static area. The caller must copy it + * for reuse if needed. + */ +DS_EXPORT_SYMBOL char * +ds_get_server_root() +{ + char *root; + + if ( (root = getenv("NETSITE_ROOT")) == NULL ) + return(NULL); + + /* WIN32: Needed to take care of embedded space, */ + /* otherwise system() call fails */ + root = ds_makeshort( root ); + + return root; +} + +/* + * Returns the install location of the server. Info is + * returned in a static area. The caller must copy it + * for reuse if needed. + */ +DS_EXPORT_SYMBOL char * +ds_get_install_root() +{ + char *root; + char *ds_name; + static char install_root[PATH_MAX]; + + if ( (root = ds_get_server_root()) == NULL ) + return(NULL); + if ( (ds_name = ds_get_server_name()) == NULL ) + return(NULL); + + sprintf(install_root, "%s/%s", root, ds_name); + return(install_root); +} + +/* + * Returns the install location of the server under the admserv + * directory. + */ +DS_EXPORT_SYMBOL char * +ds_get_admserv_based_root() +{ + char *root; + char *ds_name; + static char install_root[PATH_MAX]; + + if ( (root = getenv("ADMSERV_ROOT")) == NULL ) + return(NULL); + if ( (ds_name = ds_get_server_name()) == NULL ) + return(NULL); + sprintf(install_root, "%s/%s", root, ds_name); + return(install_root); +} + +DS_EXPORT_SYMBOL char * +ds_get_server_name() +{ + if( getenv("SERVER_NAMES") ) + return( getenv("SERVER_NAMES") ); + else { + static char logfile[PATH_MAX]; + char *buf; + char *out = logfile; + buf = getenv("SCRIPT_NAME"); + if ( buf && (*buf == '/') ) + buf++; + while ( *buf && (*buf != '/') ) { + *out++ = *buf++; + } + *out = 0; + return logfile; + } +} + +DS_EXPORT_SYMBOL char * +ds_get_logfile_name(int config_type) +{ + char *filename; + char **ds_config = NULL; + static char logfile[PATH_MAX]; + + if ( (ds_config = ds_get_config(DS_REAL_CONFIG)) == NULL ) { + /* For DS 4.0, no error output if file doesn't exist - that's + a normal situation */ + /* ds_send_error("ds_get_config(DS_REAL_CONFIG) == NULL", 0); */ + return(NULL); + } + filename = ds_get_value(ds_config, ds_get_var_name(config_type), 0, 1); + + if ( filename == NULL ) { + /* For DS 4.0, no error output if file doesn't exist - that's + a normal situation */ + /* ds_send_error("ds_get_logfile_name: filename == NULL", 0); */ + return(NULL); + } + if ( ((int) strlen(filename)) >= PATH_MAX ) { + ds_send_error("ds_get_logfile_name: filename too long", 0); + free(filename); + return(NULL); + } + strcpy(logfile, filename); + free(filename); + return(logfile); +} + +DS_EXPORT_SYMBOL char * +ds_get_errors_name() +{ + return( ds_get_logfile_name(DS_ERRORLOG) ); +} + +DS_EXPORT_SYMBOL char * +ds_get_access_name() +{ + return( ds_get_logfile_name(DS_ACCESSLOG) ); +} + +DS_EXPORT_SYMBOL char * +ds_get_audit_name() +{ + return( ds_get_logfile_name(DS_AUDITFILE) ); +} + diff --git a/ldap/admin/lib/dsalib_pw.c b/ldap/admin/lib/dsalib_pw.c new file mode 100644 index 00000000..21fd8ecb --- /dev/null +++ b/ldap/admin/lib/dsalib_pw.c @@ -0,0 +1,29 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * Adjust password policy management related variables. + * + * Valerie Chu + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/types.h> +#include "ldap.h" +#include "ldif.h" +#include "sechash.h" +#include "dsalib.h" +#include "dsalib_pw.h" + +extern char * salted_sha1_pw_enc(char *); + +DS_EXPORT_SYMBOL char * +ds_salted_sha1_pw_enc (char* pwd) +{ + return( salted_sha1_pw_enc(pwd) ); +} diff --git a/ldap/admin/lib/dsalib_tailf.c b/ldap/admin/lib/dsalib_tailf.c new file mode 100644 index 00000000..04e04578 --- /dev/null +++ b/ldap/admin/lib/dsalib_tailf.c @@ -0,0 +1,206 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#if defined( XP_WIN32 ) +#include <windows.h> +#endif +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include "dsalib.h" +#include "prthread.h" + +/* + * Function: adjustFile + * Property: Adjust the file offset to the "tail" of the file + * Called by: DisplayTail + * Return: -1 for error, else file size + */ +static int +adjustFile(FILE *fp, int curSize) +{ + struct stat statBuf; + int fd = fileno(fp); + + if ( fstat(fd, &statBuf) == -1 ) + return(-1); + if ( statBuf.st_size < curSize ) /* file has shrunk! */ + { + if ( fseek(fp, 0L, 0) == -1 ) /* get back to the beginning */ + return(-1); + } + curSize = (int) statBuf.st_size; + if ( !curSize ) + curSize = 1; + return(curSize); +} + +/* + * Function: wrapLines + * Property: wrap lines at 50 characters. When a wrap point is encountered, + * insert the string "\n", since the buffer is going to be placed + * inside a JavaScript alert() call. + * Called by: ds_display_tail + * Return: pointer to wrapped buffer. Caller should free. + */ +static char * +wrapLines( char *buf ) +{ + char *src = buf; + char *obuf, *dst; + int lwidth = 0; + + obuf = malloc( strlen( buf ) * 2 ); /* conservative */ + if ( obuf == NULL ) { + return NULL; + } + dst = obuf; + while ( *src != '\0' ) { + if (( ++lwidth > 50 ) && isspace( *src )) { + *dst++ = '\\'; + *dst++ = 'n'; + lwidth = 0; + src++; + } else { + *dst++ = *src++; + } + } + *dst = '\0'; + return obuf; +} + +DS_EXPORT_SYMBOL int +ds_get_file_size(char *fileName) +{ + struct stat statBuf; + + if ( fileName == NULL ) + return(0); + + if ( stat(fileName, &statBuf) == -1 ) + return(0); + + return(statBuf.st_size); +} + +/* + * Function: ds_display_tail + * Property: follow the tail and display it for timeOut secs or until the line + * read from the file contains the string doneMsg; the lastLine, if not null, + * will be filled in with the last line read from the file; this is useful + * for determining why the server failed to start e.g. port in use, ran out + * of semaphores, database is corrupted, etc. + * Calls: adjustFile + */ +DS_EXPORT_SYMBOL void +ds_display_tail(char *fileName, int timeOut, int startSeek, char *doneMsg, + char *lastLine) +{ + FILE *fp = NULL; + int fd; + char msgBuf[BIG_LINE]; + struct stat statBuf; + int curSize; + int i = timeOut; + + if (lastLine != NULL) + lastLine[0] = 0; + + if ( fileName == NULL ) + return; + /* + * Open the file. + * Try to keep reading it assuming that it may get truncated. + */ + while (i && !fp) + { + fp = fopen(fileName, "r"); + if (!fp) + { + PR_Sleep(PR_SecondsToInterval(1)); + --i; + /* need to print something so http connection doesn't + timeout and also to let the user know something is + happening . . . + */ + if (!(i % 10)) + { + ds_send_status("Attempting to obtain server status . . ."); + } + } + } + + if (!i || !fp) + return; + + fd = fileno(fp); + if ( fstat(fd, &statBuf) == -1 ) { + (void) fclose(fp); + return; + } + curSize = (int) statBuf.st_size; + if ( startSeek < curSize ) + curSize = startSeek; + if ( curSize > 0 ) + if ( fseek(fp, curSize, SEEK_SET) == -1 ) { + (void) fclose(fp); + return; + } + if ( !curSize ) + curSize = 1; /* ensure minimum */ + + while ( i ) + { + int newCurSize; + + newCurSize = curSize = adjustFile(fp, curSize); + if ( curSize == -1 ) { + (void) fclose(fp); + return; + } + while ( fgets(msgBuf, sizeof(msgBuf), fp) ) + { + char *tmp; + if (lastLine != NULL) + strcpy(lastLine, msgBuf); + if ( (tmp = strchr(msgBuf, ((int) '\n'))) != NULL ) + *tmp = '\0'; /* strip out real newlines from here */ + ds_send_status(msgBuf); + if ( (strstr(msgBuf, "WARNING: ") != NULL) || + (strstr(msgBuf, "ERROR: ") != NULL) ) { + char *wrapBuf; + + wrapBuf = wrapLines( msgBuf ); + if ( wrapBuf != NULL ) { + ds_send_error(wrapBuf, 5); + } else { + ds_send_error(msgBuf, 5); + } + } + if ( (doneMsg != NULL) && (strstr(msgBuf, doneMsg)) ) { + (void) fclose(fp); + return; + } + newCurSize = adjustFile(fp, newCurSize); + if ( newCurSize == -1 ) { + (void) fclose(fp); + return; + } + } + if ( ferror(fp) ) { + (void) fclose(fp); + return; + } + clearerr(fp); /* clear eof condition */ + PR_Sleep(PR_SecondsToInterval(1)); + if ( newCurSize != curSize ) + i = timeOut; /* keep going till no more changes */ + else + i--; + } + (void) fclose(fp); +} diff --git a/ldap/admin/lib/dsalib_updown.c b/ldap/admin/lib/dsalib_updown.c new file mode 100644 index 00000000..4f041208 --- /dev/null +++ b/ldap/admin/lib/dsalib_updown.c @@ -0,0 +1,702 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#if defined( XP_WIN32 ) +#include <windows.h> +#include <process.h> +#include "regparms.h" +#else +#include <signal.h> +#include <sys/signal.h> +#include <unistd.h> +#endif +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include "dsalib.h" +#include <string.h> +#include "nspr.h" + +#if defined( XP_WIN32 ) +SC_HANDLE schService; +SC_HANDLE schSCManager; + +int StartServer(); +int StopandRestartServer(); +int StopServer(); + +int StopNetscapeProgram(); +int StartNetscapeProgram(); + +int StopNetscapeService(); +int StartNetscapeService(); +void WaitForServertoStop(); +#endif + +/* + * Get status for the Directory Server. + * 0 -- down + * 1 -- up + * -1 -- unknown + */ +#if !defined( XP_WIN32 ) +static pid_t server_pid; + +DS_EXPORT_SYMBOL int +ds_get_updown_status() +{ + char pid_file_name[BIG_LINE]; + char *root; + FILE *pidfile; + int ipid = -1; + int status = 0; + + if ( (root = ds_get_install_root()) == NULL ) { + fprintf(stderr, "ds_get_updown_status: could not get install root\n"); + return(DS_SERVER_UNKNOWN); + } + sprintf(pid_file_name, "%s/logs/pid", root); + pidfile = fopen(pid_file_name, "r"); + if ( pidfile == NULL ) { +/* + fprintf(stderr, + "ds_get_updown_status: could not open pid file=%s errno=%d\n", + pid_file_name, errno); +*/ + return(DS_SERVER_DOWN); + } + status = fscanf(pidfile, "%d\n", &ipid); + fclose(pidfile); + if ( status == -1 ) { + fprintf(stderr, + "ds_get_updown_status: pidfile=%s server_pid=%d errno=%d\n", + pid_file_name, ipid, errno); + unlink(pid_file_name); /* junk in file? */ + return(DS_SERVER_DOWN); + } + server_pid = (pid_t) ipid; + if ( (status = kill(server_pid, 0)) != 0 && errno != EPERM ) { + /* we should get ESRCH if the server is down, anything else may be + a real problem */ + if (errno != ESRCH) { + fprintf(stderr, + "ds_get_updown_status: pidfile=%s server_pid=%d status=%d errno=%d\n", + pid_file_name, server_pid, status, errno); + } + unlink(pid_file_name); /* pid does not exist! */ + return(DS_SERVER_DOWN); + } + return(DS_SERVER_UP); +} +#else +DS_EXPORT_SYMBOL int +ds_get_updown_status() +{ + char *ds_name = ds_get_server_name(); + HANDLE hServerDoneEvent = NULL; + + /* watchdog.c creates a global event of this same name */ + if((hServerDoneEvent = OpenEvent(EVENT_ALL_ACCESS, TRUE, ds_name)) != NULL) + { + CloseHandle(hServerDoneEvent); + return(DS_SERVER_UP); + } + if(GetLastError() == ERROR_ACCESS_DENIED) /* it exists */ + return(DS_SERVER_UP); + + /* assume it's not running. */ + return(DS_SERVER_DOWN); +} +#endif + +/* + This function does not require calling ds_get_config(), but requires + that that information be passed in. This is very useful for starting + the server during installation, because we already have all of the + configuration information in memory, we don't need to read it in +*/ +DS_EXPORT_SYMBOL int +ds_bring_up_server_install(int verbose, char *root, char *errorlog) +{ +#if !defined( XP_WIN32 ) + char startup_line[BIG_LINE]; + char statfile[PATH_MAX]; + char *tmp_dir; +#endif + int error = -1; + int status = DS_SERVER_DOWN; + int cur_size = 0; + FILE *sf = NULL; + char msgBuf[BIG_LINE] = {0}; + int secondsToWaitForServer = 600; + char *serverStartupString = "slapd started."; + + status = ds_get_updown_status(); + if ( status == DS_SERVER_UP ) + return(DS_SERVER_ALREADY_UP); + if (!root || !errorlog) + return(DS_SERVER_UNKNOWN); + + if (verbose) { + ds_send_status("starting up server ..."); + cur_size = ds_get_file_size(errorlog); + } + +#if !defined( XP_WIN32 ) + tmp_dir = ds_get_tmp_dir(); + sprintf(statfile, "%s%cstartup.%d", tmp_dir, FILE_SEP, (int)getpid()); + + sprintf(startup_line, "%s%c%s > %s 2>&1", + root, FILE_SEP, START_SCRIPT, statfile); + alter_startup_line(startup_line); + error = system(startup_line); + if (error == -1) + error = DS_SERVER_DOWN; /* could not start server */ + else + error = DS_SERVER_UP; /* started server */ +#else + error = StartServer(); +#endif + + if (error != DS_SERVER_UP) + { +#if !defined( XP_WIN32 ) + FILE* fp = fopen(statfile, "r"); + if (fp) + { + while(fgets(msgBuf, BIG_LINE, fp)) + ds_send_status(msgBuf); + fclose(fp); + } +#endif + return DS_SERVER_COULD_NOT_START; + } + + if (verbose) + { + /* + * Stop in N secs or whenever the startup message comes up. + * Do whichever happens first. msgBuf will contain the last + * line read from the errorlog. + */ + ds_display_tail(errorlog, secondsToWaitForServer, cur_size, + serverStartupString, msgBuf); + } + if ( error != DS_SERVER_UP ) { + int retval = DS_SERVER_UNKNOWN; + if (strstr(msgBuf, "semget")) + retval = DS_SERVER_MAX_SEMAPHORES; + else if (strstr(msgBuf, "Back-End Initialization Failed")) + retval = DS_SERVER_CORRUPTED_DB; + else if (strstr(msgBuf, "not initialized... exiting")) + retval = DS_SERVER_CORRUPTED_DB; + else if (strstr(msgBuf, "address is in use")) + retval = DS_SERVER_PORT_IN_USE; +#if defined( XP_WIN32 ) + /* on NT, if we run out of resources, there will not even be an error + log + */ + else if (msgBuf[0] == 0) { + retval = DS_SERVER_NO_RESOURCES; + } +#endif + if (verbose) + ds_send_error("error in starting server.", 1); + return(retval); + } + if (verbose) { +#if !defined( XP_WIN32 ) + if( !(sf = fopen(statfile, "r")) ) { + ds_send_error("could not read status file.", 1); + return(DS_SERVER_UNKNOWN); + } + + while ( fgets(startup_line, BIG_LINE, sf) ) + ds_send_error(startup_line, 0); + fclose(sf); + unlink(statfile); +#endif + status = DS_SERVER_UNKNOWN; + if (strstr(msgBuf, "semget")) + status = DS_SERVER_MAX_SEMAPHORES; + else if (strstr(msgBuf, "Back-End Initialization Failed")) + status = DS_SERVER_CORRUPTED_DB; + else if (strstr(msgBuf, "not initialized... exiting")) + status = DS_SERVER_CORRUPTED_DB; + else if (strstr(msgBuf, "address is in use")) + status = DS_SERVER_PORT_IN_USE; +#if defined( XP_WIN32 ) + /* on NT, if we run out of resources, there will not even be an error + log + */ + else if (msgBuf[0] == 0) { + status = DS_SERVER_NO_RESOURCES; + } +#endif + } else { + int tries; + for (tries = 0; tries < secondsToWaitForServer; tries++) { + if (ds_get_updown_status() == DS_SERVER_UP) break; + PR_Sleep(PR_SecondsToInterval(1)); + } + if (verbose) { + char str[100]; + sprintf(str, "Had to retry %d times", tries); + ds_send_status(str); + } + } + + if ( (status == DS_SERVER_DOWN) || (status == DS_SERVER_UNKNOWN) ) + status = ds_get_updown_status(); + + return(status); +} + +/* + * Start the Directory Server and return status. + * Do not start if the server is already started. + * 0 -- down + * 1 -- up + * -1 -- unknown + * -2 -- already up + */ + +DS_EXPORT_SYMBOL int +ds_bring_up_server(int verbose) +{ + char *root; + int status; + char *errorlog; + status = ds_get_updown_status(); + if ( status == DS_SERVER_UP ) + return(DS_SERVER_ALREADY_UP); + if ( (root = ds_get_install_root()) == NULL ) + return(DS_SERVER_UNKNOWN); + + errorlog = ds_get_config_value(DS_ERRORLOG); + if ( errorlog == NULL ) { + errorlog = ds_get_errors_name(); /* fallback */ + } + return ds_bring_up_server_install(verbose, root, errorlog); +} + +DS_EXPORT_SYMBOL int +ds_bring_down_server() +{ + char *root; + int status; + int cur_size; + char *errorlog; + + status = ds_get_updown_status(); /* set server_pid too! */ + if ( status != DS_SERVER_UP ) { + ds_send_error("The server is not up.", 0); + return(DS_SERVER_ALREADY_DOWN); + } + if ( (root = ds_get_install_root()) == NULL ) { + ds_send_error("Could not get the server root directory.", 0); + return(DS_SERVER_UNKNOWN); + } + + ds_send_status("shutting down server ..."); + if (!(errorlog = ds_get_errors_name())) { + ds_send_error("Could not get the error log filename.", 0); + return DS_SERVER_UNKNOWN; + } + + cur_size = ds_get_file_size(errorlog); +#if !defined( XP_WIN32 ) + if ( (kill(server_pid, SIGTERM)) != 0) { + if (errno == EPERM) { + ds_send_error("Not permitted to kill server.", 0); + fprintf (stdout, "[%s]: kill (%li, SIGTERM) failed with errno = EPERM.<br>\n", + ds_get_server_name(), (long)server_pid); + } else { + ds_send_error("error in killing server.", 1); + } + return(DS_SERVER_UNKNOWN); + } +#else + if( StopServer() == DS_SERVER_DOWN ) + { + ds_send_status("shutdown: server shut down"); + } + else + { + ds_send_error("error in killing server.", 1); + return(DS_SERVER_UNKNOWN); + } +#endif + /* + * Wait up to SERVER_STOP_TIMEOUT seconds for the stopped message to + * appear in the error log. + */ + ds_display_tail(errorlog, SERVER_STOP_TIMEOUT, cur_size, "slapd stopped.", NULL); + /* in some cases, the server will tell us it's down when it's really not, + so give the OS a chance to remove it from the process table */ + PR_Sleep(PR_SecondsToInterval(1)); + return(ds_get_updown_status()); +} + +#if defined( XP_WIN32 ) + +static BOOLEAN +IsService() +{ +#if 0 + CHAR ServerKey[512], *ValueString; + HKEY hServerKey; + DWORD dwType, ValueLength, Result; + + sprintf(ServerKey,"%s\\%s\0", COMPANY_KEY, PRODUCT_KEY); + + Result = RegOpenKey(HKEY_LOCAL_MACHINE, ServerKey, &hServerKey); + if (Result != ERROR_SUCCESS) { + return TRUE; + } + ValueLength = 512; + ValueString = (PCHAR)malloc(ValueLength); + + Result = RegQueryValueEx(hServerKey, IS_SERVICE_KEY, NULL, + &dwType, ValueString, &ValueLength); + if (Result != ERROR_SUCCESS) { + return TRUE; + } + if (strcmp(ValueString, "yes")) { + return FALSE; + } + else { + return TRUE; + } +#else + return TRUE; +#endif +} + +#if 0 +NSAPI_PUBLIC BOOLEAN +IsAdminService() +{ + CHAR AdminKey[512], *ValueString; + HKEY hAdminKey; + DWORD dwType, ValueLength, Result; + + sprintf(AdminKey,"%s\\%s\0", COMPANY_KEY, ADMIN_REGISTRY_ROOT_KEY); + + Result = RegOpenKey(HKEY_LOCAL_MACHINE, AdminKey, &hAdminKey); + if (Result != ERROR_SUCCESS) { + return TRUE; + } + ValueLength = 512; + ValueString = (PCHAR)malloc(ValueLength); + + Result = RegQueryValueEx(hAdminKey, IS_SERVICE_KEY, NULL, + &dwType, ValueString, &ValueLength); + if (Result != ERROR_SUCCESS) { + return TRUE; + } + if (strcmp(ValueString, "yes")) { + return FALSE; + } else { + return TRUE; + } +} +#endif + +int +StartServer() +{ + CHAR ErrorString[512]; + BOOLEAN Service; + + /* Figure out if the server is a service or an exe */ + Service = IsService(); + + if(Service) { + if (!(schSCManager = OpenSCManager( + NULL, // machine (NULL == local) + NULL, // database (NULL == default) + SC_MANAGER_ALL_ACCESS // access required + ))) { + sprintf(ErrorString, + "Error: Could not open the ServiceControlManager:%d " + "Please restart the server %s from the Services Program Item " + "in the Control Panel", ds_get_server_name(), GetLastError()); + ds_send_error(ErrorString, 0); + return(DS_SERVER_UNKNOWN); + } + return(StartNetscapeService()); + } else { + return(StartNetscapeProgram()); + } +} + +int +StopandRestartServer() +{ + CHAR ErrorString[512]; + BOOLEAN Service; + + + /* First figure out if the server is a service or an exe */ + Service = IsService(); + if(Service) { + if (!(schSCManager = OpenSCManager( + NULL, // machine (NULL == local) + NULL, // database (NULL == default) + SC_MANAGER_ALL_ACCESS // access required + ))) { + sprintf(ErrorString, + "Error: Could not restart server." + "Please restart the server %s from the Services Program Item " + "in the Control Panel", ds_get_server_name()); + ds_send_error(ErrorString, 0); + return(DS_SERVER_UNKNOWN); + } + if (StopNetscapeService() != DS_SERVER_DOWN) + return(DS_SERVER_UNKNOWN); + + return(StartNetscapeService()); + } else { + if (StopNetscapeProgram() != DS_SERVER_DOWN) + return(DS_SERVER_UNKNOWN); + return(StartNetscapeProgram()); + } + +} + +int +StopServer() +{ + CHAR ErrorString[512]; + BOOLEAN Service; + + /* First figure out if the server is a service or an exe */ + Service = IsService(); + + if(Service) { + if (!(schSCManager = OpenSCManager( + NULL, // machine (NULL == local) + NULL, // database (NULL == default) + SC_MANAGER_ALL_ACCESS // access required + ))) { + sprintf(ErrorString, + "Error: Could not open the ServiceControlManager:%d " + "Please restart the server %s from the Services Program Item " + "in the Control Panel", ds_get_server_name(), GetLastError()); + ds_send_error(ErrorString, 0); + return(DS_SERVER_UNKNOWN); + } + return(StopNetscapeService()); + } else { + return(StopNetscapeProgram()); + } +} + +int +StartNetscapeProgram() +{ + char line[BIG_LINE], cmd[BIG_LINE]; + char *tmp = ds_get_install_root(); + + CHAR ErrorString[512]; + STARTUPINFO siStartInfo; + PROCESS_INFORMATION piProcInfo; + FILE *CmdFile; + + ZeroMemory(line, BIG_LINE); + + sprintf(line, "%s\\startsrv.bat", tmp); + + CmdFile = fopen(line, "r"); + if (!CmdFile) + { + sprintf(ErrorString, "Error:Tried to start Netscape server %s " + ": Could not open the startup script %s :Error %d. Please " + "run startsrv.bat from the server's root directory.", + ds_get_server_name(), line, errno); + ds_send_error(ErrorString, 0); + return(DS_SERVER_DOWN); + } + + ZeroMemory(cmd, BIG_LINE); + if (!fread(cmd, 1, BIG_LINE, CmdFile)) + { + sprintf(ErrorString, "Error:Tried to start Netscape server %s " + ": Could not read the startup script %s :Error %d. Please " + "run startsrv.bat from the server's root directory.", + ds_get_server_name(), line, errno); + ds_send_error(ErrorString, 0); + return(DS_SERVER_DOWN); + } + + ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.lpReserved = siStartInfo.lpReserved2 = NULL; + siStartInfo.cbReserved2 = 0; + siStartInfo.lpDesktop = NULL; + + if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, + 0, NULL, NULL, &siStartInfo, &piProcInfo)) + { + sprintf(ErrorString, "Error:Tried to start Netscape server %s " + ": Could not start up the startup script %s :Error %d. Please " + "run startsrv.bat from the server's root directory.", + ds_get_server_name(), line, GetLastError()); + ds_send_error(ErrorString, 0); + return(DS_SERVER_DOWN); + } + + CloseHandle(piProcInfo.hProcess); + CloseHandle(piProcInfo.hThread); + return(DS_SERVER_UP); +} + +int +StopNetscapeProgram() +{ + HANDLE hEvent; + CHAR ErrorString[512]; + char *servid = ds_get_server_name(); + + hEvent = CreateEvent(NULL, TRUE, FALSE, servid); + if(!SetEvent(hEvent)) + { + sprintf(ErrorString, "Tried to stop existing Netscape server %s" + ": Could not signal it to stop :Error %d", + servid, GetLastError()); + ds_send_error(ErrorString, 0); + return(DS_SERVER_UNKNOWN); + } + + return(DS_SERVER_DOWN); +} + +int +StopNetscapeService() +{ + BOOL ret; + SERVICE_STATUS ServiceStatus; + DWORD Error; + CHAR ErrorString[512]; + char *serviceName = ds_get_server_name(); + + schService = OpenService(schSCManager, serviceName, SERVICE_ALL_ACCESS); + + if (schService == NULL) + { + PR_snprintf(ErrorString, 512, "Tried to open Netscape service" + " %s: Error %d (%s). Please" + " stop the server from the Services Item in the Control Panel", + serviceName, GetLastError(), ds_system_errmsg()); + ds_send_error(ErrorString, 0); + return(DS_SERVER_UP); + } + + ret = ControlService(schService, SERVICE_CONTROL_STOP, &ServiceStatus); + Error = GetLastError(); + /* if ControlService returns with ERROR_SERVICE_CANNOT_ACCEPT_CTRL and + the server status indicates that it is either shutdown or in the process + of shutting down, then just wait for it to stop as usual */ + if (ret || + ((Error == ERROR_SERVICE_CANNOT_ACCEPT_CTRL) && + ((ServiceStatus.dwCurrentState == SERVICE_STOPPED) || + (ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING)))) + { + CloseServiceHandle(schService); + /* We make sure that the service is stopped */ + WaitForServertoStop(); + return(DS_SERVER_DOWN); + } + else if (Error != ERROR_SERVICE_NOT_ACTIVE) + { + PR_snprintf(ErrorString, 512, "Tried to stop Netscape service" + " %s: Error %d (%s)." + " Please stop the server from the Services Item in the" + " Control Panel", serviceName, Error, ds_system_errmsg()); + ds_send_error(ErrorString, 0); + return(DS_SERVER_UNKNOWN); + } + return(DS_SERVER_DOWN); +} + + +int +StartNetscapeService() +{ + CHAR ErrorString[512]; + int retries = 0; + char *serviceName = ds_get_server_name(); + + schService = OpenService( + schSCManager, // SCManager database + serviceName, // name of service + SERVICE_ALL_ACCESS); + if (schService == NULL) + { + CloseServiceHandle(schService); + sprintf(ErrorString, "Tried to start" + " the Netscape service %s: Error %d. Please" + " start the server from the Services Item in the Control Panel", + serviceName, GetLastError()); + ds_send_error(ErrorString, 0); + return(DS_SERVER_DOWN); + } + + if (!StartService(schService, 0, NULL)) + { + CloseServiceHandle(schService); + sprintf(ErrorString, "StartService:Could not start " + "the Directory service %s: Error %d. Please restart the server " + "from the Services Item in the Control Panel", + serviceName, GetLastError()); + ds_send_error(ErrorString, 0); + return(DS_SERVER_DOWN); + } + + CloseServiceHandle(schService); + return(DS_SERVER_UP); +} + +void +WaitForServertoStop() +{ + HANDLE hServDoneSemaphore; + int result,retries = 0; + char *serviceName = ds_get_server_name(); + char *newServiceName; + +RETRY: + + newServiceName = (PCHAR)malloc(strlen(serviceName) + 5); + sprintf(newServiceName, "NS_%s\0", serviceName); + + hServDoneSemaphore = CreateSemaphore( + NULL, // security attributes + 0, // initial count for semaphore + 1, // maximum count for semaphore + newServiceName); + + free(newServiceName); + + if ( hServDoneSemaphore == NULL) { + result = GetLastError(); + if (result == ERROR_INVALID_HANDLE) { + if (retries < SERVER_STOP_TIMEOUT) { + retries++; + Sleep(1000); + goto RETRY; + } + } else { + /* We aren't too interested in why the creation failed + * if it is not because of another instance */ + return; + } + } // hServDoneSemaphore == NULL + CloseHandle(hServDoneSemaphore); + return; +} +#endif diff --git a/ldap/admin/lib/dsalib_util.c b/ldap/admin/lib/dsalib_util.c new file mode 100644 index 00000000..a6cf4bee --- /dev/null +++ b/ldap/admin/lib/dsalib_util.c @@ -0,0 +1,1123 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#if defined( XP_WIN32 ) +#include <windows.h> +#include <io.h> +#else /* XP_WIN32 */ +# if defined( AIXV4 ) +# include <fcntl.h> +# else /* AIXV4 */ +# include <sys/fcntl.h> +# endif /* AIXV4 */ +#include <dirent.h> +#include <unistd.h> +#include <fcntl.h> +#endif /* XP_WIN3 */ +#include "dsalib.h" +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <ctype.h> +#include <nspr.h> + +#define COPY_BUFFER_SIZE 4096 +/* This is the separator string to use when outputting key/value pairs + to be read by the non-HTML front end (Java console) +*/ +static const char *SEPARATOR = ":"; /* from AdmTask.java */ + +#define LOGFILEENVVAR "DEBUG_LOGFILE" /* used for logfp */ + +static int internal_rm_rf(const char *path, DS_RM_RF_ERR_FUNC ds_rm_rf_err_func, void *arg); + +/* return a FILE * opened in append mode to the log file + caller must use fclose to close it +*/ +static FILE * +get_logfp(void) +{ + FILE *logfp = NULL; + char *logfile = getenv(LOGFILEENVVAR); + + if (logfile) { + logfp = fopen(logfile, "a"); + } + return logfp; +} + +DS_EXPORT_SYMBOL int +ds_file_exists(char *filename) +{ + struct stat finfo; + + if ( filename == NULL ) + return 0; + + if ( stat(filename, &finfo) == 0 ) /* successful */ + return 1; + else + return 0; +} + +DS_EXPORT_SYMBOL int +ds_mkdir(char *dir, int mode) +{ + if(!ds_file_exists(dir)) { +#ifdef XP_UNIX + if(mkdir(dir, mode) == -1) +#else /* XP_WIN32 */ + if(!CreateDirectory(dir, NULL)) +#endif /* XP_WIN32 */ + return -1; + } + return 0; +} + + +DS_EXPORT_SYMBOL char * +ds_mkdir_p(char *dir, int mode) +{ + static char errmsg[ERR_SIZE]; + struct stat fi; + char *t; + +#ifdef XP_UNIX + t = dir + 1; +#else /* XP_WIN32 */ + t = dir + 3; +#endif /* XP_WIN32 */ + + while(1) { + t = strchr(t, FILE_PATHSEP); + + if(t) *t = '\0'; + if(stat(dir, &fi) == -1) { + if(ds_mkdir(dir, mode) == -1) { + sprintf(errmsg, "mkdir %s failed (%s)", dir, ds_system_errmsg()); + return errmsg; + } + } + if(t) *t++ = FILE_PATHSEP; + else break; + } + return NULL; +} + + +/* + * Given the name of a directory, return a NULL-terminated array of + * the file names contained in that directory. Returns NULL if the directory + * does not exist or an error occurs, and returns an array with a + * single NULL string if the directory exists but is empty. The caller + * is responsible for freeing the returned array of strings. + * File names "." and ".." are not returned. + */ +#if !defined( XP_WIN32 ) +DS_EXPORT_SYMBOL char ** +ds_get_file_list( char *dir ) +{ + DIR *dirp; + struct dirent *direntp; + char **ret = NULL; + int nfiles = 0; + + if (( dirp = opendir( dir )) == NULL ) { + return NULL; + } + + if (( ret = malloc( sizeof( char * ))) == NULL ) { + return NULL; + }; + + while (( direntp = readdir( dirp )) != NULL ) { + if ( strcmp( direntp->d_name, "." ) && + strcmp( direntp->d_name, ".." )) { + if (( ret = (char **) realloc( ret, + sizeof( char * ) * ( nfiles + 2 ))) == NULL ); + ret[ nfiles ] = strdup( direntp->d_name ); + nfiles++; + } + } + (void) closedir( dirp ); + + ret[ nfiles ] = NULL; + return ret; +} +#else +DS_EXPORT_SYMBOL char ** +ds_get_file_list( char *dir ) +{ + char szWildcardFileSpec[MAX_PATH]; + char **ret = NULL; + long hFile; + struct _finddata_t fileinfo; + int nfiles = 0; + + if( ( dir == NULL ) || (strlen( dir ) == 0) ) + return NULL; + + if( ( ret = malloc( sizeof( char * ) ) ) == NULL ) + return NULL; + + strcpy(szWildcardFileSpec, dir); + strcat(szWildcardFileSpec, "/*"); + + hFile = _findfirst( szWildcardFileSpec, &fileinfo); + if( hFile == -1 ) + return NULL; + + if( ( strcmp( fileinfo.name, "." ) != 0 ) && + ( strcmp( fileinfo.name, ".." ) != 0 ) ) + { + ret[ nfiles++ ] = strdup( fileinfo.name ); + } + + while( _findnext( hFile, &fileinfo ) == 0 ) + { + if( ( strcmp( fileinfo.name, "." ) != 0 ) && + ( strcmp( fileinfo.name, ".." ) != 0 ) ) + { + if( ( ret = (char **) realloc( ret, sizeof( char * ) * ( nfiles + 2 ) ) ) != NULL ) + ret[ nfiles++ ] = strdup( fileinfo.name); + } + } + + _findclose( hFile ); + ret[ nfiles ] = NULL; + return ret; +} +#endif /* ( XP_WIN32 ) */ + + +DS_EXPORT_SYMBOL time_t +ds_get_mtime(char *filename) +{ + struct stat fi; + + if ( stat(filename, &fi) ) + return 0; + return fi.st_mtime; +} + +/* + * Copy files: return is + * 1: success + * 0: failure + * Print errors as needed. + */ +DS_EXPORT_SYMBOL int +ds_cp_file(char *sfile, char *dfile, int mode) +{ +#if defined( XP_WIN32 ) + return( CopyFile( sfile, dfile, FALSE ) ); /* Copy even if dfile exists */ +#else + int sfd, dfd, len; + struct stat fi; + char copy_buffer[COPY_BUFFER_SIZE]; + unsigned long read_len; + char error[BIG_LINE]; + +/* Make sure we're in the right umask */ + umask(022); + + if( (sfd = open(sfile, O_RDONLY)) == -1) { + sprintf(error, "Can't open file %s for reading.", sfile); + ds_send_error(error, 1); + return(0); + } + + fstat(sfd, &fi); + if (!(S_ISREG(fi.st_mode))) { + sprintf(error, "File %s is not a regular file.", sfile); + ds_send_error(error, 1); + close(sfd); + return(0); + } + len = fi.st_size; + + if( (dfd = open(dfile, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1) { + sprintf(error, "can't write to file %s", dfile); + ds_send_error(error, 1); + close(sfd); + return(0); + } + while (len) { + read_len = len>COPY_BUFFER_SIZE?COPY_BUFFER_SIZE:len; + + if ( (read_len = read(sfd, copy_buffer, read_len)) == -1) { + sprintf(error, "Error reading file %s for copy.", sfile); + ds_send_error(error, 1); + close(sfd); + close(dfd); + return(0); + } + + if ( write(dfd, copy_buffer, read_len) != read_len) { + sprintf(error, "Error writing file %s for copy.", dfile); + ds_send_error(error, 1); + close(sfd); + close(dfd); + return(0); + } + + len -= read_len; + } + close(sfd); + close(dfd); + return(1); +#endif +} + +/* Returns a directory path used for tmp files. */ +DS_EXPORT_SYMBOL char * +ds_get_tmp_dir() +{ + static char tmpdir[] = "/tmp"; + static char tmp[256] = {0}; + unsigned ilen; + char pch; + char* instanceDir = ds_get_install_root(); + + if(instanceDir == NULL) + { + #if defined( XP_WIN32 ) + ilen = strlen(tmp); + GetTempPath( ilen +1, tmp ); + /* Remove trailing slash. */ + pch = tmp[ilen-1]; + if( pch == '\\' || pch == '/' ) + tmp[ilen-1] = '\0'; + return tmp; + #else + return( tmpdir ); + #endif + } + + sprintf(tmp,"%s/tmp",instanceDir); + +#if defined( XP_WIN32 ) + for(ilen=0;ilen < strlen(tmp); ilen++) + { + if(tmp[ilen]=='/') + tmp[ilen]='\\'; + } +#endif + + if(!ds_file_exists(tmp)) + ds_mkdir_p(tmp,00770); + + return ( tmp ); +} + +DS_EXPORT_SYMBOL void +ds_unixtodospath(char *szText) +{ + if(szText) + { + while(*szText) + { + if( *szText == '/' ) + *szText = '\\'; + szText++; + } + } +} + +/* converts '\' chars to '/' */ +DS_EXPORT_SYMBOL void +ds_dostounixpath(char *szText) +{ + if(szText) + { + while(*szText) + { + if( *szText == '\\' ) + *szText = '/'; + szText++; + } + } +} + +/* converts ':' chars to ' ' */ +DS_EXPORT_SYMBOL void +ds_timetofname(char *szText) +{ + if(szText) + { + /* Replace trailing newline */ + szText[ strlen( szText ) -1 ] = 0; + while(*szText) + { + if( *szText == ':' || + *szText == ' ' ) + *szText = '_'; + szText++; + } + } +} + +/* Effects a rename in 2 steps, needed on NT because if the +target of a rename() already exists, the rename() will fail. */ +DS_EXPORT_SYMBOL int +ds_saferename(char *szSrc, char *szTarget) +{ +#ifdef XP_WIN32 + int iRetVal; + char *szTmpFile; + struct stat buf; +#endif + + if( !szSrc || !szTarget ) + return 1; + +#if defined( XP_WIN32 ) + + szTmpFile = mktemp("slrnXXXXXX" ); + if( stat( szTarget, &buf ) == 0 ) + { + /* Target file exists */ + if( !szTmpFile ) + return 1; + + if( !ds_cp_file( szTarget, szTmpFile, 0644) ) + return( 1 ); + + unlink( szTarget ); + if( (iRetVal = rename( szSrc, szTarget )) != 0 ) + { + /* Failed to rename, copy back. */ + ds_cp_file( szTmpFile, szTarget, 0644); + } + /* Now remove temp file */ + unlink( szTmpFile ); + } + else + iRetVal = rename(szSrc, szTarget); + + return iRetVal; +#else + return rename(szSrc, szTarget); +#endif + +} + +DS_EXPORT_SYMBOL char* +ds_encode_all (const char* s) +{ + char* r; + size_t l; + size_t i; + if (s == NULL || *s == '\0') { + return strdup (""); + } + l = strlen (s); + r = malloc (l * 3 + 1); + for (i = 0; *s != '\0'; ++s) { + r[i++] = '%'; + sprintf (r + i, "%.2X", 0xFF & (unsigned int)*s); + i += 2; + } + r[i] = '\0'; + return r; +} + +DS_EXPORT_SYMBOL char* +ds_URL_encode (const char* s) +{ + char* r; + size_t l; + size_t i; + if (s == NULL || *s == '\0') { + return strdup (""); + } + l = strlen (s) + 1; + r = malloc (l); + for (i = 0; *s != '\0'; ++s) { + if (*s >= 0x20 && *s <= 0x7E && strchr (" <>\"#%{}[]|\\^~`?,;=+\n", *s) == NULL) { + if (l - i <= 1) r = realloc (r, l *= 2); + r[i++] = *s; + } else { /* encode *s */ + if (l - i <= 3) r = realloc (r, l *= 2); + r[i++] = '%'; + sprintf (r + i, "%.2X", 0xFF & (unsigned int)*s); + i += 2; + } + } + r[i] = '\0'; + return r; +} + +DS_EXPORT_SYMBOL char* +ds_URL_decode (const char* original) +{ + char* r = strdup (original); + char* s; + for (s = r; *s != '\0'; ++s) { + if (*s == '+') { + *s = ' '; + } + else if (*s == '%' && isxdigit(s[1]) && isxdigit(s[2])) { + memmove (s, s+1, 2); + s[2] = '\0'; + *s = (char)strtoul (s, NULL, 16); + memmove (s+1, s+3, strlen (s+3) + 1); + } + } + return r; +} + +#if !defined( XP_WIN32 ) +#include <errno.h> /* errno */ +#include <pwd.h> /* getpwnam */ + +static int saved_uid_valid = 0; +static uid_t saved_uid; +static int saved_gid_valid = 0; +static gid_t saved_gid; + +#if defined( HPUX ) +#define SETEUID(id) setresuid((uid_t) -1, id, (uid_t) -1) +#else +#define SETEUID(id) seteuid(id) +#endif + +#endif + +DS_EXPORT_SYMBOL char* +ds_become_localuser_name (char *localuser) +{ +#if !defined( XP_WIN32 ) + if (localuser != NULL) { + struct passwd* pw = getpwnam (localuser); + if (pw == NULL) { + fprintf (stderr, "getpwnam(%s) == NULL; errno %d", + localuser, errno); + fprintf (stderr, "\n"); + fflush (stderr); + } else { + if ( ! saved_uid_valid) saved_uid = geteuid(); + if ( ! saved_gid_valid) saved_gid = getegid(); + if (setgid (pw->pw_gid) == 0) { + saved_gid_valid = 1; + } else { + fprintf (stderr, "setgid(%li) != 0; errno %d", + (long)pw->pw_gid, errno); + fprintf (stderr, "\n"); + fflush (stderr); + } + if (SETEUID (pw->pw_uid) == 0) { + saved_uid_valid = 1; + } else { + fprintf (stderr, "seteuid(%li) != 0; errno %d", + (long)pw->pw_uid, errno); + fprintf (stderr, "\n"); + fflush (stderr); + } + } + } + return NULL; +#else + return NULL; +#endif +} + +DS_EXPORT_SYMBOL char* +ds_become_localuser (char **ds_config) +{ +#if !defined( XP_WIN32 ) + char* localuser = ds_get_value (ds_config, ds_get_var_name(DS_LOCALUSER), 0, 1); + if (localuser != NULL) { + char *rv = ds_become_localuser_name(localuser); + + free(localuser); + return rv; + } + return NULL; +#else + return NULL; +#endif +} + +DS_EXPORT_SYMBOL char* +ds_become_original (char **ds_config) +{ +#if !defined( XP_WIN32 ) + if (saved_uid_valid) { + if (SETEUID (saved_uid) == 0) { + saved_uid_valid = 0; + } else { + fprintf (stderr, "seteuid(%li) != 0; errno %d<br>n", + (long)saved_uid, errno); + fflush (stderr); + } + } + if (saved_gid_valid) { + if (setgid (saved_gid) == 0) { + saved_gid_valid = 0; + } else { + fprintf (stderr, "setgid(%li) != 0; errno %d<br>\n", + (long)saved_gid, errno); + fflush (stderr); + } + } + return NULL; +#else + return NULL; +#endif +} + +/* + * When a path containing a long filename is passed to system(), the call + * fails. Therfore, we need to use the short version of the path, when + * constructing the path to pass to system(). + */ +DS_EXPORT_SYMBOL char* +ds_makeshort( char * filepath ) +{ +#if defined( XP_WIN32 ) + char *shortpath = malloc( MAX_PATH ); + DWORD dwStatus; + if( shortpath ) + { + dwStatus = GetShortPathName( filepath, shortpath, MAX_PATH ); + return( shortpath ); + } +#endif + return filepath; +} + +/* returns 1 if string "searchstring" found in file "filename" */ +DS_EXPORT_SYMBOL int +ds_search_file(char *filename, char *searchstring) +{ + struct stat finfo; + FILE * sf; + char big_line[BIG_LINE]; + + if( filename == NULL ) + return 0; + + if( stat(filename, &finfo) != 0 ) /* successful */ + return 0; + + if( !(sf = fopen(filename, "r")) ) + return 0; + + while ( fgets(big_line, BIG_LINE, sf) ) { + if( strstr( big_line, searchstring ) != NULL ) { + fclose(sf); + return 1; + } + } + + fclose(sf); + + return 0; +} + +/* + * on linux when running as root, doing something like + * system("date > out.log 2>&1") will fail, because of an + * ambigious redirect. This works for /bin/sh, but not /bin/csh or /bin/tcsh + * + * using this would turn + * system("date > out.log 2>&1"); + * into + * system("/bin/sh/ -c \"date > out.log 2>&1\"") + * + */ +DS_EXPORT_SYMBOL void +alter_startup_line(char *startup_line) +{ +#if (defined Linux && !defined LINUX2_4) + char temp_startup_line[BIG_LINE+40]; + + sprintf(temp_startup_line, "/bin/sh -c \"%s\"", startup_line); + strcpy(startup_line, temp_startup_line); +#else + /* do nothing */ +#endif /* Linux */ +} + +DS_EXPORT_SYMBOL void +ds_send_error(char *errstr, int print_errno) +{ + FILE *logfp; + fprintf(stdout, "error%s%s\n", SEPARATOR, errstr); + if (print_errno && errno) + fprintf(stdout, "system_errno%s%d\n", SEPARATOR, errno); + + fflush(stdout); + + if (logfp = get_logfp()) { + fprintf(logfp, "error%s%s\n", SEPARATOR, errstr); + if (print_errno && errno) + fprintf(logfp, "system_errno%s%d\n", SEPARATOR, errno); + fclose(logfp); + } + +} + +DS_EXPORT_SYMBOL void +ds_send_status(char *str) +{ + FILE *logfp; + fprintf(stdout, "[%s]: %s\n", ds_get_server_name(), str); + fflush(stdout); + + if (logfp = get_logfp()) { + fprintf(logfp, "[%s]: %s\n", ds_get_server_name(), str); + fclose(logfp); + } +} + +/* type and doexit are unused + I'm not sure what type is supposed to be used for + removed the doexit code because we don't want to + exit abruptly anymore, we must exit by returning an + exit code from the return in main() +*/ +static void +report_error(int type, char *msg, char *details, int doexit) +{ + char error[BIG_LINE*4] = {0}; + + if (msg) + { + strcat(error, msg); + strcat(error, SEPARATOR); + } + if (details) + strcat(error, details); + ds_send_error(error, 1); +} + +DS_EXPORT_SYMBOL void +ds_report_error(int type, char *msg, char *details) +{ + /* richm - changed exit flag to 0 - we must not exit + abruptly, we should instead exit by returning a code + as the return value of main - this ensures that callers + are properly notified of the status + */ + report_error(type, msg, details, 0); +} + +DS_EXPORT_SYMBOL void +ds_report_warning(int type, char *msg, char *details) +{ + report_error(type, msg, details, 0); +} + +DS_EXPORT_SYMBOL void +ds_show_message(const char *message) +{ + FILE *logfp; + printf("%s\n", message); + fflush(stdout); + + if (logfp = get_logfp()) { + fprintf(logfp, "%s\n", message); + fclose(logfp); + } + + return; +} + +DS_EXPORT_SYMBOL void +ds_show_key_value(char *key, char *value) +{ + FILE *logfp; + printf("%s%s%s\n", key, SEPARATOR, value); + + if (logfp = get_logfp()) { + fprintf(logfp, "%s%s%s\n", key, SEPARATOR, value); + fclose(logfp); + } + return; +} + +/* Stolen from the Admin Server dsgw_escape_for_shell */ +DS_EXPORT_SYMBOL char * +ds_escape_for_shell( char *s ) +{ + char *escaped; + char tmpbuf[4]; + size_t x,l; + + if ( s == NULL ) { + return( s ); + } + + l = 3 * strlen( s ) + 1; + escaped = malloc( l ); + memset( escaped, 0, l ); + for ( x = 0; s[x]; x++ ) { + if (( (unsigned char)s[x] & 0x80 ) == 0 ) { + strncat( escaped, &s[x], 1 ); + } else { + /* not an ASCII character - escape it */ + sprintf( tmpbuf, "\\%x", (unsigned)(((unsigned char)(s[x])) & 0xff) ); + strcat( escaped, tmpbuf ); + } + } + return( escaped ); +} + +DS_EXPORT_SYMBOL char * +ds_system_errmsg(void) +{ + static char static_error[BUFSIZ]; + char *lmsg = 0; /* Local message pointer */ + size_t msglen = 0; + int sys_error = 0; +#ifdef XP_WIN32 + LPTSTR sysmsg = 0; +#endif + + /* Grab the OS error message */ +#ifdef XP_WIN32 + sys_error = GetLastError(); +#else + sys_error = errno; +#endif + +#if defined(XP_WIN32) + msglen = FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + GetLastError(), + LOCALE_SYSTEM_DEFAULT, + (LPTSTR)&sysmsg, + 0, + 0); + if (msglen > 0) + lmsg = sysmsg; + SetLastError(0); +#else + lmsg = strerror(errno); + errno = 0; +#endif + + if (!lmsg) + static_error[0] = 0; + else + { + /* At this point lmsg points to something. */ + int min = 0; + msglen = strlen(lmsg); + + min = msglen > BUFSIZ ? BUFSIZ : msglen; + strncpy(static_error, lmsg, min); + static_error[min-1] = 0; + } + +#ifdef XP_WIN32 + /* NT's FormatMessage() dynamically allocated the msg; free it */ + if (sysmsg) + LocalFree(sysmsg); +#endif + + return static_error; +} + +/* get db path dir info from dse.ldif and remove it if it's not under path +*/ +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +enum { + DB_DIRECTORY = 0, + DB_LOGDIRECTORY, + DB_CHANGELOGDIRECTORY, + DB_HOME_DIRECTORY +}; + +static int +is_fullpath(char *path) +{ + int len; + if (NULL == path || '\0' == *path) + return 0; + + if (FILE_PATHSEP == *path) /* UNIX */ + return 1; + + len = strlen(path); + if (len > 2) + { + if (':' == path[1] && ('/' == path[2] || '\\' == path[2])) /* Windows */ + return 1; + } + return 0; +} + +static void +rm_db_dirs(char *fullpath, DS_RM_RF_ERR_FUNC ds_rm_rf_err_func, void *arg) +{ + FILE *fp = fopen(fullpath, "r"); + char buf[2][MAXPATHLEN]; + char rmbuf[MAXPATHLEN]; + char *bufp, *nextbufp; + char *retp; + int readit = 0; + + if (fp == NULL) + { + ds_rm_rf_err_func(fullpath, "opening dse.ldif", arg); + return; + } + + bufp = buf[0]; *bufp = '\0'; + nextbufp = buf[1]; *nextbufp = '\0'; + + while (readit || (retp = fgets(bufp, MAXPATHLEN, fp)) != NULL) + { + int len = strlen(bufp); + int type = -1; + char *p, *q; + + if (strstr(bufp, "nsslapd-directory")) + type = DB_DIRECTORY; + else if (strstr(bufp, "nsslapd-db-home-directory")) + type = DB_HOME_DIRECTORY; + else if (strstr(bufp, "nsslapd-db-logdirectory")) + type = DB_LOGDIRECTORY; + else if (strstr(bufp, "nsslapd-changelogdir")) + type = DB_CHANGELOGDIRECTORY; + else + { + readit = 0; + continue; + } + + p = bufp + len; + + while ((retp = fgets(nextbufp, MAXPATHLEN, fp)) != NULL) + { + int thislen; + if (*nextbufp == ' ') + { + thislen = strlen(nextbufp); + len += thislen; + if (len < MAXPATHLEN) + { + strncpy(p, nextbufp, thislen); + p += thislen; + } + /* else too long as a path. ignore it */ + } + else + break; + } + if (retp == NULL) /* done */ + break; + + p = strchr(bufp, ':'); + if (p == NULL) + { + char *tmpp = bufp; + bufp = nextbufp; + nextbufp = tmpp; + readit = 1; + continue; + } + + while (*(++p) == ' ') ; + + q = p + strlen(p) - 1; + while (*q == ' ' || *q == '\t' || *q == '\n') + q--; + *(q+1) = '\0'; + + switch (type) + { + case DB_DIRECTORY: + case DB_LOGDIRECTORY: + case DB_CHANGELOGDIRECTORY: + if (is_fullpath(p)) + internal_rm_rf(p, ds_rm_rf_err_func, NULL); + break; + case DB_HOME_DIRECTORY: + internal_rm_rf(p, ds_rm_rf_err_func, NULL); + break; + } + } + + fclose(fp); +} + +/* this function will recursively remove a directory hierarchy from the file + system, like "rm -rf" + In order to handle errors, the user supplies a callback function. When an + error occurs, the callback function is called with the file or directory name + and the system errno. The callback function should return TRUE if it wants + to continue or FALSE if it wants the remove aborted. + The error callback should use PR_GetError and/or PR_GetOSError to + determine the cause of the failure +*/ +/* you could locate db dirs non standard location + we should remove them, as well. +*/ +static int +internal_rm_rf(const char *path, DS_RM_RF_ERR_FUNC ds_rm_rf_err_func, void *arg) +{ + struct PRFileInfo prfi; + char *fullpath = NULL; + int retval = 0; + + if (PR_GetFileInfo(path, &prfi) != PR_SUCCESS) { + if (!ds_rm_rf_err_func(path, "reading directory", arg)) { + return 1; + } + } + + if (prfi.type == PR_FILE_DIRECTORY) + { + PRDir *dir; + PRDirEntry *dirent; + + if (!(dir = PR_OpenDir(path))) { + if (!ds_rm_rf_err_func(path, "opening directory", arg)) { + return 1; + } + return 0; + } + + while (dirent = PR_ReadDir(dir, PR_SKIP_BOTH)) { + char *fullpath = PR_smprintf("%s%c%s", path, FILE_PATHSEP, dirent->name); + if (PR_GetFileInfo(fullpath, &prfi) != PR_SUCCESS) { + if (!ds_rm_rf_err_func(fullpath, "reading file", arg)) { + PR_smprintf_free(fullpath); + PR_CloseDir(dir); + return 1; + } /* else just continue */ + } else if (prfi.type == PR_FILE_DIRECTORY) { + retval = internal_rm_rf(fullpath, ds_rm_rf_err_func, arg); + if (retval) { /* non zero return means stop */ + PR_smprintf_free(fullpath); + break; + } + } else { + /* if dse.ldif, check db dir is under the instance dir or not */ + if (0 == strcmp(dirent->name, "dse.ldif")) + rm_db_dirs(fullpath, ds_rm_rf_err_func, arg); + + if (PR_Delete(fullpath) != PR_SUCCESS) { + if (!ds_rm_rf_err_func(fullpath, "deleting file", arg)) { + PR_smprintf_free(fullpath); + PR_CloseDir(dir); + return 1; + } + } + } + PR_smprintf_free(fullpath); + } + PR_CloseDir(dir); + if (PR_RmDir(path) != PR_SUCCESS) { + if (!ds_rm_rf_err_func(path, "removing directory", arg)) { + retval = 1; + } + } + } + + return retval; +} + +static int +default_err_func(const char *path, const char *op, void *arg) +{ + PRInt32 errcode = PR_GetError(); + char *msg; + const char *errtext; + + if (!errcode || (errcode == PR_UNKNOWN_ERROR)) { + errcode = PR_GetOSError(); + errtext = ds_system_errmsg(); + } else { + errtext = PR_ErrorToString(errcode, PR_LANGUAGE_I_DEFAULT); + } + + msg = PR_smprintf("%s %s: error code %d (%s)", op, path, errcode, errtext); + ds_send_error(msg, 0); + PR_smprintf_free(msg); + return 1; /* just continue */ +} + +DS_EXPORT_SYMBOL int +ds_rm_rf(const char *dir, DS_RM_RF_ERR_FUNC ds_rm_rf_err_func, void *arg) +{ + int retval = 0; + struct PRFileInfo prfi; + + if (!dir) { + ds_send_error("Could not remove NULL directory name", 1); + return 1; + } + + if (!ds_rm_rf_err_func) { + ds_rm_rf_err_func = default_err_func; + } + + if (PR_GetFileInfo(dir, &prfi) != PR_SUCCESS) { + if (ds_rm_rf_err_func(dir, "reading directory", arg)) { + return 0; + } else { + return 1; + } + } + if (prfi.type != PR_FILE_DIRECTORY) { + char *msg = PR_smprintf("Cannot remove directory %s because it is not a directory", dir); + ds_send_error(msg, 0); + PR_smprintf_free(msg); + return 1; + } + + return internal_rm_rf(dir, ds_rm_rf_err_func, arg); +} + +DS_EXPORT_SYMBOL int +ds_remove_reg_key(void *base, const char *format, ...) +{ + int rc = 0; +#ifdef XP_WIN32 + int retries = 3; + HKEY hkey = (HKEY)base; + char *key; + va_list ap; + + va_start(ap, format); + key = PR_vsmprintf(format, ap); + va_end(ap); + + do { + if (ERROR_SUCCESS != RegDeleteKey(hkey, key)) { + rc = GetLastError(); + if (rc == ERROR_BADKEY || rc == ERROR_CANTOPEN || + rc == ERROR_CANTREAD || + rc == ERROR_CANTWRITE || rc == ERROR_KEY_DELETED || + rc == ERROR_ALREADY_EXISTS || rc == ERROR_NO_MORE_FILES) { + rc = 0; /* key already deleted - no error */ + } else if ((retries > 1) && (rc == ERROR_IO_PENDING)) { + /* the key is busy - lets wait and try again */ + PR_Sleep(PR_SecondsToInterval(3)); + retries--; + } else { + char *errmsg = PR_smprintf("Could not remove registry key %s - error %d (%s)", + key, rc, ds_system_errmsg()); + ds_send_error(errmsg, 0); + PR_smprintf_free(errmsg); + break; /* no retry, just fail */ + } + } + } while (rc && retries); + PR_smprintf_free(key); +#endif + return rc; +} |