diff options
Diffstat (limited to 'ldap/admin')
111 files changed, 52973 insertions, 0 deletions
diff --git a/ldap/admin/Makefile b/ldap/admin/Makefile new file mode 100644 index 00000000..99b1653b --- /dev/null +++ b/ldap/admin/Makefile @@ -0,0 +1,33 @@ +# +# 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 components +# + +MCOM_ROOT = ../../.. +LDAP_SRC = ../ + +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) + +include $(MCOM_ROOT)/ldapserver/nsdefs.mk +include $(MCOM_ROOT)/ldapserver/nsconfig.mk +include $(LDAP_SRC)/nsldap.mk + +all: + cd include; $(MAKE) $(MFLAGS) all + cd lib; $(MAKE) $(MFLAGS) all + cd src; $(MAKE) $(MFLAGS) all + +veryclean: clean + +clean: + cd include; $(MAKE) $(MFLAGS) clean + cd lib; $(MAKE) $(MFLAGS) clean + cd src; $(MAKE) $(MFLAGS) clean diff --git a/ldap/admin/include/Makefile b/ldap/admin/include/Makefile new file mode 100644 index 00000000..0b45ede0 --- /dev/null +++ b/ldap/admin/include/Makefile @@ -0,0 +1,39 @@ +# +# 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 include directory. +# + +MCOM_ROOT = ../../../.. +LDAP_SRC = ../.. + +NOSTDCLEAN=true # don't let nsconfig.mk define target clean + +include $(MCOM_ROOT)/ldapserver/nsdefs.mk +include $(MCOM_ROOT)/ldapserver/nsconfig.mk +include $(LDAP_SRC)/nsldap.mk + +HDRDEST=$(LDAP_ADMROOT)/include + +HEADERS=dsalib.h dsalib_pw.h +BINS=$(addprefix $(HDRDEST)/,$(HEADERS)) + +all: $(HDRDEST) $(BINS) + +$(HDRDEST): + $(MKDIR) $(HDRDEST) + +strip: +depend: + +clean: + -$(RM) $(BINS) + +$(HDRDEST)/%.h: %.h + -@$(RM) $@ + $(CP) $< $@ diff --git a/ldap/admin/include/dsalib.h b/ldap/admin/include/dsalib.h new file mode 100644 index 00000000..c00f6cb0 --- /dev/null +++ b/ldap/admin/include/dsalib.h @@ -0,0 +1,450 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +#ifndef __dsalib_h +#define __dsalib_h + +#include <stdio.h> +#include <time.h> +#include <stdarg.h> +#ifdef HPUX +#include <limits.h> /* for PATH_MAX */ +#endif + +/* error types */ +#define DS_FILE_ERROR 0 +#define DS_MEMORY_ERROR 1 +#define DS_SYSTEM_ERROR 2 +#define DS_INCORRECT_USAGE 3 +#define DS_ELEM_MISSING 4 +#define DS_REGISTRY_DATABASE_ERROR 5 +#define DS_NETWORK_ERROR 6 +#define DS_GENERAL_FAILURE 7 +#define DS_WARNING 8 + +/* The upper bound on error types */ +#define DS_MAX_ERROR 9 + +/* The default error type (in case something goes wrong */ +#define DS_DEFAULT_ERROR 3 + +#ifndef BIG_LINE +#define BIG_LINE 1024 +#endif +#ifndef PATH_MAX +#if defined( _WIN32 ) +#define PATH_MAX _MAX_PATH +#else +#define PATH_MAX 256 +#endif /* _WIN32 */ +#endif /* PATH_MAX */ +#ifndef HTML_ERRCOLOR +#define HTML_ERRCOLOR "#AA0000" +#endif +#ifndef CONTENT_NAME +#define CONTENT_NAME "content" +#endif + +#ifdef XP_UNIX + +#define FILE_PATHSEP '/' +#define FILE_PATHSEPP "/" +#define FILE_PARENT "../" +#define WSACleanup() + +#elif defined(XP_WIN32) + +#define FILE_PATHSEP '/' +#define FILE_PATHSEPP "\\\\" +#define FILE_PARENT "..\\" + +#endif /* XP_WIN32 */ + +#define PATH_SIZE 1024 +#define ERR_SIZE 8192 + +/* + NT doesn't strictly need these, but the libadmin API which is emulated + below uses them. + */ +#define NEWSCRIPT_MODE 0755 +#define NEWFILE_MODE 0644 +#define NEWDIR_MODE 0755 + +#if defined( XP_WIN32 ) +#define DS_EXPORT_SYMBOL __declspec( dllexport ) +#else +#define DS_EXPORT_SYMBOL +#endif + +#if defined( XP_WIN32 ) +#define ENQUOTE "\"" +#else +#define ENQUOTE "" +#endif + +#ifndef FILE_SEP +#ifdef XP_WIN32 + #define FILE_SEP '\\' +#else + #define FILE_SEP '/' +#endif +#endif + +#if defined( XP_WIN32 ) + #define PATH_FOR_PLATFORM(_path) ds_unixtodospath(_path) +#else + #define PATH_FOR_PLATFORM(_path) +#endif + +#define START_SCRIPT "start-slapd" +#define RESTART_SCRIPT "restart-slapd" +#define STOP_SCRIPT "stop-slapd" + +#if defined( XP_WIN32 ) +#define SLAPD_NAME "slapd" +#else +#define SLAPD_NAME "ns-slapd" +#endif + +#define MOCHA_NAME "JavaScript" + +/* + * Return values from ds_get_updown_status() + */ +#define DS_SERVER_UP 1 +#define DS_SERVER_DOWN 0 +#define DS_SERVER_UNKNOWN -1 +/* + * Return values from ds_bring_up_server() + */ +#define DS_SERVER_ALREADY_UP -2 +#define DS_SERVER_ALREADY_DOWN -3 +#define DS_SERVER_PORT_IN_USE -4 +#define DS_SERVER_MAX_SEMAPHORES -5 +#define DS_SERVER_CORRUPTED_DB -6 +#define DS_SERVER_NO_RESOURCES -7 +#define DS_SERVER_COULD_NOT_START -8 + +/* + * Other return values + */ +#define DS_UNKNOWN_ERROR -1 +#define DS_NO_SERVER_ROOT -10 +#define DS_CANNOT_EXEC -11 +#define DS_CANNOT_OPEN_STAT_FILE -12 +#define DS_NULL_PARAMETER -13 +#define DS_SERVER_MUST_BE_DOWN -14 +#define DS_CANNOT_OPEN_BACKUP_FILE -15 +#define DS_NOT_A_DIRECTORY -16 +#define DS_CANNOT_CREATE_DIRECTORY -17 +#define DS_CANNOT_OPEN_LDIF_FILE -18 +#define DS_IS_A_DIRECTORY -19 +#define DS_CANNOT_CREATE_FILE -20 +#define DS_UNDEFINED_VARIABLE -21 +#define DS_NO_SUCH_FILE -22 +#define DS_CANNOT_DELETE_FILE -23 +#define DS_UNKNOWN_SNMP_COMMAND -24 +#define DS_NON_NUMERIC_VALUE -25 +#define DS_NO_LOGFILE_NAME -26 +#define DS_CANNOT_OPEN_LOG_FILE -27 +#define DS_HAS_TOBE_READONLY_MODE -28 +#define DS_INVALID_LDIF_FILE -29 + +/* + * Types of config files. + */ +#define DS_REAL_CONFIG 1 +#define DS_TMP_CONFIG 2 + +/* + * Maximum numeric value we will accept in admin interface + * We may at some point need per-option bounds, but for now, + * there's just one global maximum. + */ +#define DS_MAX_NUMERIC_VALUE 4294967295 /* 2^32 - 1 */ + +/* Use our own macro for rpt_err, so we can put our own error code in + NMC_STATUS */ +#undef rpt_err +#define rpt_err(CODE, STR1, STR2, STR3) \ + fprintf( stdout, "NMC_ErrInfo: %s\n", (STR1) ); \ + fprintf( stdout, "NMC_STATUS: %d\n", CODE ) + +/* + * Flags for ds_display_config() + */ +#define DS_DISP_HRB 1 /* horizontal line to begin with */ +#define DS_DISP_HRE 2 /* horizontal line to end with */ +#define DS_DISP_TB 4 /* table begin */ +#define DS_DISP_TE 8 /* table end */ +#define DS_DISP_EOL 16 /* End Of Line */ +#define DS_DISP_NOMT 32 /* display only non empty */ +#define DS_DISP_NOIN 64 /* display with no input field */ +#define DS_DISP_HELP 128 /* display with a help button */ +#define DS_DISP_PLAIN 256 /* No table, no nothin */ +#define DS_SIMPLE (DS_DISP_EOL | DS_DISP_NOIN | DS_DISP_HELP) + +/* + * dci_type for ds_cfg_info + */ +#define DS_ATTR_STRING 1 +#define DS_ATTR_NUMBER 2 +#define DS_ATTR_ONOFF 3 +#define DS_ATTR_LIMIT 4 /* a number where -1 is displayed as blank */ + +struct ds_cfg_info { + char *dci_varname; + char *dci_display; + int dci_type; + char *dci_help; +}; + +extern struct ds_cfg_info ds_cfg_info[]; + +#define LDBM_DATA_SIZE 5 + +/*ldbm specific backend information*/ +struct ldbm_data { + char *tv[LDBM_DATA_SIZE][2]; /*type and value*/ +}; + + +/* + * varname for ds_showparam() + * NOTE: these must be kept in synch with the ds_cfg_info array defined + * in ../lib/dsalib_conf.c + */ +#define DS_LOGLEVEL 0 +#define DS_REFERRAL 1 +#define DS_AUDITFILE 2 +#define DS_LOCALHOST 3 +#define DS_PORT 4 +#define DS_SECURITY 5 +#define DS_SECURE_PORT 6 +#define DS_SSL3CIPHERS 7 +#define DS_PASSWDHASH 8 +#define DS_ACCESSLOG 9 +#define DS_ERRORLOG 10 +#define DS_ROOTDN 11 +#define DS_ROOTPW 12 +#define DS_SUFFIX 13 +#define DS_LOCALUSER 14 +#define DS_CFG_MAX 15 /* MUST be one greater than the last option */ + +/* These control how long we wait for the server to start up or shutdown */ +#define SERVER_START_TIMEOUT 600 /* seconds */ +#define SERVER_STOP_TIMEOUT SERVER_START_TIMEOUT /* same as start timeout */ + +typedef int (*DS_RM_RF_ERR_FUNC)(const char *path, const char *op, void *arg); + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +extern DS_EXPORT_SYMBOL char *ds_get_server_root(); +extern DS_EXPORT_SYMBOL char *ds_get_install_root(); +extern DS_EXPORT_SYMBOL char *ds_get_admserv_based_root(); +extern DS_EXPORT_SYMBOL void ds_log_debug_message(char *msg); +extern DS_EXPORT_SYMBOL void ds_log_env(char **envp); +extern DS_EXPORT_SYMBOL int ds_get_updown_status(); +extern DS_EXPORT_SYMBOL void ds_print_startstop(int stop); +extern DS_EXPORT_SYMBOL int ds_bring_up_server_install(int verbose, + char *root, char *errorlog); +extern DS_EXPORT_SYMBOL int ds_bring_up_server(int verbose); +extern DS_EXPORT_SYMBOL char *ds_get_server_name(); +extern DS_EXPORT_SYMBOL void ds_send_error(char *errstr, int print_errno); +extern DS_EXPORT_SYMBOL void ds_send_status(char *str); +extern DS_EXPORT_SYMBOL char *ds_get_cgi_var(char *cgi_var_name); +extern DS_EXPORT_SYMBOL char *ds_get_cgi_var_simple(int index); +extern DS_EXPORT_SYMBOL char *ds_get_cgi_multiple(char *cgi_var_name); +extern DS_EXPORT_SYMBOL char *ds_get_errors_name(); +extern DS_EXPORT_SYMBOL char *ds_get_access_name(); +extern DS_EXPORT_SYMBOL char *ds_get_audit_name(); +extern DS_EXPORT_SYMBOL char *ds_get_logfile_name(int config_type); + + +extern DS_EXPORT_SYMBOL int ds_bring_down_server(); +extern DS_EXPORT_SYMBOL void ds_print_server_status(int isrunning); +extern DS_EXPORT_SYMBOL int ds_get_file_size(char *fileName); +extern DS_EXPORT_SYMBOL void ds_display_tail(char *fileName, int timeOut, + int startSeek, char *doneMsg, char *lastLine); +extern DS_EXPORT_SYMBOL char **ds_get_ldif_files(); +extern DS_EXPORT_SYMBOL int ds_ldif2db_preserve(char *file); +extern DS_EXPORT_SYMBOL int ds_ldif2db(char *file); +extern DS_EXPORT_SYMBOL int ds_ldif2db_backend_subtree(char *file, char *backend, char *subtree); +extern DS_EXPORT_SYMBOL int ds_db2ldif(char *file); +extern DS_EXPORT_SYMBOL int ds_vlvindex(char **backendList, char **attrList); +extern DS_EXPORT_SYMBOL int ds_addindex(char **attrList, char *backendName); +extern DS_EXPORT_SYMBOL int ds_db2ldif_subtree(char *file, char *subtree); +extern DS_EXPORT_SYMBOL char **ds_get_bak_dirs(); +extern DS_EXPORT_SYMBOL int ds_db2bak(char *file); +extern DS_EXPORT_SYMBOL int ds_bak2db(char *file); +extern DS_EXPORT_SYMBOL int ds_get_monitor(int frontend, char *port); +extern DS_EXPORT_SYMBOL int ds_get_bemonitor(char *bemdn, char *port); +extern DS_EXPORT_SYMBOL int ds_client_access(char *port, char *dn); +extern DS_EXPORT_SYMBOL char **ds_get_config(int type); +extern DS_EXPORT_SYMBOL char *ds_get_pwenc(char *passwd_hash, char *password); +extern DS_EXPORT_SYMBOL int ds_check_config(int type); +extern DS_EXPORT_SYMBOL int ds_check_pw(char *pwhash, char *pwclear); +extern DS_EXPORT_SYMBOL int ds_set_config(char *change_file_name); +extern DS_EXPORT_SYMBOL char **ds_get_conf_from_file(FILE *conf); +extern DS_EXPORT_SYMBOL void ds_display_config(char **ds_config); +extern DS_EXPORT_SYMBOL char *ds_get_var_name(int varnum); +extern DS_EXPORT_SYMBOL int ds_showparam(char **ds_config, int varname, int phase, + int occurance, char *dispname, int size, int maxlength, unsigned flags, + char *url); +extern DS_EXPORT_SYMBOL void ds_show_pwmaxage(char *value); +extern DS_EXPORT_SYMBOL void ds_show_pwhash(char *value); +extern DS_EXPORT_SYMBOL char *ds_get_value(char **ds_config, char *parm, int phase, int occurance); +extern DS_EXPORT_SYMBOL void ds_apply_cfg_changes(int param_list[], int changed); +extern DS_EXPORT_SYMBOL int ds_commit_cfg_changes(); +extern DS_EXPORT_SYMBOL int ds_config_updated(); +extern DS_EXPORT_SYMBOL void ds_display_header(char *font_size, char *header); +extern DS_EXPORT_SYMBOL void ds_display_message(char *font_size, char *header); +extern DS_EXPORT_SYMBOL void ds_print_file_form(char *action, char *fileptr, char *full_fileptr); +extern DS_EXPORT_SYMBOL char *ds_get_file_meaning(char *file); +extern DS_EXPORT_SYMBOL void ds_print_file_name(char *fileptr); +extern DS_EXPORT_SYMBOL int ds_file_exists(char *filename); +extern DS_EXPORT_SYMBOL int ds_cp_file(char *sfile, char *dfile, int mode); +extern DS_EXPORT_SYMBOL time_t ds_get_mtime(char *filename); +extern DS_EXPORT_SYMBOL char *ds_get_config_value( int option ); +extern DS_EXPORT_SYMBOL char **ds_get_file_list( char *dir ); +extern DS_EXPORT_SYMBOL char *ds_get_tmp_dir(); +extern DS_EXPORT_SYMBOL void ds_unixtodospath(char *szText); +extern DS_EXPORT_SYMBOL void ds_timetofname(char *szText); +extern DS_EXPORT_SYMBOL void ds_dostounixpath(char *szText); +extern DS_EXPORT_SYMBOL int ds_saferename(char *szSrc, char *szTarget); +extern DS_EXPORT_SYMBOL char *get_specific_help_button(char *help_link, + char *dispname, char *helpinfo); + +/* Change the DN to a canonical format (in place); return DN. */ +extern DS_EXPORT_SYMBOL char* dn_normalize (char* DN); + +/* Change the DN to a canonical format (in place) and convert to v3; return DN. */ +extern DS_EXPORT_SYMBOL char* dn_normalize_convert (char* DN); + +/* if dn contains an unescaped quote return true */ +extern DS_EXPORT_SYMBOL int ds_dn_uses_LDAPv2_quoting(const char *dn); + +/* Return != 0 iff the DN equals or ends with the given suffix. + Both DN and suffix must be normalized, by dn_normalize(). */ +extern DS_EXPORT_SYMBOL int dn_issuffix (char* DN, char* suffix); + +/* Return a copy of the DN, but with optional whitespace inserted. */ +extern DS_EXPORT_SYMBOL char* ds_dn_expand (char* DN); + +/* Return the value if it can be stored 'as is' in a config file. + If it requires enquoting, allocate and return its enquoted form. + The caller should free() the returned pointer iff it's != value. + On Windows, we don't want to double up on "\" characters in filespecs, + so we need to pass in the value type */ +extern DS_EXPORT_SYMBOL char* ds_enquote_config_value (int paramnum, char* value); + +/* + * Bring up a javascript alert. + */ +extern DS_EXPORT_SYMBOL void ds_alert_user(char *header, char *message); + +/* Construct and return the DN that corresponds to the give DNS name. + The caller should free() the returned pointer. */ +extern DS_EXPORT_SYMBOL char* ds_DNS_to_DN (char* DNS); + +/* Construct and return the DN of the LDAP server's own entry. + The caller must NOT free() the returned pointer. */ +extern DS_EXPORT_SYMBOL char* ds_get_config_DN (char** ds_config); + +/* Encode characters, as described in RFC 1738 section 2.2, + if they're 'unsafe' (as defined in RFC 1738), or '?' or + <special> (as defined in RFC 1779). + The caller should free() the returned pointer. */ +extern DS_EXPORT_SYMBOL char* ds_URL_encode (const char*); + +/* Decode characters, as described in RFC 1738 section 2.2. + The caller should free() the returned pointer. */ +extern DS_EXPORT_SYMBOL char* ds_URL_decode (const char*); + +/* Encode all characters, even if 'safe' */ +extern DS_EXPORT_SYMBOL char* ds_encode_all (const char*); + +/* Change the effective UID and GID of this process to + those associated with the given localuser (if any). */ +extern DS_EXPORT_SYMBOL char* ds_become_localuser_name (char* localuser); + +/* Change the effective UID and GID of this process to + those associated with ds_config's localuser (if any). */ +extern DS_EXPORT_SYMBOL char* ds_become_localuser (char** ds_config); + +/* Change the effective UID and GID of this process back to + what they were before calling ds_become_localuser(). */ +extern DS_EXPORT_SYMBOL char* ds_become_original(); + +extern DS_EXPORT_SYMBOL char* ds_makeshort(char *filepath); + +extern DS_EXPORT_SYMBOL int ds_search_file(char *filename, char *searchstring); + +/* Begin parsing a POST in a CGI context */ +extern DS_EXPORT_SYMBOL int ds_post_begin(FILE *input); + +/* Begin parsing a GET in a CGI context */ +extern DS_EXPORT_SYMBOL void ds_get_begin(char *query_string); + +/* Display an error to the user and exit from a CGI */ +extern DS_EXPORT_SYMBOL void ds_report_error(int type, char *errmsg, char *details); + +/* Display a warning to the user */ +extern DS_EXPORT_SYMBOL void ds_report_warning(int type, char *errmsg, char *details); + +/* These functions are used by the program to alter the output behaviour +if not executing in a CGI context */ +extern DS_EXPORT_SYMBOL int ds_get_formatted_output(void); +extern DS_EXPORT_SYMBOL void ds_set_formatted_output(int val); + +/* return the value of a CGI variable */ +extern DS_EXPORT_SYMBOL char *ds_a_get_cgi_var(char *varname, char *elem_id, char *bongmsg); + +/* return a multi-valued CGI variable */ +extern DS_EXPORT_SYMBOL char **ds_a_get_cgi_multiple(char *varname, char *elem_id, char *bongmsg); + +/* open an html file */ +extern DS_EXPORT_SYMBOL FILE *ds_open_html_file(char *filename); + +/* show a message to be parsed by the non-HTML front end */ +extern DS_EXPORT_SYMBOL void ds_show_message(const char *message); + +/* show a key/value pair to be parsed by the non-HTML front end */ +extern DS_EXPORT_SYMBOL void ds_show_key_value(char *key, char *value); + +extern DS_EXPORT_SYMBOL void ds_submit(char *helptarget) ; +extern DS_EXPORT_SYMBOL char *ds_get_helpbutton(char *topic); + +extern DS_EXPORT_SYMBOL void alter_startup_line(char *startup_line); + +extern DS_EXPORT_SYMBOL int ds_dir_exists(char *fn); +extern DS_EXPORT_SYMBOL int ds_mkdir(char *dir, int mode); +extern DS_EXPORT_SYMBOL char *ds_mkdir_p(char *dir, int mode); +extern DS_EXPORT_SYMBOL char *ds_salted_sha1_pw_enc (char* pwd); +extern DS_EXPORT_SYMBOL char * ds_escape_for_shell( char *s ); + +extern DS_EXPORT_SYMBOL char **ds_string_to_vec(char *s); + +extern DS_EXPORT_SYMBOL char *ds_system_errmsg(void); + +extern DS_EXPORT_SYMBOL int ds_exec_and_report(char *cmd); + +/* remove a directory hierarchy - if the error function is given, it will be called upon + error (e.g. directory not readable, cannot remove file, etc.) - if the callback function + returns 0, this means to abort the removal, otherwise, continue +*/ +extern DS_EXPORT_SYMBOL int ds_rm_rf(const char *dir, DS_RM_RF_ERR_FUNC ds_rm_rf_err_func, void *arg); +/* + remove a registry key and report an error message if unsuccessful +*/ +extern DS_EXPORT_SYMBOL int ds_remove_reg_key(void *base, const char *format, ...); +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __dsalib_h */ diff --git a/ldap/admin/include/dsalib_pw.h b/ldap/admin/include/dsalib_pw.h new file mode 100644 index 00000000..78c22c11 --- /dev/null +++ b/ldap/admin/include/dsalib_pw.h @@ -0,0 +1,17 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +#ifndef __dsalib_pw_h +#define __dsalib_pw_h + +extern DS_EXPORT_SYMBOL void dsparm_help_button(char *var_name, char *dispname, + char *helpinfo); +extern DS_EXPORT_SYMBOL LDAP* bind_as_root (char** cfg, char* rootdn, + char* rootpw); +extern DS_EXPORT_SYMBOL void get_pw_policy(char*** pValue, char** cfg); +extern DS_EXPORT_SYMBOL void ds_showpw( char** cfg); + +#endif /* __dsalib_pw_h */ diff --git a/ldap/admin/include/dsalib_schema.h b/ldap/admin/include/dsalib_schema.h new file mode 100644 index 00000000..ff3488eb --- /dev/null +++ b/ldap/admin/include/dsalib_schema.h @@ -0,0 +1,255 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * Routines to parse schema LDIF + * + * -atom + * + */ + +#ifndef __DSALIB_SCHEMA_H +#define __DSALIB_SCHEMA_H__ + + + +/************************************************************************ + + BNF for attributes and objectclasses: + + AttributeTypeDescription = "(" whsp + numericoid whsp ; AttributeType identifier + [ "NAME" qdescrs ] ; name used in AttributeType + [ "DESC" qdstring ] ; description + [ "OBSOLETE" whsp ] + [ "SUP" woid ] ; derived from this other + ; AttributeType + [ "EQUALITY" woid ; Matching Rule name + [ "ORDERING" woid ; Matching Rule name + [ "SUBSTR" woid ] ; Matching Rule name + [ "SYNTAX" whsp noidlen whsp ] ; see section 4.3 + [ "SINGLE-VALUE" whsp ] ; default multi-valued + [ "COLLECTIVE" whsp ] ; default not collective + [ "NO-USER-MODIFICATION" whsp ]; default user modifiable + [ "USAGE" whsp AttributeUsage ]; default user applications + whsp ")" + + + + ObjectClassDescription = "(" whsp + numericoid whsp ; ObjectClass identifier + [ "NAME" qdescrs ] + [ "DESC" qdstring ] + [ "OBSOLETE" whsp ] + [ "SUP" oids ] ; Superior ObjectClasses + [ ( "ABSTRACT" / "STRUCTURAL" / "AUXILIARY" ) whsp ] + ; default structural + [ "MUST" oids ] ; AttributeTypes + [ "MAY" oids ] ; AttributeTypes + whsp ")" + + +************************************************************************/ + + +/* + * ds_check_valid_oid: check to see if an oid is valid. + * Oids should only contain digits and dots. + * + * returns 1 if valid, 0 if not + */ + +DS_EXPORT_SYMBOL int ds_check_valid_oid (char *oid); + + +/* + * ds_check_valid_name: check to see if an attribute name or an objectclass + * name is valid. A valid name contains only digits, letters, or hyphens + * + * returns 1 if valid, 0 if not + * + */ + +DS_EXPORT_SYMBOL int ds_check_valid_name (char *name); + +/* + * ds_get_oc_desc: + * + * Input : pointer to string containing an ObjectClassDescription + * Returns : pointer to string containing objectclass DESC + * + * The caller must free the return value + * + */ + +DS_EXPORT_SYMBOL char * ds_get_oc_desc (char *oc); + + +/* + * ds_get_oc_name: + * + * Input : pointer to string containing an ObjectClassDescription + * Returns: pointer to string containing objectclass name. + * + * The caller must free the return value + * + */ + +DS_EXPORT_SYMBOL char *ds_get_oc_name (char *o); + + +/* + * ds_get_attr_name: + * + * Input : pointer to string containing an AttributeTypeDescription + * Returns: pointer to string containing an attribute name. + * + * The caller must free the return value + * + */ + +DS_EXPORT_SYMBOL char *ds_get_attr_name (char *a); + + + +/* + * ds_get_oc_superior: + * + * Input : pointer to string containing an ObjectClassDescription + * Returns: pointer to string containing the objectclass's SUP (superior/parent) + * objectclass + * + * The caller must free the return value + * + */ + +DS_EXPORT_SYMBOL char *ds_get_oc_superior (char *o); + + +/* + * ds_get_attr_desc: + * + * Input : Pointer to string containing an AttributeTypeDescription + * Returns: Pointer to string containing the attribute's description + * + * The caller must free the return value + * + */ + +DS_EXPORT_SYMBOL char *ds_get_attr_desc (char *a); + + +/* + * ds_get_attr_syntax: + * + * Input: Pointer to string containing an AttributeTypeDescription + * Returns: Pointer to string containing the attribute's syntax + * + * The caller must free the return value + * + */ + +DS_EXPORT_SYMBOL char *ds_get_attr_syntax (char *a); + + +/* + * ds_get_attr_oid: + * + * Input : Pointer to string containing an AttributeTypeDescription + * Returns: Pointer to string containing an attribute's oid + * + * The caller must free the return value + * + */ +DS_EXPORT_SYMBOL char *ds_get_attr_oid (char *a); + + +/* + * ds_get_attr_name: + * + * Input : Pointer to string containing an AttributeTypeDescription + * Returns: Pointer to string containing the attribute's name + * + * The caller must free the return value + * + */ + +DS_EXPORT_SYMBOL char *ds_get_attr_name (char *a); + + + +/* + * syntax_oid_to_english: convert an attribute syntax oid to something more + * human readable + * + * Input : string containing numeric OID for a attribute syntax + * Returns: Human readable string + */ + + +DS_EXPORT_SYMBOL char *syntax_oid_to_english (char *oid); + + +/* StripSpaces: Remove all leading and trailing spaces from a string */ + +DS_EXPORT_SYMBOL char *StripSpaces (char **s); + + +/* ds_print_required_attrs: + * + * input: pointer to string containing an ObjectClassDescription + * + * prints JavaScript array containing the required attributes of an objectclass + * The array name is oc_<objectclass name>_requires + */ + +DS_EXPORT_SYMBOL void ds_print_required_attrs (char *o); + + +/* ds_print_allowed_attrs: + * + * input: pointer to string containing an ObjectClassDescription + * + * prints JavaScript array containing the allowed attributes of an objectclass + * The array name is oc_<objectclass name>_allows + */ +DS_EXPORT_SYMBOL void ds_print_allowed_attrs (char *o); + + +/* ds_print_oc_oid: + * + * input: pointer to string containing an ObjectClassDescription + * + * prints JavaScript string containing an objectclass oid + * The variable name is oc_<objectclass name>_oid + */ + +DS_EXPORT_SYMBOL void ds_print_oc_oid (char *o); + +/* ds_print_oc_superior: + * + * input: pointer to string containing an ObjectClassDescription + * + * prints JavaScript string containing an objectclass superior + * The variable name is oc_<objectclass name>_superior + */ + +DS_EXPORT_SYMBOL void ds_print_oc_superior (char *o); + + +/* underscore2hyphen: + * transform underscores to hyphens in a string + */ + +DS_EXPORT_SYMBOL char *underscore2hyphen (char *src); + +/* hyphen2underscore: + * transform hyphens to underscores in a string + */ + +DS_EXPORT_SYMBOL char *hyphen2underscore (char *src); + + +#endif /* __DSALIB_SCHEMA_H__ */ diff --git a/ldap/admin/include/nterrors.h b/ldap/admin/include/nterrors.h new file mode 100644 index 00000000..a15c9ea0 --- /dev/null +++ b/ldap/admin/include/nterrors.h @@ -0,0 +1,728 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* DO NOT EDIT THIS FILE - it is automatically generated */ + +struct _NtError { + int ErrorNumber; + char *ErrorString; + struct _NtError *next; +} ; + +typedef struct _NtError NtError; + +NtError NtErrorStrings[] = { +{ 0 , "ERROR_SUCCESS" }, +{ 0 , "NO_ERROR" }, +{ 1 , "ERROR_INVALID_FUNCTION" }, +{ 2 , "ERROR_FILE_NOT_FOUND" }, +{ 3 , "ERROR_PATH_NOT_FOUND" }, +{ 4 , "ERROR_TOO_MANY_OPEN_FILES" }, +{ 5 , "ERROR_ACCESS_DENIED" }, +{ 6 , "ERROR_INVALID_HANDLE" }, +{ 7 , "ERROR_ARENA_TRASHED" }, +{ 8 , "ERROR_NOT_ENOUGH_MEMORY" }, +{ 9 , "ERROR_INVALID_BLOCK" }, +{ 10 , "ERROR_BAD_ENVIRONMENT" }, +{ 11 , "ERROR_BAD_FORMAT" }, +{ 12 , "ERROR_INVALID_ACCESS" }, +{ 13 , "ERROR_INVALID_DATA" }, +{ 14 , "ERROR_OUTOFMEMORY" }, +{ 15 , "ERROR_INVALID_DRIVE" }, +{ 16 , "ERROR_CURRENT_DIRECTORY" }, +{ 17 , "ERROR_NOT_SAME_DEVICE" }, +{ 18 , "ERROR_NO_MORE_FILES" }, +{ 19 , "ERROR_WRITE_PROTECT" }, +{ 20 , "ERROR_BAD_UNIT" }, +{ 21 , "ERROR_NOT_READY" }, +{ 22 , "ERROR_BAD_COMMAND" }, +{ 23 , "ERROR_CRC" }, +{ 24 , "ERROR_BAD_LENGTH" }, +{ 25 , "ERROR_SEEK" }, +{ 26 , "ERROR_NOT_DOS_DISK" }, +{ 27 , "ERROR_SECTOR_NOT_FOUND" }, +{ 28 , "ERROR_OUT_OF_PAPER" }, +{ 29 , "ERROR_WRITE_FAULT" }, +{ 30 , "ERROR_READ_FAULT" }, +{ 31 , "ERROR_GEN_FAILURE" }, +{ 32 , "ERROR_SHARING_VIOLATION" }, +{ 33 , "ERROR_LOCK_VIOLATION" }, +{ 34 , "ERROR_WRONG_DISK" }, +{ 36 , "ERROR_SHARING_BUFFER_EXCEEDED" }, +{ 38 , "ERROR_HANDLE_EOF" }, +{ 39 , "ERROR_HANDLE_DISK_FULL" }, +{ 50 , "ERROR_NOT_SUPPORTED" }, +{ 51 , "ERROR_REM_NOT_LIST" }, +{ 52 , "ERROR_DUP_NAME" }, +{ 53 , "ERROR_BAD_NETPATH" }, +{ 54 , "ERROR_NETWORK_BUSY" }, +{ 55 , "ERROR_DEV_NOT_EXIST" }, +{ 56 , "ERROR_TOO_MANY_CMDS" }, +{ 57 , "ERROR_ADAP_HDW_ERR" }, +{ 58 , "ERROR_BAD_NET_RESP" }, +{ 59 , "ERROR_UNEXP_NET_ERR" }, +{ 60 , "ERROR_BAD_REM_ADAP" }, +{ 61 , "ERROR_PRINTQ_FULL" }, +{ 62 , "ERROR_NO_SPOOL_SPACE" }, +{ 63 , "ERROR_PRINT_CANCELLED" }, +{ 64 , "ERROR_NETNAME_DELETED" }, +{ 65 , "ERROR_NETWORK_ACCESS_DENIED" }, +{ 66 , "ERROR_BAD_DEV_TYPE" }, +{ 67 , "ERROR_BAD_NET_NAME" }, +{ 68 , "ERROR_TOO_MANY_NAMES" }, +{ 69 , "ERROR_TOO_MANY_SESS" }, +{ 70 , "ERROR_SHARING_PAUSED" }, +{ 71 , "ERROR_REQ_NOT_ACCEP" }, +{ 72 , "ERROR_REDIR_PAUSED" }, +{ 80 , "ERROR_FILE_EXISTS" }, +{ 82 , "ERROR_CANNOT_MAKE" }, +{ 83 , "ERROR_FAIL_I24" }, +{ 84 , "ERROR_OUT_OF_STRUCTURES" }, +{ 85 , "ERROR_ALREADY_ASSIGNED" }, +{ 86 , "ERROR_INVALID_PASSWORD" }, +{ 87 , "ERROR_INVALID_PARAMETER" }, +{ 88 , "ERROR_NET_WRITE_FAULT" }, +{ 89 , "ERROR_NO_PROC_SLOTS" }, +{ 100 , "ERROR_TOO_MANY_SEMAPHORES" }, +{ 101 , "ERROR_EXCL_SEM_ALREADY_OWNED" }, +{ 102 , "ERROR_SEM_IS_SET" }, +{ 103 , "ERROR_TOO_MANY_SEM_REQUESTS" }, +{ 104 , "ERROR_INVALID_AT_INTERRUPT_TIME" }, +{ 105 , "ERROR_SEM_OWNER_DIED" }, +{ 106 , "ERROR_SEM_USER_LIMIT" }, +{ 107 , "ERROR_DISK_CHANGE" }, +{ 108 , "ERROR_DRIVE_LOCKED" }, +{ 109 , "ERROR_BROKEN_PIPE" }, +{ 110 , "ERROR_OPEN_FAILED" }, +{ 111 , "ERROR_BUFFER_OVERFLOW" }, +{ 112 , "ERROR_DISK_FULL" }, +{ 113 , "ERROR_NO_MORE_SEARCH_HANDLES" }, +{ 114 , "ERROR_INVALID_TARGET_HANDLE" }, +{ 117 , "ERROR_INVALID_CATEGORY" }, +{ 118 , "ERROR_INVALID_VERIFY_SWITCH" }, +{ 119 , "ERROR_BAD_DRIVER_LEVEL" }, +{ 120 , "ERROR_CALL_NOT_IMPLEMENTED" }, +{ 121 , "ERROR_SEM_TIMEOUT" }, +{ 122 , "ERROR_INSUFFICIENT_BUFFER" }, +{ 123 , "ERROR_INVALID_NAME" }, +{ 124 , "ERROR_INVALID_LEVEL" }, +{ 125 , "ERROR_NO_VOLUME_LABEL" }, +{ 126 , "ERROR_MOD_NOT_FOUND" }, +{ 127 , "ERROR_PROC_NOT_FOUND" }, +{ 128 , "ERROR_WAIT_NO_CHILDREN" }, +{ 129 , "ERROR_CHILD_NOT_COMPLETE" }, +{ 130 , "ERROR_DIRECT_ACCESS_HANDLE" }, +{ 131 , "ERROR_NEGATIVE_SEEK" }, +{ 132 , "ERROR_SEEK_ON_DEVICE" }, +{ 133 , "ERROR_IS_JOIN_TARGET" }, +{ 134 , "ERROR_IS_JOINED" }, +{ 135 , "ERROR_IS_SUBSTED" }, +{ 136 , "ERROR_NOT_JOINED" }, +{ 137 , "ERROR_NOT_SUBSTED" }, +{ 138 , "ERROR_JOIN_TO_JOIN" }, +{ 139 , "ERROR_SUBST_TO_SUBST" }, +{ 140 , "ERROR_JOIN_TO_SUBST" }, +{ 141 , "ERROR_SUBST_TO_JOIN" }, +{ 142 , "ERROR_BUSY_DRIVE" }, +{ 143 , "ERROR_SAME_DRIVE" }, +{ 144 , "ERROR_DIR_NOT_ROOT" }, +{ 145 , "ERROR_DIR_NOT_EMPTY" }, +{ 146 , "ERROR_IS_SUBST_PATH" }, +{ 147 , "ERROR_IS_JOIN_PATH" }, +{ 148 , "ERROR_PATH_BUSY" }, +{ 149 , "ERROR_IS_SUBST_TARGET" }, +{ 150 , "ERROR_SYSTEM_TRACE" }, +{ 151 , "ERROR_INVALID_EVENT_COUNT" }, +{ 152 , "ERROR_TOO_MANY_MUXWAITERS" }, +{ 153 , "ERROR_INVALID_LIST_FORMAT" }, +{ 154 , "ERROR_LABEL_TOO_LONG" }, +{ 155 , "ERROR_TOO_MANY_TCBS" }, +{ 156 , "ERROR_SIGNAL_REFUSED" }, +{ 157 , "ERROR_DISCARDED" }, +{ 158 , "ERROR_NOT_LOCKED" }, +{ 159 , "ERROR_BAD_THREADID_ADDR" }, +{ 160 , "ERROR_BAD_ARGUMENTS" }, +{ 161 , "ERROR_BAD_PATHNAME" }, +{ 162 , "ERROR_SIGNAL_PENDING" }, +{ 164 , "ERROR_MAX_THRDS_REACHED" }, +{ 167 , "ERROR_LOCK_FAILED" }, +{ 170 , "ERROR_BUSY" }, +{ 173 , "ERROR_CANCEL_VIOLATION" }, +{ 174 , "ERROR_ATOMIC_LOCKS_NOT_SUPPORTED" }, +{ 180 , "ERROR_INVALID_SEGMENT_NUMBER" }, +{ 182 , "ERROR_INVALID_ORDINAL" }, +{ 183 , "ERROR_ALREADY_EXISTS" }, +{ 186 , "ERROR_INVALID_FLAG_NUMBER" }, +{ 187 , "ERROR_SEM_NOT_FOUND" }, +{ 188 , "ERROR_INVALID_STARTING_CODESEG" }, +{ 189 , "ERROR_INVALID_STACKSEG" }, +{ 190 , "ERROR_INVALID_MODULETYPE" }, +{ 191 , "ERROR_INVALID_EXE_SIGNATURE" }, +{ 192 , "ERROR_EXE_MARKED_INVALID" }, +{ 193 , "ERROR_BAD_EXE_FORMAT" }, +{ 194 , "ERROR_ITERATED_DATA_EXCEEDS_64k" }, +{ 195 , "ERROR_INVALID_MINALLOCSIZE" }, +{ 196 , "ERROR_DYNLINK_FROM_INVALID_RING" }, +{ 197 , "ERROR_IOPL_NOT_ENABLED" }, +{ 198 , "ERROR_INVALID_SEGDPL" }, +{ 199 , "ERROR_AUTODATASEG_EXCEEDS_64k" }, +{ 200 , "ERROR_RING2SEG_MUST_BE_MOVABLE" }, +{ 201 , "ERROR_RELOC_CHAIN_XEEDS_SEGLIM" }, +{ 202 , "ERROR_INFLOOP_IN_RELOC_CHAIN" }, +{ 203 , "ERROR_ENVVAR_NOT_FOUND" }, +{ 205 , "ERROR_NO_SIGNAL_SENT" }, +{ 206 , "ERROR_FILENAME_EXCED_RANGE" }, +{ 207 , "ERROR_RING2_STACK_IN_USE" }, +{ 208 , "ERROR_META_EXPANSION_TOO_LONG" }, +{ 209 , "ERROR_INVALID_SIGNAL_NUMBER" }, +{ 210 , "ERROR_THREAD_1_INACTIVE" }, +{ 212 , "ERROR_LOCKED" }, +{ 214 , "ERROR_TOO_MANY_MODULES" }, +{ 215 , "ERROR_NESTING_NOT_ALLOWED" }, +{ 230 , "ERROR_BAD_PIPE" }, +{ 231 , "ERROR_PIPE_BUSY" }, +{ 232 , "ERROR_NO_DATA" }, +{ 233 , "ERROR_PIPE_NOT_CONNECTED" }, +{ 234 , "ERROR_MORE_DATA" }, +{ 240 , "ERROR_VC_DISCONNECTED" }, +{ 254 , "ERROR_INVALID_EA_NAME" }, +{ 255 , "ERROR_EA_LIST_INCONSISTENT" }, +{ 259 , "ERROR_NO_MORE_ITEMS" }, +{ 266 , "ERROR_CANNOT_COPY" }, +{ 267 , "ERROR_DIRECTORY" }, +{ 275 , "ERROR_EAS_DIDNT_FIT" }, +{ 276 , "ERROR_EA_FILE_CORRUPT" }, +{ 277 , "ERROR_EA_TABLE_FULL" }, +{ 278 , "ERROR_INVALID_EA_HANDLE" }, +{ 282 , "ERROR_EAS_NOT_SUPPORTED" }, +{ 288 , "ERROR_NOT_OWNER" }, +{ 298 , "ERROR_TOO_MANY_POSTS" }, +{ 299 , "ERROR_PARTIAL_COPY" }, +{ 317 , "ERROR_MR_MID_NOT_FOUND" }, +{ 487 , "ERROR_INVALID_ADDRESS" }, +{ 534 , "ERROR_ARITHMETIC_OVERFLOW" }, +{ 535 , "ERROR_PIPE_CONNECTED" }, +{ 536 , "ERROR_PIPE_LISTENING" }, +{ 994 , "ERROR_EA_ACCESS_DENIED" }, +{ 995 , "ERROR_OPERATION_ABORTED" }, +{ 996 , "ERROR_IO_INCOMPLETE" }, +{ 997 , "ERROR_IO_PENDING" }, +{ 998 , "ERROR_NOACCESS" }, +{ 999 , "ERROR_SWAPERROR" }, +{ 1001 , "ERROR_STACK_OVERFLOW" }, +{ 1002 , "ERROR_INVALID_MESSAGE" }, +{ 1003 , "ERROR_CAN_NOT_COMPLETE" }, +{ 1004 , "ERROR_INVALID_FLAGS" }, +{ 1005 , "ERROR_UNRECOGNIZED_VOLUME" }, +{ 1006 , "ERROR_FILE_INVALID" }, +{ 1007 , "ERROR_FULLSCREEN_MODE" }, +{ 1008 , "ERROR_NO_TOKEN" }, +{ 1009 , "ERROR_BADDB" }, +{ 1010 , "ERROR_BADKEY" }, +{ 1011 , "ERROR_CANTOPEN" }, +{ 1012 , "ERROR_CANTREAD" }, +{ 1013 , "ERROR_CANTWRITE" }, +{ 1014 , "ERROR_REGISTRY_RECOVERED" }, +{ 1015 , "ERROR_REGISTRY_CORRUPT" }, +{ 1016 , "ERROR_REGISTRY_IO_FAILED" }, +{ 1017 , "ERROR_NOT_REGISTRY_FILE" }, +{ 1018 , "ERROR_KEY_DELETED" }, +{ 1019 , "ERROR_NO_LOG_SPACE" }, +{ 1020 , "ERROR_KEY_HAS_CHILDREN" }, +{ 1021 , "ERROR_CHILD_MUST_BE_VOLATILE" }, +{ 1022 , "ERROR_NOTIFY_ENUM_DIR" }, +{ 1051 , "ERROR_DEPENDENT_SERVICES_RUNNING" }, +{ 1052 , "ERROR_INVALID_SERVICE_CONTROL" }, +{ 1053 , "ERROR_SERVICE_REQUEST_TIMEOUT" }, +{ 1054 , "ERROR_SERVICE_NO_THREAD" }, +{ 1055 , "ERROR_SERVICE_DATABASE_LOCKED" }, +{ 1056 , "ERROR_SERVICE_ALREADY_RUNNING" }, +{ 1057 , "ERROR_INVALID_SERVICE_ACCOUNT" }, +{ 1058 , "ERROR_SERVICE_DISABLED" }, +{ 1059 , "ERROR_CIRCULAR_DEPENDENCY" }, +{ 1060 , "ERROR_SERVICE_DOES_NOT_EXIST" }, +{ 1061 , "ERROR_SERVICE_CANNOT_ACCEPT_CTRL" }, +{ 1062 , "ERROR_SERVICE_NOT_ACTIVE" }, +{ 1063 , "ERROR_FAILED_SERVICE_CONTROLLER_CONNECT" }, +{ 1064 , "ERROR_EXCEPTION_IN_SERVICE" }, +{ 1065 , "ERROR_DATABASE_DOES_NOT_EXIST" }, +{ 1066 , "ERROR_SERVICE_SPECIFIC_ERROR" }, +{ 1067 , "ERROR_PROCESS_ABORTED" }, +{ 1068 , "ERROR_SERVICE_DEPENDENCY_FAIL" }, +{ 1069 , "ERROR_SERVICE_LOGON_FAILED" }, +{ 1070 , "ERROR_SERVICE_START_HANG" }, +{ 1071 , "ERROR_INVALID_SERVICE_LOCK" }, +{ 1072 , "ERROR_SERVICE_MARKED_FOR_DELETE" }, +{ 1073 , "ERROR_SERVICE_EXISTS" }, +{ 1074 , "ERROR_ALREADY_RUNNING_LKG" }, +{ 1075 , "ERROR_SERVICE_DEPENDENCY_DELETED" }, +{ 1076 , "ERROR_BOOT_ALREADY_ACCEPTED" }, +{ 1077 , "ERROR_SERVICE_NEVER_STARTED" }, +{ 1078 , "ERROR_DUPLICATE_SERVICE_NAME" }, +{ 1100 , "ERROR_END_OF_MEDIA" }, +{ 1101 , "ERROR_FILEMARK_DETECTED" }, +{ 1102 , "ERROR_BEGINNING_OF_MEDIA" }, +{ 1103 , "ERROR_SETMARK_DETECTED" }, +{ 1104 , "ERROR_NO_DATA_DETECTED" }, +{ 1105 , "ERROR_PARTITION_FAILURE" }, +{ 1106 , "ERROR_INVALID_BLOCK_LENGTH" }, +{ 1107 , "ERROR_DEVICE_NOT_PARTITIONED" }, +{ 1108 , "ERROR_UNABLE_TO_LOCK_MEDIA" }, +{ 1109 , "ERROR_UNABLE_TO_UNLOAD_MEDIA" }, +{ 1110 , "ERROR_MEDIA_CHANGED" }, +{ 1111 , "ERROR_BUS_RESET" }, +{ 1112 , "ERROR_NO_MEDIA_IN_DRIVE" }, +{ 1113 , "ERROR_NO_UNICODE_TRANSLATION" }, +{ 1114 , "ERROR_DLL_INIT_FAILED" }, +{ 1115 , "ERROR_SHUTDOWN_IN_PROGRESS" }, +{ 1116 , "ERROR_NO_SHUTDOWN_IN_PROGRESS" }, +{ 1117 , "ERROR_IO_DEVICE" }, +{ 1118 , "ERROR_SERIAL_NO_DEVICE" }, +{ 1119 , "ERROR_IRQ_BUSY" }, +{ 1120 , "ERROR_MORE_WRITES" }, +{ 1121 , "ERROR_COUNTER_TIMEOUT" }, +{ 1122 , "ERROR_FLOPPY_ID_MARK_NOT_FOUND" }, +{ 1123 , "ERROR_FLOPPY_WRONG_CYLINDER" }, +{ 1124 , "ERROR_FLOPPY_UNKNOWN_ERROR" }, +{ 1125 , "ERROR_FLOPPY_BAD_REGISTERS" }, +{ 1126 , "ERROR_DISK_RECALIBRATE_FAILED" }, +{ 1127 , "ERROR_DISK_OPERATION_FAILED" }, +{ 1128 , "ERROR_DISK_RESET_FAILED" }, +{ 1129 , "ERROR_EOM_OVERFLOW" }, +{ 1130 , "ERROR_NOT_ENOUGH_SERVER_MEMORY" }, +{ 1131 , "ERROR_POSSIBLE_DEADLOCK" }, +{ 1132 , "ERROR_MAPPED_ALIGNMENT" }, +{ 1140 , "ERROR_SET_POWER_STATE_VETOED" }, +{ 1141 , "ERROR_SET_POWER_STATE_FAILED" }, +{ 1150 , "ERROR_OLD_WIN_VERSION" }, +{ 1151 , "ERROR_APP_WRONG_OS" }, +{ 1152 , "ERROR_SINGLE_INSTANCE_APP" }, +{ 1153 , "ERROR_RMODE_APP" }, +{ 1154 , "ERROR_INVALID_DLL" }, +{ 1155 , "ERROR_NO_ASSOCIATION" }, +{ 1156 , "ERROR_DDE_FAIL" }, +{ 1157 , "ERROR_DLL_NOT_FOUND" }, +{ 2202 , "ERROR_BAD_USERNAME" }, +{ 2250 , "ERROR_NOT_CONNECTED" }, +{ 2401 , "ERROR_OPEN_FILES" }, +{ 2402 , "ERROR_ACTIVE_CONNECTIONS" }, +{ 2404 , "ERROR_DEVICE_IN_USE" }, +{ 1200 , "ERROR_BAD_DEVICE" }, +{ 1201 , "ERROR_CONNECTION_UNAVAIL" }, +{ 1202 , "ERROR_DEVICE_ALREADY_REMEMBERED" }, +{ 1203 , "ERROR_NO_NET_OR_BAD_PATH" }, +{ 1204 , "ERROR_BAD_PROVIDER" }, +{ 1205 , "ERROR_CANNOT_OPEN_PROFILE" }, +{ 1206 , "ERROR_BAD_PROFILE" }, +{ 1207 , "ERROR_NOT_CONTAINER" }, +{ 1208 , "ERROR_EXTENDED_ERROR" }, +{ 1209 , "ERROR_INVALID_GROUPNAME" }, +{ 1210 , "ERROR_INVALID_COMPUTERNAME" }, +{ 1211 , "ERROR_INVALID_EVENTNAME" }, +{ 1212 , "ERROR_INVALID_DOMAINNAME" }, +{ 1213 , "ERROR_INVALID_SERVICENAME" }, +{ 1214 , "ERROR_INVALID_NETNAME" }, +{ 1215 , "ERROR_INVALID_SHARENAME" }, +{ 1216 , "ERROR_INVALID_PASSWORDNAME" }, +{ 1217 , "ERROR_INVALID_MESSAGENAME" }, +{ 1218 , "ERROR_INVALID_MESSAGEDEST" }, +{ 1219 , "ERROR_SESSION_CREDENTIAL_CONFLICT" }, +{ 1220 , "ERROR_REMOTE_SESSION_LIMIT_EXCEEDED" }, +{ 1221 , "ERROR_DUP_DOMAINNAME" }, +{ 1222 , "ERROR_NO_NETWORK" }, +{ 1223 , "ERROR_CANCELLED" }, +{ 1224 , "ERROR_USER_MAPPED_FILE" }, +{ 1225 , "ERROR_CONNECTION_REFUSED" }, +{ 1226 , "ERROR_GRACEFUL_DISCONNECT" }, +{ 1227 , "ERROR_ADDRESS_ALREADY_ASSOCIATED" }, +{ 1228 , "ERROR_ADDRESS_NOT_ASSOCIATED" }, +{ 1229 , "ERROR_CONNECTION_INVALID" }, +{ 1230 , "ERROR_CONNECTION_ACTIVE" }, +{ 1231 , "ERROR_NETWORK_UNREACHABLE" }, +{ 1232 , "ERROR_HOST_UNREACHABLE" }, +{ 1233 , "ERROR_PROTOCOL_UNREACHABLE" }, +{ 1234 , "ERROR_PORT_UNREACHABLE" }, +{ 1235 , "ERROR_REQUEST_ABORTED" }, +{ 1236 , "ERROR_CONNECTION_ABORTED" }, +{ 1237 , "ERROR_RETRY" }, +{ 1238 , "ERROR_CONNECTION_COUNT_LIMIT" }, +{ 1239 , "ERROR_LOGIN_TIME_RESTRICTION" }, +{ 1240 , "ERROR_LOGIN_WKSTA_RESTRICTION" }, +{ 1241 , "ERROR_INCORRECT_ADDRESS" }, +{ 1242 , "ERROR_ALREADY_REGISTERED" }, +{ 1243 , "ERROR_SERVICE_NOT_FOUND" }, +{ 1244 , "ERROR_NOT_AUTHENTICATED" }, +{ 1245 , "ERROR_NOT_LOGGED_ON" }, +{ 1246 , "ERROR_CONTINUE" }, +{ 1247 , "ERROR_ALREADY_INITIALIZED" }, +{ 1248 , "ERROR_NO_MORE_DEVICES" }, +{ 1300 , "ERROR_NOT_ALL_ASSIGNED" }, +{ 1301 , "ERROR_SOME_NOT_MAPPED" }, +{ 1302 , "ERROR_NO_QUOTAS_FOR_ACCOUNT" }, +{ 1303 , "ERROR_LOCAL_USER_SESSION_KEY" }, +{ 1304 , "ERROR_NULL_LM_PASSWORD" }, +{ 1305 , "ERROR_UNKNOWN_REVISION" }, +{ 1306 , "ERROR_REVISION_MISMATCH" }, +{ 1307 , "ERROR_INVALID_OWNER" }, +{ 1308 , "ERROR_INVALID_PRIMARY_GROUP" }, +{ 1309 , "ERROR_NO_IMPERSONATION_TOKEN" }, +{ 1310 , "ERROR_CANT_DISABLE_MANDATORY" }, +{ 1311 , "ERROR_NO_LOGON_SERVERS" }, +{ 1312 , "ERROR_NO_SUCH_LOGON_SESSION" }, +{ 1313 , "ERROR_NO_SUCH_PRIVILEGE" }, +{ 1314 , "ERROR_PRIVILEGE_NOT_HELD" }, +{ 1315 , "ERROR_INVALID_ACCOUNT_NAME" }, +{ 1316 , "ERROR_USER_EXISTS" }, +{ 1317 , "ERROR_NO_SUCH_USER" }, +{ 1318 , "ERROR_GROUP_EXISTS" }, +{ 1319 , "ERROR_NO_SUCH_GROUP" }, +{ 1320 , "ERROR_MEMBER_IN_GROUP" }, +{ 1321 , "ERROR_MEMBER_NOT_IN_GROUP" }, +{ 1322 , "ERROR_LAST_ADMIN" }, +{ 1323 , "ERROR_WRONG_PASSWORD" }, +{ 1324 , "ERROR_ILL_FORMED_PASSWORD" }, +{ 1325 , "ERROR_PASSWORD_RESTRICTION" }, +{ 1326 , "ERROR_LOGON_FAILURE" }, +{ 1327 , "ERROR_ACCOUNT_RESTRICTION" }, +{ 1328 , "ERROR_INVALID_LOGON_HOURS" }, +{ 1329 , "ERROR_INVALID_WORKSTATION" }, +{ 1330 , "ERROR_PASSWORD_EXPIRED" }, +{ 1331 , "ERROR_ACCOUNT_DISABLED" }, +{ 1332 , "ERROR_NONE_MAPPED" }, +{ 1333 , "ERROR_TOO_MANY_LUIDS_REQUESTED" }, +{ 1334 , "ERROR_LUIDS_EXHAUSTED" }, +{ 1335 , "ERROR_INVALID_SUB_AUTHORITY" }, +{ 1336 , "ERROR_INVALID_ACL" }, +{ 1337 , "ERROR_INVALID_SID" }, +{ 1338 , "ERROR_INVALID_SECURITY_DESCR" }, +{ 1340 , "ERROR_BAD_INHERITANCE_ACL" }, +{ 1341 , "ERROR_SERVER_DISABLED" }, +{ 1342 , "ERROR_SERVER_NOT_DISABLED" }, +{ 1343 , "ERROR_INVALID_ID_AUTHORITY" }, +{ 1344 , "ERROR_ALLOTTED_SPACE_EXCEEDED" }, +{ 1345 , "ERROR_INVALID_GROUP_ATTRIBUTES" }, +{ 1346 , "ERROR_BAD_IMPERSONATION_LEVEL" }, +{ 1347 , "ERROR_CANT_OPEN_ANONYMOUS" }, +{ 1348 , "ERROR_BAD_VALIDATION_CLASS" }, +{ 1349 , "ERROR_BAD_TOKEN_TYPE" }, +{ 1350 , "ERROR_NO_SECURITY_ON_OBJECT" }, +{ 1351 , "ERROR_CANT_ACCESS_DOMAIN_INFO" }, +{ 1352 , "ERROR_INVALID_SERVER_STATE" }, +{ 1353 , "ERROR_INVALID_DOMAIN_STATE" }, +{ 1354 , "ERROR_INVALID_DOMAIN_ROLE" }, +{ 1355 , "ERROR_NO_SUCH_DOMAIN" }, +{ 1356 , "ERROR_DOMAIN_EXISTS" }, +{ 1357 , "ERROR_DOMAIN_LIMIT_EXCEEDED" }, +{ 1358 , "ERROR_INTERNAL_DB_CORRUPTION" }, +{ 1359 , "ERROR_INTERNAL_ERROR" }, +{ 1360 , "ERROR_GENERIC_NOT_MAPPED" }, +{ 1361 , "ERROR_BAD_DESCRIPTOR_FORMAT" }, +{ 1362 , "ERROR_NOT_LOGON_PROCESS" }, +{ 1363 , "ERROR_LOGON_SESSION_EXISTS" }, +{ 1364 , "ERROR_NO_SUCH_PACKAGE" }, +{ 1365 , "ERROR_BAD_LOGON_SESSION_STATE" }, +{ 1366 , "ERROR_LOGON_SESSION_COLLISION" }, +{ 1367 , "ERROR_INVALID_LOGON_TYPE" }, +{ 1368 , "ERROR_CANNOT_IMPERSONATE" }, +{ 1369 , "ERROR_RXACT_INVALID_STATE" }, +{ 1370 , "ERROR_RXACT_COMMIT_FAILURE" }, +{ 1371 , "ERROR_SPECIAL_ACCOUNT" }, +{ 1372 , "ERROR_SPECIAL_GROUP" }, +{ 1373 , "ERROR_SPECIAL_USER" }, +{ 1374 , "ERROR_MEMBERS_PRIMARY_GROUP" }, +{ 1375 , "ERROR_TOKEN_ALREADY_IN_USE" }, +{ 1376 , "ERROR_NO_SUCH_ALIAS" }, +{ 1377 , "ERROR_MEMBER_NOT_IN_ALIAS" }, +{ 1378 , "ERROR_MEMBER_IN_ALIAS" }, +{ 1379 , "ERROR_ALIAS_EXISTS" }, +{ 1380 , "ERROR_LOGON_NOT_GRANTED" }, +{ 1381 , "ERROR_TOO_MANY_SECRETS" }, +{ 1382 , "ERROR_SECRET_TOO_LONG" }, +{ 1383 , "ERROR_INTERNAL_DB_ERROR" }, +{ 1384 , "ERROR_TOO_MANY_CONTEXT_IDS" }, +{ 1385 , "ERROR_LOGON_TYPE_NOT_GRANTED" }, +{ 1386 , "ERROR_NT_CROSS_ENCRYPTION_REQUIRED" }, +{ 1387 , "ERROR_NO_SUCH_MEMBER" }, +{ 1388 , "ERROR_INVALID_MEMBER" }, +{ 1389 , "ERROR_TOO_MANY_SIDS" }, +{ 1390 , "ERROR_LM_CROSS_ENCRYPTION_REQUIRED" }, +{ 1391 , "ERROR_NO_INHERITANCE" }, +{ 1392 , "ERROR_FILE_CORRUPT" }, +{ 1393 , "ERROR_DISK_CORRUPT" }, +{ 1394 , "ERROR_NO_USER_SESSION_KEY" }, +{ 1395 , "ERROR_LICENSE_QUOTA_EXCEEDED" }, +{ 1400 , "ERROR_INVALID_WINDOW_HANDLE" }, +{ 1401 , "ERROR_INVALID_MENU_HANDLE" }, +{ 1402 , "ERROR_INVALID_CURSOR_HANDLE" }, +{ 1403 , "ERROR_INVALID_ACCEL_HANDLE" }, +{ 1404 , "ERROR_INVALID_HOOK_HANDLE" }, +{ 1405 , "ERROR_INVALID_DWP_HANDLE" }, +{ 1406 , "ERROR_TLW_WITH_WSCHILD" }, +{ 1407 , "ERROR_CANNOT_FIND_WND_CLASS" }, +{ 1408 , "ERROR_WINDOW_OF_OTHER_THREAD" }, +{ 1409 , "ERROR_HOTKEY_ALREADY_REGISTERED" }, +{ 1410 , "ERROR_CLASS_ALREADY_EXISTS" }, +{ 1411 , "ERROR_CLASS_DOES_NOT_EXIST" }, +{ 1412 , "ERROR_CLASS_HAS_WINDOWS" }, +{ 1413 , "ERROR_INVALID_INDEX" }, +{ 1414 , "ERROR_INVALID_ICON_HANDLE" }, +{ 1415 , "ERROR_PRIVATE_DIALOG_INDEX" }, +{ 1416 , "ERROR_LISTBOX_ID_NOT_FOUND" }, +{ 1417 , "ERROR_NO_WILDCARD_CHARACTERS" }, +{ 1418 , "ERROR_CLIPBOARD_NOT_OPEN" }, +{ 1419 , "ERROR_HOTKEY_NOT_REGISTERED" }, +{ 1420 , "ERROR_WINDOW_NOT_DIALOG" }, +{ 1421 , "ERROR_CONTROL_ID_NOT_FOUND" }, +{ 1422 , "ERROR_INVALID_COMBOBOX_MESSAGE" }, +{ 1423 , "ERROR_WINDOW_NOT_COMBOBOX" }, +{ 1424 , "ERROR_INVALID_EDIT_HEIGHT" }, +{ 1425 , "ERROR_DC_NOT_FOUND" }, +{ 1426 , "ERROR_INVALID_HOOK_FILTER" }, +{ 1427 , "ERROR_INVALID_FILTER_PROC" }, +{ 1428 , "ERROR_HOOK_NEEDS_HMOD" }, +{ 1429 , "ERROR_GLOBAL_ONLY_HOOK" }, +{ 1430 , "ERROR_JOURNAL_HOOK_SET" }, +{ 1431 , "ERROR_HOOK_NOT_INSTALLED" }, +{ 1432 , "ERROR_INVALID_LB_MESSAGE" }, +{ 1433 , "ERROR_SETCOUNT_ON_BAD_LB" }, +{ 1434 , "ERROR_LB_WITHOUT_TABSTOPS" }, +{ 1435 , "ERROR_DESTROY_OBJECT_OF_OTHER_THREAD" }, +{ 1436 , "ERROR_CHILD_WINDOW_MENU" }, +{ 1437 , "ERROR_NO_SYSTEM_MENU" }, +{ 1438 , "ERROR_INVALID_MSGBOX_STYLE" }, +{ 1439 , "ERROR_INVALID_SPI_VALUE" }, +{ 1440 , "ERROR_SCREEN_ALREADY_LOCKED" }, +{ 1441 , "ERROR_HWNDS_HAVE_DIFF_PARENT" }, +{ 1442 , "ERROR_NOT_CHILD_WINDOW" }, +{ 1443 , "ERROR_INVALID_GW_COMMAND" }, +{ 1444 , "ERROR_INVALID_THREAD_ID" }, +{ 1445 , "ERROR_NON_MDICHILD_WINDOW" }, +{ 1446 , "ERROR_POPUP_ALREADY_ACTIVE" }, +{ 1447 , "ERROR_NO_SCROLLBARS" }, +{ 1448 , "ERROR_INVALID_SCROLLBAR_RANGE" }, +{ 1449 , "ERROR_INVALID_SHOWWIN_COMMAND" }, +{ 1450 , "ERROR_NO_SYSTEM_RESOURCES" }, +{ 1451 , "ERROR_NONPAGED_SYSTEM_RESOURCES" }, +{ 1452 , "ERROR_PAGED_SYSTEM_RESOURCES" }, +{ 1453 , "ERROR_WORKING_SET_QUOTA" }, +{ 1454 , "ERROR_PAGEFILE_QUOTA" }, +{ 1455 , "ERROR_COMMITMENT_LIMIT" }, +{ 1456 , "ERROR_MENU_ITEM_NOT_FOUND" }, +{ 1500 , "ERROR_EVENTLOG_FILE_CORRUPT" }, +{ 1501 , "ERROR_EVENTLOG_CANT_START" }, +{ 1502 , "ERROR_LOG_FILE_FULL" }, +{ 1503 , "ERROR_EVENTLOG_FILE_CHANGED" }, +{ 1700 , "RPC_S_INVALID_STRING_BINDING" }, +{ 1701 , "RPC_S_WRONG_KIND_OF_BINDING" }, +{ 1702 , "RPC_S_INVALID_BINDING" }, +{ 1703 , "RPC_S_PROTSEQ_NOT_SUPPORTED" }, +{ 1704 , "RPC_S_INVALID_RPC_PROTSEQ" }, +{ 1705 , "RPC_S_INVALID_STRING_UUID" }, +{ 1706 , "RPC_S_INVALID_ENDPOINT_FORMAT" }, +{ 1707 , "RPC_S_INVALID_NET_ADDR" }, +{ 1708 , "RPC_S_NO_ENDPOINT_FOUND" }, +{ 1709 , "RPC_S_INVALID_TIMEOUT" }, +{ 1710 , "RPC_S_OBJECT_NOT_FOUND" }, +{ 1711 , "RPC_S_ALREADY_REGISTERED" }, +{ 1712 , "RPC_S_TYPE_ALREADY_REGISTERED" }, +{ 1713 , "RPC_S_ALREADY_LISTENING" }, +{ 1714 , "RPC_S_NO_PROTSEQS_REGISTERED" }, +{ 1715 , "RPC_S_NOT_LISTENING" }, +{ 1716 , "RPC_S_UNKNOWN_MGR_TYPE" }, +{ 1717 , "RPC_S_UNKNOWN_IF" }, +{ 1718 , "RPC_S_NO_BINDINGS" }, +{ 1719 , "RPC_S_NO_PROTSEQS" }, +{ 1720 , "RPC_S_CANT_CREATE_ENDPOINT" }, +{ 1721 , "RPC_S_OUT_OF_RESOURCES" }, +{ 1722 , "RPC_S_SERVER_UNAVAILABLE" }, +{ 1723 , "RPC_S_SERVER_TOO_BUSY" }, +{ 1724 , "RPC_S_INVALID_NETWORK_OPTIONS" }, +{ 1725 , "RPC_S_NO_CALL_ACTIVE" }, +{ 1726 , "RPC_S_CALL_FAILED" }, +{ 1727 , "RPC_S_CALL_FAILED_DNE" }, +{ 1728 , "RPC_S_PROTOCOL_ERROR" }, +{ 1730 , "RPC_S_UNSUPPORTED_TRANS_SYN" }, +{ 1732 , "RPC_S_UNSUPPORTED_TYPE" }, +{ 1733 , "RPC_S_INVALID_TAG" }, +{ 1734 , "RPC_S_INVALID_BOUND" }, +{ 1735 , "RPC_S_NO_ENTRY_NAME" }, +{ 1736 , "RPC_S_INVALID_NAME_SYNTAX" }, +{ 1737 , "RPC_S_UNSUPPORTED_NAME_SYNTAX" }, +{ 1739 , "RPC_S_UUID_NO_ADDRESS" }, +{ 1740 , "RPC_S_DUPLICATE_ENDPOINT" }, +{ 1741 , "RPC_S_UNKNOWN_AUTHN_TYPE" }, +{ 1742 , "RPC_S_MAX_CALLS_TOO_SMALL" }, +{ 1743 , "RPC_S_STRING_TOO_LONG" }, +{ 1744 , "RPC_S_PROTSEQ_NOT_FOUND" }, +{ 1745 , "RPC_S_PROCNUM_OUT_OF_RANGE" }, +{ 1746 , "RPC_S_BINDING_HAS_NO_AUTH" }, +{ 1747 , "RPC_S_UNKNOWN_AUTHN_SERVICE" }, +{ 1748 , "RPC_S_UNKNOWN_AUTHN_LEVEL" }, +{ 1749 , "RPC_S_INVALID_AUTH_IDENTITY" }, +{ 1750 , "RPC_S_UNKNOWN_AUTHZ_SERVICE" }, +{ 1751 , "EPT_S_INVALID_ENTRY" }, +{ 1752 , "EPT_S_CANT_PERFORM_OP" }, +{ 1753 , "EPT_S_NOT_REGISTERED" }, +{ 1754 , "RPC_S_NOTHING_TO_EXPORT" }, +{ 1755 , "RPC_S_INCOMPLETE_NAME" }, +{ 1756 , "RPC_S_INVALID_VERS_OPTION" }, +{ 1757 , "RPC_S_NO_MORE_MEMBERS" }, +{ 1758 , "RPC_S_NOT_ALL_OBJS_UNEXPORTED" }, +{ 1759 , "RPC_S_INTERFACE_NOT_FOUND" }, +{ 1760 , "RPC_S_ENTRY_ALREADY_EXISTS" }, +{ 1761 , "RPC_S_ENTRY_NOT_FOUND" }, +{ 1762 , "RPC_S_NAME_SERVICE_UNAVAILABLE" }, +{ 1763 , "RPC_S_INVALID_NAF_ID" }, +{ 1764 , "RPC_S_CANNOT_SUPPORT" }, +{ 1765 , "RPC_S_NO_CONTEXT_AVAILABLE" }, +{ 1766 , "RPC_S_INTERNAL_ERROR" }, +{ 1767 , "RPC_S_ZERO_DIVIDE" }, +{ 1768 , "RPC_S_ADDRESS_ERROR" }, +{ 1769 , "RPC_S_FP_DIV_ZERO" }, +{ 1770 , "RPC_S_FP_UNDERFLOW" }, +{ 1771 , "RPC_S_FP_OVERFLOW" }, +{ 1772 , "RPC_X_NO_MORE_ENTRIES" }, +{ 1773 , "RPC_X_SS_CHAR_TRANS_OPEN_FAIL" }, +{ 1774 , "RPC_X_SS_CHAR_TRANS_SHORT_FILE" }, +{ 1775 , "RPC_X_SS_IN_NULL_CONTEXT" }, +{ 1777 , "RPC_X_SS_CONTEXT_DAMAGED" }, +{ 1778 , "RPC_X_SS_HANDLES_MISMATCH" }, +{ 1779 , "RPC_X_SS_CANNOT_GET_CALL_HANDLE" }, +{ 1780 , "RPC_X_NULL_REF_POINTER" }, +{ 1781 , "RPC_X_ENUM_VALUE_OUT_OF_RANGE" }, +{ 1782 , "RPC_X_BYTE_COUNT_TOO_SMALL" }, +{ 1783 , "RPC_X_BAD_STUB_DATA" }, +{ 1784 , "ERROR_INVALID_USER_BUFFER" }, +{ 1785 , "ERROR_UNRECOGNIZED_MEDIA" }, +{ 1786 , "ERROR_NO_TRUST_LSA_SECRET" }, +{ 1787 , "ERROR_NO_TRUST_SAM_ACCOUNT" }, +{ 1788 , "ERROR_TRUSTED_DOMAIN_FAILURE" }, +{ 1789 , "ERROR_TRUSTED_RELATIONSHIP_FAILURE" }, +{ 1790 , "ERROR_TRUST_FAILURE" }, +{ 1791 , "RPC_S_CALL_IN_PROGRESS" }, +{ 1792 , "ERROR_NETLOGON_NOT_STARTED" }, +{ 1793 , "ERROR_ACCOUNT_EXPIRED" }, +{ 1794 , "ERROR_REDIRECTOR_HAS_OPEN_HANDLES" }, +{ 1795 , "ERROR_PRINTER_DRIVER_ALREADY_INSTALLED" }, +{ 1796 , "ERROR_UNKNOWN_PORT" }, +{ 1797 , "ERROR_UNKNOWN_PRINTER_DRIVER" }, +{ 1798 , "ERROR_UNKNOWN_PRINTPROCESSOR" }, +{ 1799 , "ERROR_INVALID_SEPARATOR_FILE" }, +{ 1800 , "ERROR_INVALID_PRIORITY" }, +{ 1801 , "ERROR_INVALID_PRINTER_NAME" }, +{ 1802 , "ERROR_PRINTER_ALREADY_EXISTS" }, +{ 1803 , "ERROR_INVALID_PRINTER_COMMAND" }, +{ 1804 , "ERROR_INVALID_DATATYPE" }, +{ 1805 , "ERROR_INVALID_ENVIRONMENT" }, +{ 1806 , "RPC_S_NO_MORE_BINDINGS" }, +{ 1807 , "ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT" }, +{ 1808 , "ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT" }, +{ 1809 , "ERROR_NOLOGON_SERVER_TRUST_ACCOUNT" }, +{ 1810 , "ERROR_DOMAIN_TRUST_INCONSISTENT" }, +{ 1811 , "ERROR_SERVER_HAS_OPEN_HANDLES" }, +{ 1812 , "ERROR_RESOURCE_DATA_NOT_FOUND" }, +{ 1813 , "ERROR_RESOURCE_TYPE_NOT_FOUND" }, +{ 1814 , "ERROR_RESOURCE_NAME_NOT_FOUND" }, +{ 1815 , "ERROR_RESOURCE_LANG_NOT_FOUND" }, +{ 1816 , "ERROR_NOT_ENOUGH_QUOTA" }, +{ 1817 , "RPC_S_NO_INTERFACES" }, +{ 1818 , "RPC_S_CALL_CANCELLED" }, +{ 1819 , "RPC_S_BINDING_INCOMPLETE" }, +{ 1820 , "RPC_S_COMM_FAILURE" }, +{ 1821 , "RPC_S_UNSUPPORTED_AUTHN_LEVEL" }, +{ 1822 , "RPC_S_NO_PRINC_NAME" }, +{ 1823 , "RPC_S_NOT_RPC_ERROR" }, +{ 1824 , "RPC_S_UUID_LOCAL_ONLY" }, +{ 1825 , "RPC_S_SEC_PKG_ERROR" }, +{ 1826 , "RPC_S_NOT_CANCELLED" }, +{ 1827 , "RPC_X_INVALID_ES_ACTION" }, +{ 1828 , "RPC_X_WRONG_ES_VERSION" }, +{ 1829 , "RPC_X_WRONG_STUB_VERSION" }, +{ 1898 , "RPC_S_GROUP_MEMBER_NOT_FOUND" }, +{ 1899 , "EPT_S_CANT_CREATE" }, +{ 1900 , "RPC_S_INVALID_OBJECT" }, +{ 1901 , "ERROR_INVALID_TIME" }, +{ 1902 , "ERROR_INVALID_FORM_NAME" }, +{ 1903 , "ERROR_INVALID_FORM_SIZE" }, +{ 1904 , "ERROR_ALREADY_WAITING" }, +{ 1905 , "ERROR_PRINTER_DELETED" }, +{ 1906 , "ERROR_INVALID_PRINTER_STATE" }, +{ 1907 , "ERROR_PASSWORD_MUST_CHANGE" }, +{ 1908 , "ERROR_DOMAIN_CONTROLLER_NOT_FOUND" }, +{ 1909 , "ERROR_ACCOUNT_LOCKED_OUT" }, +{ 6118 , "ERROR_NO_BROWSER_SERVERS_FOUND" }, +{ 2000 , "ERROR_INVALID_PIXEL_FORMAT" }, +{ 2001 , "ERROR_BAD_DRIVER" }, +{ 2002 , "ERROR_INVALID_WINDOW_STYLE" }, +{ 2003 , "ERROR_METAFILE_NOT_SUPPORTED" }, +{ 2004 , "ERROR_TRANSFORM_NOT_SUPPORTED" }, +{ 2005 , "ERROR_CLIPPING_NOT_SUPPORTED" }, +{ 3000 , "ERROR_UNKNOWN_PRINT_MONITOR" }, +{ 3001 , "ERROR_PRINTER_DRIVER_IN_USE" }, +{ 3002 , "ERROR_SPOOL_FILE_NOT_FOUND" }, +{ 3003 , "ERROR_SPL_NO_STARTDOC" }, +{ 3004 , "ERROR_SPL_NO_ADDJOB" }, +{ 3005 , "ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED" }, +{ 3006 , "ERROR_PRINT_MONITOR_ALREADY_INSTALLED" }, +{ 4000 , "ERROR_WINS_INTERNAL" }, +{ 4001 , "ERROR_CAN_NOT_DEL_LOCAL_WINS" }, +{ 4002 , "ERROR_STATIC_INIT" }, +{ 4003 , "ERROR_INC_BACKUP" }, +{ 4004 , "ERROR_FULL_BACKUP" }, +{ 4005 , "ERROR_REC_NON_EXISTENT" }, +{ 4006 , "ERROR_RPL_NOT_ALLOWED" }, +{ 10004 , "WSAEINTR" }, +{ 10009 , "WSAEBADF" }, +{ 10013 , "WSAEACCES" }, +{ 10014 , "WSAEFAULT" }, +{ 10022 , "WSAEINVAL" }, +{ 10024 , "WSAEMFILE" }, +{ 10035 , "WSAEWOULDBLOCK" }, +{ 10036 , "WSAEINPROGRESS" }, +{ 10037 , "WSAEALREADY" }, +{ 10038 , "WSAENOTSOCK" }, +{ 10039 , "WSAEDESTADDRREQ" }, +{ 10040 , "WSAEMSGSIZE" }, +{ 10041 , "WSAEPROTOTYPE" }, +{ 10042 , "WSAENOPROTOOPT" }, +{ 10043 , "WSAEPROTONOSUPPORT" }, +{ 10044 , "WSAESOCKTNOSUPPORT" }, +{ 10045 , "WSAEOPNOTSUPP" }, +{ 10046 , "WSAEPFNOSUPPORT" }, +{ 10047 , "WSAEAFNOSUPPORT" }, +{ 10048 , "WSAEADDRINUSE" }, +{ 10049 , "WSAEADDRNOTAVAIL" }, +{ 10050 , "WSAENETDOWN" }, +{ 10051 , "WSAENETUNREACH" }, +{ 10052 , "WSAENETRESET" }, +{ 10053 , "WSAECONNABORTED" }, +{ 10054 , "WSAECONNRESET" }, +{ 10055 , "WSAENOBUFS" }, +{ 10056 , "WSAEISCONN" }, +{ 10057 , "WSAENOTCONN" }, +{ 10058 , "WSAESHUTDOWN" }, +{ 10059 , "WSAETOOMANYREFS" }, +{ 10060 , "WSAETIMEDOUT" }, +{ 10061 , "WSAECONNREFUSED" }, +{ 10062 , "WSAELOOP" }, +{ 10063 , "WSAENAMETOOLONG" }, +{ 10064 , "WSAEHOSTDOWN" }, +{ 10065 , "WSAEHOSTUNREACH" }, +{ 10066 , "WSAENOTEMPTY" }, +{ 10067 , "WSAEPROCLIM" }, +{ 10068 , "WSAEUSERS" }, +{ 10069 , "WSAEDQUOT" }, +{ 10070 , "WSAESTALE" }, +{ 10071 , "WSAEREMOTE" }, +{ 10101 , "WSAEDISCON" }, +{ 10091 , "WSASYSNOTREADY" }, +{ 10092 , "WSAVERNOTSUPPORTED" }, +{ 10093 , "WSANOTINITIALISED" }, +{ 11001 , "WSAHOST_NOT_FOUND" }, +{ 11002 , "WSATRY_AGAIN" }, +{ 11003 , "WSANO_RECOVERY" }, +{ 11004 , "WSANO_DATA" }, +{ 0, NULL } +}; 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; +} diff --git a/ldap/admin/src/AddPerlHeader.pl b/ldap/admin/src/AddPerlHeader.pl new file mode 100644 index 00000000..a3be11b5 --- /dev/null +++ b/ldap/admin/src/AddPerlHeader.pl @@ -0,0 +1,60 @@ +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +# used to add the perl preamble to all perl scripts used by the directory +# server run time; the problem is that the INC paths are compiled into +# the executable and cannot be overridden at run time, so we have to make +# sure we fix them + +# the first argument is the source path for the INC path +# the second argument is the token to replace with the server root +# at install time +# the third argument is the source perl script +# the fourth argument is the destination perl script +# + +($sourceLibPath, $serverRootToken, $sourceScript, $destScript) = @ARGV; +open SRC, $sourceScript or die "Error: could not open $sourceScript: $!"; +open DEST, ">$destScript" or die "Error: could not write $destScript: $!"; + +$isNT = -d '\\'; + +print DEST<<EOF1; +#!perl +# This preamble must be at the beginning of every perl script so that we can +# find packages and dynamically load code at run time; SERVER_ROOT must +# be replaced with the absolute path to the server root at installation +# time; it is assumed that the perl library will be installed as +# server root/install/perl +BEGIN { +EOF1 + +# if on NT, just assume we are using activeState, which looks like this +# server root/install/lib +# /bin +# /site/lib +# there is no arch subdir on NT +if ($isNT) { + print DEST "\t\@INC = qw( $serverRootToken/install/lib $serverRootToken/install/site/lib . );\n"; + print DEST "}\n"; +} else { + print DEST<<EOF2; + \$BUILD_PERL_PATH = \"$sourceLibPath\"; + \$RUN_PERL_PATH = \"$serverRootToken/install\"; + # make sure we use the unix path conventions + grep { s#\$BUILD_PERL_PATH#\$RUN_PERL_PATH#g } \@INC; +} +EOF2 +} + +# copy the rest of the file +while (<SRC>) { + print DEST; +} + +close DEST; +close SRC; diff --git a/ldap/admin/src/Base.def b/ldap/admin/src/Base.def new file mode 100644 index 00000000..ff1d1451 --- /dev/null +++ b/ldap/admin/src/Base.def @@ -0,0 +1,13 @@ +; BEGIN COPYRIGHT BLOCK +; Copyright 2001 Sun Microsystems, Inc. +; Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +; All rights reserved. +; END COPYRIGHT BLOCK +; +DESCRIPTION 'Netscape Setup SDK Dynamic perl module' +CODE SHARED READ EXECUTE +DATA SHARED READ WRITE +EXPORTS + XS_NSSetupSDK__Base_toLocal @2 + XS_NSSetupSDK__Base_toUTF8 @3 + boot_NSSetupSDK__Base @4 diff --git a/ldap/admin/src/Base.pm b/ldap/admin/src/Base.pm new file mode 100644 index 00000000..cbebf192 --- /dev/null +++ b/ldap/admin/src/Base.pm @@ -0,0 +1,63 @@ +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +package NSSetupSDK::Base; + +use POSIX; + +use strict; +use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $AUTOLOAD); + +require Exporter; +require DynaLoader; +require AutoLoader; + +@ISA = qw(Exporter DynaLoader); +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. + +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. +@EXPORT = qw( + toLocal toUTF8 +); +$VERSION = '1.00'; + +bootstrap NSSetupSDK::Base $VERSION; + +# Autoload methods go after =cut, and are processed by the autosplit program. + +1; +__END__ +# Below is the stub of documentation for your module. You better edit it! + +=head1 NAME + +NSSetupSDK::Base - Perl extension for directory server administrative utility functions + +=head1 SYNOPSIS + + use NSSetupSDK::Base; + +=head1 DESCRIPTION + +The NSSetupSDK::Base module is used by directory server administration scripts, such as +those used for installation/uninstallation, instance creation/removal, CGIs, +etc. + +=head1 AUTHOR + +Richard Megginson richm@netscape.com + +=head1 SEE ALSO + +perl(1). + +=cut diff --git a/ldap/admin/src/CGI_ENV b/ldap/admin/src/CGI_ENV new file mode 100644 index 00000000..d96d3ff8 --- /dev/null +++ b/ldap/admin/src/CGI_ENV @@ -0,0 +1,36 @@ +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +The following is a debug printout which is useful for reference. It +is a dump of all the env vars for a real running CGI admin program. +*********************************************************************** +HTTP_HOST=asterix.mcom.com:9616 +HTTP_ACCEPT=image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* +HTTP_USER_AGENT=Mozilla/2.0 (X11; U; SunOS 5.4 sun4m) +HTTP_CONNECTION=Keep-Alive +ADMSERV_PID=14001 +ADMSERV_ROOT=/export/free2/ns-home/admserv +NETSITE_ROOT=/export/free2/ns-home +SERVER_NAMES=slapd-asterix +CONFIG_DIR=/export/free2/ns-home/admserv/%s/ +COMMIT_LOG=/export/free2/ns-home/admserv/commit +BACKUPS=10 +PATH=/usr/sbin:/usr/bin +TZ=US/Pacific +SERVER_SOFTWARE=Netscape-Administrator/2.0b3 +SERVER_PORT=9616 +SERVER_NAME=asterix.mcom.com +SERVER_URL=http://asterix.mcom.com:9616 +REMOTE_HOST=goa.mcom.com +REMOTE_ADDR=207.1.137.54 +REMOTE_USER=admin +AUTH_TYPE=basic +HTTPS=OFF +GATEWAY_INTERFACE=CGI/1.1 +SERVER_PROTOCOL=HTTP/1.0 +REQUEST_METHOD=GET +SCRIPT_NAME=/slapd-asterix/bin/ds_pcontrol diff --git a/ldap/admin/src/Cgi.pm b/ldap/admin/src/Cgi.pm new file mode 100644 index 00000000..aba11e75 --- /dev/null +++ b/ldap/admin/src/Cgi.pm @@ -0,0 +1,70 @@ +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +package Cgi; + +sub parse { + my $line = shift; + my $assign; + my $var; + my $value; + + # save time, don't parse empty lines + return if (!$line); + + chomp( $line ); + if ( $raw ) { + $raw .= '&' . $line; + } else { + $raw = $line; + } + # decode the line first + $line = &decode($line); + # this only works if there are no '&' characters in var or value . . . + foreach $assign ( split( /&/, $line ) ) { + # assume the var is everything before the first '=' in assign + # and the value is everything after the first '=' + ( $var, $value ) = split( /=/, $assign, 2 ); + $main::cgiVars{$var} = $value; + } +} + +sub decode { + my $string = shift; + + $string =~ s/\+/ /g; + $string =~ s/%(\w\w)/chr(hex($1))/ge; + + return $string; +} + +sub main::freakOut { + my $i; + + for ( $i = 0 ; $i < scalar( @_ ) ; ++$i ) { + $_[$i] =~ s/'/\\'/g; + } + print "<SCRIPT language=JAVASCRIPT>\n"; + print "alert('@_');\n"; + print "location='index';\n</SCRIPT>\n"; + exit 0; +} + +if ($ENV{'QUERY_STRING'}) { + &parse( $ENV{'QUERY_STRING'} ); + $Cgi::QUERY_STRING = $ENV{'QUERY_STRING'}; +} + +if ( $ENV{'CONTENT_LENGTH'} ) { + read STDIN, $Cgi::CONTENT, $ENV{'CONTENT_LENGTH'}; + &parse( $Cgi::CONTENT ); +} + +# $Cgi::QUERY_STRING contains the query string and +# $Cgi::CONTENT contains what was passed in through stdin + +1; diff --git a/ldap/admin/src/CreateInstall.pl b/ldap/admin/src/CreateInstall.pl new file mode 100644 index 00000000..51714683 --- /dev/null +++ b/ldap/admin/src/CreateInstall.pl @@ -0,0 +1,34 @@ +#!perl +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +# figure out what the server root assuming the path to this script is +# server root/bin/slapd/admin/bin + +($serverRoot = $0) =~ s@[\\/]?bin[\\/]slapd[\\/]admin[\\/]bin.*$@@g; + +# run the post install program +$isNT = -d '\\'; +$quote = $isNT ? "\"" : ""; +# make sure the arguments are correctly quoted on NT +@fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @ARGV; +if (! $serverRoot) { + $serverRoot = "."; +} +chdir "$serverRoot/bin/slapd/admin/bin"; + +# note: exec on NT doesn't work the same way as exec on Unix. On Unix, exec replaces the calling +# process with the called process. The parent, if waiting for the calling process, will happily +# wait for it's replacement. On NT however, the parent thinks the calling process has gone, and +# it doesn't know about the called process, so it stops waiting. So, we have to do a system() +# on NT to force the calling process to wait for the called process. On Unix, we can do the +# faster and more memory efficient exec() call. +if ($isNT) { + system {'./ds_create'} './ds_create', @fixargs; +} else { + exec {'./ds_create'} './ds_create', @fixargs; +} diff --git a/ldap/admin/src/DSAdmin.def b/ldap/admin/src/DSAdmin.def new file mode 100644 index 00000000..a27ea129 --- /dev/null +++ b/ldap/admin/src/DSAdmin.def @@ -0,0 +1,11 @@ +; BEGIN COPYRIGHT BLOCK +; Copyright 2001 Sun Microsystems, Inc. +; Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +; All rights reserved. +; END COPYRIGHT BLOCK +; +LIBRARY "DSAdmin" +EXPORTS + boot_DSAdmin + _boot_DSAdmin = boot_DSAdmin + diff --git a/ldap/admin/src/DSAdmin.mk b/ldap/admin/src/DSAdmin.mk new file mode 100644 index 00000000..f81ca8a2 --- /dev/null +++ b/ldap/admin/src/DSAdmin.mk @@ -0,0 +1,134 @@ +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +# Makefile for the DSAdmin dynamic loaded perl module + +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) + +include $(MCOM_ROOT)/ldapserver/nsconfig.mk +include $(LDAP_SRC)/nsldap.mk +ifndef LDAP_USE_OLD_DB +include $(MCOM_ROOT)/ldapserver/ns_usedb.mk +endif + +BINDIR=$(LDAP_ADMIN_BIN_RELDIR) +OBJDEST=$(LDAP_ADMOBJDIR) + +INCLUDES += -I$(LDAP_SRC)/admin/include + +DS_SERVER_DEFS = -DNS_DS + +INFO = $(OBJDIR)/$(DIR) + +ifneq ($(ARCH), WINNT) +EXTRALDFLAGS += $(SSLLIBFLAG) +endif + +EXTRA_LIBS += $(LIBPERL_A) $(SETUPSDK_S_LINK) $(LDAP_ADMLIB) \ + $(LDAPLINK) $(DEPLINK) $(ADMINUTIL_LINK) \ + $(NSPRLINK) $(NLSLINK) \ + $(NLSLINK_CONV_STATIC) + +# the security libs are statically linked into libds_admin.so; osf doesn't like +# to link against them again, it thinks they are multiply defined +ifneq ($(ARCH), OSF1) +EXTRA_LIBS += $(SECURITYLINK) $(DBMLINK) +else +#DLL_LDFLAGS=-shared -all -error_unresolved -taso +#EXTRA_LIBS += -lcxx -lcxxstd -lcurses -lc +endif + +ifeq ($(ARCH), WINNT) +PLATFORM_INCLUDE = -I$(MCOM_ROOT)/ldapserver/include/nt +SUBSYSTEM=console +EXTRA_LIBS+=comctl32.lib $(LDAP_SDK_LIBLDAP_DLL) $(LDAP_LIBUTIL) +EXTRA_LIBS_DEP+=$(LDAP_LIBUTIL_DEP) +DEF_FILE:=DSAdmin.def +LINK_DLL += /NODEFAULTLIB:msvcrtd.lib +endif + +ifeq ($(ARCH), AIX) +EXTRA_LIBS += $(DLL_EXTRA_LIBS) -lbsd +LD=ld +endif + +# absolutely do not try to build perl-stuff with warnings-as-errors. +# (duh.) +ifeq ($(ARCH), Linux) +CFLAGS := $(subst -Werror,,$(CFLAGS)) +endif + +DSADMIN_OBJS = DSAdmin.o +DSADMIN_BASENAME = DSAdmin$(DLL_PRESUFFIX).$(DLL_SUFFIX) + +OBJS= $(addprefix $(OBJDEST)/, $(DSADMIN_OBJS)) +DSADMIN_SO = $(addprefix $(BINDIR)/, $(DSADMIN_BASENAME)) + +EXTRA_LIBS_DEP = $(SETUPSDK_DEP) + +# 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 explicitly link with the C and +# C++ runtime libraries (e.g., -lc) because, even though ld and CC link +# with them implicitly, -z defs will throw errors if we do not link with +# them explicitly. +ifeq ($(ARCH), SOLARIS) +LINK_DLL += -z defs +# removed -lcx from the following line +EXTRA_LIBS += -lCstd -lCrun -lm -lw -lc +# with the Forte 6 and later compilers, we must use CC to link +LD=CC +endif + +all: $(OBJDEST) $(BINDIR) $(DSADMIN_SO) + +dummy: + -@echo PERL_EXE = $(PERL_EXE) + -@echo PERL_EXENT = $(PERL_EXENT) + -@echo PERL_BASEDIR = $(PERL_BASEDIR) + -@echo PERL_ROOT = $(PERL_ROOT) + -@echo IS_ACTIVESTATE = $(IS_ACTIVESTATE) + -@echo PERL_CONFIG = $(PERL_CONFIG) + -@echo PERL_ROOT = $(PERL_ROOT) + -@echo PERL = $(PERL) + -@echo PERL_LIB = $(PERL_LIB) + -@echo PERL_ARCHLIB = $(PERL_ARCHLIB) + -@echo EXTRA_LIBS_DEP = $(EXTRA_LIBS_DEP) + abort + +ifeq ($(ARCH), WINNT) +$(DSADMIN_SO): $(OBJS) $(EXTRA_LIBS_DEP) $(DEF_FILE) + $(LINK_DLL) /DEF:$(DEF_FILE) +# linking this file causes a .exp and a .lib file to be generated which don't seem +# to be required while running, so I get rid of them + $(RM) $(subst .dll,.exp,$@) $(subst .dll,.lib,$@) +else +$(DSADMIN_SO): $(OBJS) + $(LINK_DLL) $(EXTRA_LIBS) +endif + +$(OBJDEST)/DSAdmin.o: $(OBJDEST)/DSAdmin.c +ifeq ($(ARCH), WINNT) + $(CC) -c $(CFLAGS) $(PERL_CFLAGS) $(MCC_INCLUDE) $(SETUPSDK_INCLUDE) $(PERL_INC) $< $(OFFLAG)$@ +else + $(CXX) $(EXCEPTIONS) -c $(CFLAGS) $(PERL_CFLAGS) $(MCC_INCLUDE) $(SETUPSDK_INCLUDE) $(PERL_INC) $< $(OFFLAG)$@ +endif + +$(OBJDEST)/DSAdmin.c: DSAdmin.xs + $(PERL) -w -I$(PERL_ARCHLIB) -I$(PERL_LIB) $(XSUBPP) $(XSPROTOARG) $(XSUBPPARGS) $< > $@ + +#MYCMD := "Mksymlists('NAME' => 'DSAdmin', 'DLBASE' => 'DSAdmin');" +#$(DEF_FILE): DSAdmin.xs +# $(PERL) -w "-I$(PERL_ARCHLIB)" "-I$(PERL_LIB)" -MExtUtils::Mksymlists -e "$(MYCMD)" + +clean: + -$(RM) $(OBJDEST)/DSAdmin.c $(OBJS) $(DSADMIN_SO) diff --git a/ldap/admin/src/DSAdmin.pm b/ldap/admin/src/DSAdmin.pm new file mode 100644 index 00000000..a8578a32 --- /dev/null +++ b/ldap/admin/src/DSAdmin.pm @@ -0,0 +1,225 @@ +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +package DSAdmin; + +use POSIX; + +use strict; +use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $AUTOLOAD +$isNT $PATHSEP $quote $script_suffix $exe_suffix $os +$dll_suffix $argumentative @args $first $rest $errs $pos +); + +require Exporter; +require DynaLoader; +require AutoLoader; + +@ISA = qw(Exporter DynaLoader); +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. + +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. +@EXPORT = qw( + normalizeDN toLocal toUTF8 +); +$VERSION = '1.00'; + +bootstrap DSAdmin $VERSION; + +BEGIN { + require 'uname.lib'; + $isNT = -d '\\'; +# @INC = ( '.', '../../../admin/admin/bin' ); +# grep { s@/@\\@g } @INC if $isNT; + $PATHSEP = $isNT ? '\\' : '/'; + # NT needs quotes around some things unix doesn't + $quote = $isNT ? "\"" : ""; + + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + if ($isNT) { + $os = "WINNT"; + } else { + $os = &uname("-s"); + } + + # dll suffix for shared libraries in old instance; note that the dll suffix + # may have changed for the new instance e.g. AIX now uses .so + if ( $os eq "AIX" ) { + $dll_suffix = "_shr.a"; + } + elsif ( $os eq "HP-UX" ) { + $dll_suffix = ".sl"; + } + elsif ( $os eq "WINNT" ) { + $dll_suffix = ".dll"; + } + else { + $dll_suffix = ".so"; + } +} + +sub getCwd { + my $command = $isNT ? "cd" : "/bin/pwd"; + open(PWDCMD, "$command 2>&1 |") or + die "Error: could not execute $command: $!"; + # without the following sleep, reading from the pipe will + # return nothing; I guess it gives the pwd command time + # to get some data to read . . . + sleep(1); + my $curdir; + while (<PWDCMD>) { + if (!$curdir) { + chomp($curdir = $_); + } + } + my $code = close(PWDCMD); +# if ($code || $?) { +# print "$command returned code=$code status=$? dir=$curdir\n"; +# } +# print "getCwd curdir=\[$curdir\]\n"; + return $curdir; +} + +# this is used to run the system() call, capture exit and signal codes, +# and die() upon badness; the first argument is a directory to change +# dir to, if any, and the rest are passed to system() +sub mySystem { + my $rc = &mySystemNoDie(@_); + my ($dir, @args) = @_; + if ($rc == 0) { +# success + } elsif ($rc == 0xff00) { + die "Error executing @args: error code $rc: $!"; + } elsif ($rc > 0x80) { + $rc >>= 8; + die "Error executing @args: error code $rc: $!"; + } else { + if ($rc & 0x80) { + $rc &= ~0x80; + } + die "Error executing @args: received signal $rc: $!"; + } + + # usually won't get return value + return $rc; +} + +# This version does not die but just returns the error code +sub mySystemNoDie { + my ($dir, @args) = @_; + if ($dir && ($dir ne "")) { + chdir($dir) or die "Could not change directory to $dir: $!"; + } + my $cmd = $args[0]; + # the system {$cmd} avoids some NT shell quoting problems if the $cmd + # needs to be quoted e.g. contains spaces; the map puts double quotes + # around the arguments on NT which are stripped by the command + # interpreter cmd.exe; but don't quote things which are already quoted + my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @args; + my $rc = 0; + if ($cmd =~ /[.](bat|cmd)$/) { + # we have to pass batch files directly to the NT command interpreter + $cmd = $ENV{COMSPEC}; + if (!$cmd) { + $cmd = 'c:\winnt\system32\cmd.exe'; + } +# print "system $cmd /c \"@fixargs\"\n"; + $rc = 0xffff & system {$cmd} '/c', "\"@fixargs\""; + } else { + print "system $cmd @fixargs\n"; + $rc = 0xffff & system {$cmd} @fixargs; + } + return $rc; +} + +sub getTempFileName { + my $tmp = tmpnam(); + while (-f $tmp) { + $tmp = tmpnam(); + } + + return $tmp; +} + +sub getopts { + local($argumentative) = @_; + local(@args,$_,$first,$rest); + local($errs) = 0; + local($[) = 0; + + @args = split( / */, $argumentative ); + while(@ARGV && ($_ = $ARGV[0]) =~ /^-(.)(.*)/) { + ($first,$rest) = ($1,$2); + $pos = index($argumentative,$first); + if($pos >= $[) { + if($args[$pos+1] eq ':') { + shift(@ARGV); + if($rest eq '') { + ++$errs unless @ARGV; + $rest = shift(@ARGV); + } + eval "\$main::opt_$first = \$rest;"; + } + else { + eval "\$main::opt_$first = 1"; + if($rest eq '') { + shift(@ARGV); + } + else { + $ARGV[0] = "-$rest"; + } + } + } + else { + print STDERR "Unknown option: $first\n"; + ++$errs; + if($rest ne '') { + $ARGV[0] = "-$rest"; + } + else { + shift(@ARGV); + } + } + } + $errs == 0; +} + +# Autoload methods go after =cut, and are processed by the autosplit program. + +1; +__END__ +# Below is the stub of documentation for your module. You better edit it! + +=head1 NAME + +DSAdmin - Perl extension for directory server administrative utility functions + +=head1 SYNOPSIS + + use DSAdmin; + +=head1 DESCRIPTION + +The DSAdmin module is used by directory server administration scripts, such as +those used for installation/uninstallation, instance creation/removal, CGIs, +etc. + +=head1 AUTHOR + +Richard Megginson richm@netscape.com + +=head1 SEE ALSO + +perl(1). + +=cut diff --git a/ldap/admin/src/DSAdmin.xs b/ldap/admin/src/DSAdmin.xs new file mode 100644 index 00000000..22d862ce --- /dev/null +++ b/ldap/admin/src/DSAdmin.xs @@ -0,0 +1,76 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + This file contains the definitions of C functions callable from perl. + The perl interface for these functions is found in DSAdmin.pm. +*/ + +#include "dsalib.h" + +#include "nsutils.h" +#include "utf8.h" + +/* these are the perl include files needed */ +#ifdef __cplusplus +extern "C" { +#endif +#include "EXTERN.h" +/* The next two lines are hacks because someone build perl with gcc which +has this feature call __attribute__ which is not present with sun cc */ +#define HASATTRIBUTE +#define __attribute__(_attr_) + +#ifdef HPUX11 /* conflict with perl 'struct magic' and hpux 'struct magic' */ +#define magic p_magic +#define MAGIC p_MAGIC +#endif /* HPUX */ + +#include "perl.h" +#include "XSUB.h" +#ifdef __cplusplus +} +#endif + + +MODULE = DSAdmin PACKAGE = DSAdmin + +PROTOTYPES: DISABLE + +SV * +normalizeDN(dn) + char* dn + PREINIT: + char* temp_dn; + CODE: + /* duplicate the DN since dn_normalize_convert modifies the argument */ + temp_dn = (char *)malloc(strlen(dn) + 1); + strcpy(temp_dn, dn); + ST(0) = sv_newmortal(); + /* dn_normalize_convert returns its argument */ + sv_setpv( ST(0), dn_normalize_convert(temp_dn) ); + free(temp_dn); + +SV * +toLocal(s) + char* s + PREINIT: + char* temp_s; + CODE: + temp_s = UTF8ToLocal(s); + ST(0) = sv_newmortal(); + sv_setpv( ST(0), temp_s ); + nsSetupFree(temp_s); + +SV * +toUTF8(s) + char* s + PREINIT: + char* temp_s; + CODE: + temp_s = localToUTF8(s); + ST(0) = sv_newmortal(); + sv_setpv( ST(0), temp_s ); + nsSetupFree(temp_s); diff --git a/ldap/admin/src/Inf.pm b/ldap/admin/src/Inf.pm new file mode 100644 index 00000000..41d6458a --- /dev/null +++ b/ldap/admin/src/Inf.pm @@ -0,0 +1,243 @@ +#!perl +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +package NSSetupSDK::Inf; + +use NSSetupSDK::Base; + +%otherEnc = ('local' => "utf8", utf8 => "local"); +# mapping of encoding to the subroutine which converts from that encoding +%convertEnc = ('local' => \&toUTF8, utf8 => \&toLocal); + +############################################################################# +# Creator, the argument (optional) is the INF file to read +# +sub new { + my ($class, $filename) = @_; + my $self = {}; + + bless $self, $class; + + if ($filename) { + $self->read($filename); + } + + return $self; +} + +############################################################################# +# Read in and initialize ourself with the given INF file. The file will be +# encoded in either local or utf8 encoding. The type of encoding is given +# in the $enc argument. We first read in the values in the given encoding, +# then convert the file to the other encoding, then read in and initialize +# the values for the other encoding +# +sub read { + my ($self, $filename, $enc) = @_; + my $inf = {}; # the contents of the inf file + my @sectionList = (); # a list of section names, in order + my $sectionName = "General"; # default section name + + open INF, $filename or return undef; + + push @sectionList, $sectionName; + while (<INF>) { + next if /^\s*#/; # skip comments + next if /^\s*$/; # skip blank lines + if (/^\s*\[([^\]]+)\]/) { + $sectionName = $1; # new section + if ($sectionName cmp "General") { + # General is already in the list + push @sectionList, $sectionName; + } + } else { + chop; + ($name, $value) = split(/\s*=\s*/, $_, 2); +# print "name=$name value=$value\n"; + $inf->{$sectionName}{$enc}{$name} = $value; + $inf->{$sectionName}{$otherEnc{$enc}}{$name} = + &{$convertEnc{$enc}}($value); + } + } + close INF; + + $self->{inf} = $inf; + $self->{sections} = [ @sectionList ]; + +# foreach $section (keys %inf) { +# print '[', $section, ']', "\n"; +# foreach $name (keys %{ $inf{$section} }) { +# print "local $name=$inf{$section}{local}{$name}\n"; +# print "UTF8 $name=$inf{$section}{utf8}{$name}\n"; +# } +# } + + return 1; +} + +sub readLocal { + my $self = shift; + return $self->read(@_, 'local'); +} + +sub readUTF8 { + my $self = shift; + return $self->read(@_, 'utf8'); +} + +############################################################################# +# Init from a hash; used to create a subsection as another inf +# +sub init { + my ($self, $hashRef) = @_; + my $inf = {}; + $inf->{General} = $hashRef; + $self->{inf} = $inf; + $self->{sections} = [ "General" ]; + + return 1; +} + +############################################################################# +# return the number of sections +# +sub numSections { + my $self = shift; + return scalar(@{$self->{sections}}); +} + +############################################################################# +# return the section corresponding to the given name or number +# +sub getSection { + my ($self, $section) = @_; + if ($section =~ /\d+/) { # section is a number + $section = $self->{sections}->[$section]; + } + + my $newSec = new Inf; + $newSec->init($self->{inf}->{$section}); + return $newSec; +} + +############################################################################# +# return the value of the given name in local encoding +# +sub getLocal { + my ($self, $name) = @_; + return getFromSection($self, "General", $name, "local"); +} + +############################################################################# +# return the value of the given name in UTF8 encoding +# +sub getUTF8 { + my ($self, $name) = @_; + return getFromSection($self, "General", $name, "utf8"); +} + +############################################################################# +# return the value of the given name in UTF8 encoding +# +sub get { + my ($self, $name) = @_; + return getFromSection($self, "General", $name, "utf8"); +} + +############################################################################# +# return the value of the given name in the given section +# +sub getFromSection { + my ($self, $section, $name, $enc) = @_; +# print "self inf = ", %{ $self->{inf} }, "\n"; +# print "self inf section = ", %{ $self->{inf}->{$section} }, "\n"; + return $self->{inf}->{$section}{$enc}{$name}; +} + +############################################################################# +# set the value +# +sub setInSection { + my ($self, $section, $name, $value, $enc) = @_; + if (!$enc) { + $enc = 'utf8'; + } + $self->{inf}->{$section}{$enc}{$name} = $value; + $self->{inf}->{$section}{$otherEnc{$enc}}{$name} = + &{$convertEnc{$enc}}($value); +} + +############################################################################# +# set the value; value is locally encoded +# +sub setLocal { + my ($self, $name, $value) = @_; + setInSection($self, "General", $name, $value, "local"); +} + +############################################################################# +# set the value; value is UTF-8 encoded +# +sub setUTF8 { + my ($self, $name, $value) = @_; + setInSection($self, "General", $name, $value, "utf8"); +} + +############################################################################# +# set the value, assume UTF-8 encoding +# +sub set { + my ($self, $name, $value) = @_; + setInSection($self, "General", $name, $value, "utf8"); +} + +sub write { + my ($self, $ref, $enc) = @_; + my $needClose = undef; + if (!$enc) { + $enc = "local"; # write file in local encoding by default + } + if (!$ref) { + # no filehandle given + $ref = \*STDOUT; + } elsif (!ref($ref)) { # not a ref, assume scalar filename + # filename + open(OUTPUT, ">$ref") or die "Error: could not write file $ref: $!"; + $ref = \*OUTPUT; + $needClose = 1; # be sure to close + } elsif (ref($ref) eq 'SCALAR') { + # filename + open(OUTPUT, ">$$ref") or die "Error: could not write file $$ref: $!"; + $ref = \*OUTPUT; + $needClose = 1; # be sure to close + } # else already a file handle ref + foreach $secName (@{ $self->{sections} }) { + print $ref "[", $secName, "]\n"; + foreach $name (keys %{ $self->{inf}->{$secName}{$enc} }) { + $value = $self->{inf}->{$secName}{$enc}{$name}; + print $ref $name, "=", $value, "\n"; + } + print $ref "\n"; + } + if ($needClose) { + close $ref; + } +} + +sub writeLocal { + my ($self, $ref) = @_; + $self->write($ref, 'local'); +} + +sub writeUTF8 { + my ($self, $ref) = @_; + $self->write($ref, 'utf8'); +} + +1; # the mandatory TRUE return from the package diff --git a/ldap/admin/src/Makefile b/ldap/admin/src/Makefile new file mode 100644 index 00000000..e3343791 --- /dev/null +++ b/ldap/admin/src/Makefile @@ -0,0 +1,304 @@ +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +# Source for the admin forms and CGI programs + +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) + +BINDIR=$(LDAP_ADMIN_BIN_RELDIR) +OBJDEST=$(LDAP_ADMOBJDIR) + +SCRIPTSDIR=$(LDAP_BASE_RELDIR)/admin/scripts + +include $(MCOM_ROOT)/ldapserver/nsconfig.mk +include $(LDAP_SRC)/nsldap.mk +ifndef LDAP_USE_OLD_DB +include $(MCOM_ROOT)/ldapserver/ns_usedb.mk +endif + +MCC_INCLUDE += $(ADMINUTIL_INCLUDE) + +INCLUDES += -I$(LDAP_SRC)/admin/include + +DS_SERVER_DEFS = -DNS_DS + +ifneq ($(ARCH), WINNT) +EXTRALDFLAGS += $(SSLLIBFLAG) +endif + +ifeq ($(BUILD_DLL), yes) +DYNAMIC_DEPLIBS=$(LDAP_ADMLIB) $(LDAP_COMMON_LIBS_DEP) $(ADMINUTIL) +DYNAMIC_DEPLINK=$(DYNAMIC_DEPLIBS) +else +DYNAMIC_DEPLIBS=$(LDAP_COMMON_LIBS_DEP) +DYNAMIC_DEPLINK=$(LDAP_ADMLIB) $(LDAP_COMMON_LIBS) +endif + +EXTRA_LIBS_DEP += $(NSPR_DEP) $(LDAPSDK_DEP) $(ADMINUTIL_DEP) $(ICU_DEP) + +# we don't want to build with warnings-as-errors for the admin/ stuff, because +# it's got crappy C++ code which is LITTERED with warnings, most of which we +# can't fix because it comes from files in dist/, etc. +ifeq ($(ARCH), Linux) +CFLAGS := $(subst -Werror,,$(CFLAGS)) +endif + +OLD_EXTRA_LIBS := $(EXTRA_LIBS) +EXTRA_LIBS = $(DYNAMIC_DEPLINK) $(ADMINUTIL_LINK) $(LDAP_NOSSL_LINK) \ + $(SECURITYLINK) $(NSPRLINK) $(SETUPSDK_S_LINK) $(ICULINK) $(OLD_EXTRA_LIBS) + +ifeq ($(ARCH), WINNT) +PLATFORM_INCLUDE = -I$(MCOM_ROOT)/ldapserver/include/nt +SUBSYSTEM=console +EXTRA_LIBS+=comctl32.lib $(LDAP_LIBUTIL) +EXTRA_LIBS_DEP+=$(LDAP_LIBUTIL_DEP) + +ifeq ($(DEBUG), optimize) +#NT_NOLIBS = /NODEFAULTLIB:LIBCMT /NODEFAULTLIB:MSVCRT +else +NT_NOLIBS = /NODEFAULTLIB:LIBCMTD /NODEFAULTLIB:MSVCRTD +endif + +else +ifeq ($(ARCH), IRIX) +EXCEPTIONS=-exceptions +else +ifeq ($(ARCH),SOLARIS) +ifeq ($(USE_64), 1) +EXTRALDFLAGS += -xarch=v9 +endif +EXTRA_LIBS += -lsocket -lnsl -lgen -lm -lposix4 -lthread +else +ifeq ($(ARCH),SOLARISx86) +EXTRA_LIBS += -lsocket -lnsl -lgen -lm -lposix4 -lthread +else +ifeq ($(ARCH),HPUX) +ifdef FORTEZZA +# link with libci.a for FORTEZZA builds. On other platforms, libci.a is +# linked into libds_admin.so, but not on HPUX +EXTRA_LIBS_DEP += $(FORTEZZA_DRIVER) +EXTRA_LIBS += $(FORTEZZA_DRIVER) +endif +ifeq ($(USE_64), 1) +EXTRALDFLAGS += +DA2.0W +DS2.0 +Z +endif +else +ifeq ($(ARCH),OSF1) +#CC += -E +#CXX += -Wl,-ymain +else +ifeq ($(ARCH),ReliantUNIX) +else +ifeq ($(ARCH), AIX) +EXTRA_LIBS += -lcurses +else +ifeq ($(ARCH), UnixWare) +# rgc: +EXTRA_LIBS += -lsocket -lnsl -lgen -lm +else +ifeq ($(ARCH), Linux) +EXTRA_LIBS += -lcrypt +else +#this will help with porting other platforms +EXTRA_LIBS+="you need to define EXTRA_LIBS for $(ARCH) in ldapserver/ldap/admin/src/Makefile" +endif # Linux +endif # UnixWare +endif # AIX +endif # ReliantUNIX +endif # OSF1 +endif # HPUX +endif # SOLARISx86 +endif # SOLARIS +endif # IRIX +endif # WINNT + +TEMP_EXTRALDFLAGS:=$(EXTRALDFLAGS) +EXTRALDFLAGS = -lpthread $(TEMP_EXTRALDFLAGS) + +ifeq ($(SECURITY),domestic) +SECUS_BINS= +MODULE_CFLAGS += -DUS_VERSION -DEXPORT_VERSION +endif + +ifeq ($(SECURITY),export) +MODULE_CFLAGS += -DEXPORT_VERSION +endif + +ifneq ($(SECURITY),none) +SECURE_BINS= +SECLIB=$(LIBSECURITY) +endif + +ADMIN_DLLGLUEOBJ=$(MCOM_ROOT)/ldapserver/built/$(ARCH)-$(SECURITY)-$(DEBUG)-admin/admin-lib/dllglue.o + +ifeq ($(ARCH),AIX) +DLLGLUEOBJ= +GLUEOBJS= +endif + +$(OBJDEST)/key.res: key.rc + $(RC) $(OFFLAG)$(OBJDEST)/key.res ey.rc + +OLD_PROGS = ds_pcontrol ds_impldif \ + ds_backldif ds_backdb ds_restdb \ + ds_monitor ds_conf ds_rmldif \ + commit index ds_acccon ds_perf ds_dbconf ds_conf_check \ + ds_net ds_ldap ds_pwconf ds_inconf ds_grplst ds_grpcrt \ + ds_version ds_client ds_secpref ds_secact instindex \ + ds_reploc ds_repinit ldif2replica ds_addldif ds_ldif2ldap clpstat \ + ds_sscfg ds_attr_manage ds_oc_view ds_oc_create ds_schema_update \ + ds_replov ds_pw ds_snmpconf + +PROGS = start restart shutdown ds_ldif2db \ + ds_db2ldif ds_db2bak ds_listdb \ + ds_bak2db ds_rmdb ds_create \ + ds_remove ds_snmpctrl vlvindex addindex + +ifeq ($(ARCH), WINNT) +SERVER_PROGS = namegen latest_file +endif + +OBJECTS= init_ds_env.o + +ifeq ($(ARCH), WINNT) +OBJECTS += namegen.o latest_file.o ds_remove_uninst.o +endif + +ifeq ($(ARCH), WINNT) +BINS = $(addprefix $(BINDIR)/, $(addsuffix .exe, $(PROGS))) $(addprefix $(LDAP_SERVER_RELDIR)/, $(addsuffix .exe, $(SERVER_PROGS))) +else +BINS = $(addprefix $(BINDIR)/, $(PROGS)) +endif +ALLOBJS = $(addprefix $(OBJDEST)/, $(OBJECTS)) + +PERL_SCRIPTS = migrateTo4 uname.lib Cgi.pm migrateInstance getConfigInfo migrateLocalDB migratePwdFile ds_viewlog.pl upgradeServer updatedsgw + +PERL_SCRIPTS_DEST = $(addprefix $(BINDIR)/, $(PERL_SCRIPTS)) + +INST_INCLUDES = $(OBJDIR)/install_keywords.h + +TEMPLATE_SCRIPTS_SRC = $(wildcard scripts/template-*) +TEMPLATE_SCRIPTS_DEST = $(subst scripts/,$(SCRIPTSDIR)/,$(TEMPLATE_SCRIPTS_SRC)) + +# gmake 3.74 will remove "intermediate" files if generated via a pattern match rule +# this is annoying for debugging since it tries to find the .o file +# if you're debugging and you want to make sure your file does not get removed +# by gmake, just uncomment the precious target and put your object files there +# or FIX IT! if you can figure out how . . . +#.PRECIOUS: $(OBJDEST)/ds_db2bak.o + +all: $(BINDIR) $(OBJDEST) $(INST_INCLUDES) $(ALLOBJS) $(BINS) \ + installPerlFiles $(SCRIPTSDIR) $(TEMPLATE_SCRIPTS_DEST) + +$(SCRIPTSDIR): + $(MKDIR) $@ + +.PHONY: installPerlFiles + +#NSSetupSDK: +# $(MAKE) -f NSSetupSDK_Base.mk $(MFLAGS) all + +clean: + -@echo $(BINS) + -$(RM) $(BINS) + -$(RM) $(OBJDEST)/*.o + +strip: + $(STRIP) $(BINS) + +# if $(DLLGLUEOBJ) isn't available, use $(ADMIN_DLLGLUEOBJ) as a substitute: +$(DLLGLUEOBJ): $(ADMIN_DLLGLUEOBJ) + cp $(ADMIN_DLLGLUEOBJ) $(DLLGLUEOBJ) + +# if $(SECGLUEOBJ) isn't available, use $(ADMIN_SECGLUEOBJ) as a substitute: +$(SECGLUEOBJ): $(ADMIN_SECGLUEOBJ) + cp $(ADMIN_SECGLUEOBJ) $(SECGLUEOBJ) + +# Special objects + +$(BINDIR)/ds_create: $(OBJDEST)/instindex.o $(OBJDEST)/cfg_sspt.o \ + $(OBJDEST)/create_instance.o $(OBJDEST)/configure_instance.o \ + $(OBJDEST)/script-gen.o $(DEPLIBS) + $(LINK_EXE_NOLIBSOBJS) $(SHARED) $(EXTRALDFLAGS) \ + $(OBJDEST)/instindex.o $(OBJDEST)/script-gen.o \ + $(OBJDEST)/create_instance.o $(OBJDEST)/cfg_sspt.o \ + $(OBJDEST)/configure_instance.o \ + $(GLUEOBJ) $(EXTRA_LIBS) + +$(BINDIR)/ds_create.exe: $(OBJDEST)/instindex.o $(OBJDEST)/cfg_sspt.o \ + $(OBJDEST)/create_instance.o $(OBJDEST)/configure_instance.o \ + $(OBJDEST)/script-gen.o $(LIBNT_DEP) $(DEPLIBS) + $(LINK_EXE) $(NT_NOLIBS) $(OBJDEST)/instindex.o \ + $(OBJDEST)/create_instance.o $(OBJDEST)/cfg_sspt.o \ + $(OBJDEST)/configure_instance.o $(OBJDEST)/script-gen.o \ + $(SETUPSDK_S_LINK) $(LDAP_SDK_LIBS) $(LIBNT) \ + $(NSPRLINK) $(EXTRA_LIBS) $(DB_LIB) +# linking this file causes a .exp and a .lib file to be generated which don't seem +# to be required while running, so I get rid of them + $(RM) $(subst .exe,.exp,$@) $(subst .exe,.lib,$@) + +$(BINDIR)/ds_remove: $(OBJDEST)/ds_remove.o $(OBJDEST)/ds_remove_uninst.o $(DEPLIBS) $(EXTRA_LIBS_DEP) + $(LINK_EXE_NOLIBSOBJS) $(SHARED) $(EXTRALDFLAGS) \ + $(OBJDEST)/ds_remove.o $(OBJDEST)/ds_remove_uninst.o $(OBJDEST)/init_ds_env.o \ + $(SETUPSDK_S_LINK) $(GLUEOBJ) $(EXTRA_LIBS) + +$(BINDIR)/ds_remove.exe: $(OBJDEST)/ds_remove.o $(OBJDEST)/ds_remove_uninst.o $(DEPLIBS) $(EXTRA_LIBS_DEP) + $(LINK_EXE) $(OBJDEST)/ds_remove_uninst.o $(OBJDEST)/ds_remove.o $(OBJDEST)/init_ds_env.o $(LDAP_SDK_LIBS) $(NSPRLINK) $(SETUPSDK_S_LINK) $(NT_NOLIBS) +# linking this file causes a .exp and a .lib file to be generated which don't seem +# to be required while running, so I get rid of them + $(RM) $(subst .exe,.exp,$@) $(subst .exe,.lib,$@) + +$(OBJDEST)/%.o: %.c + $(CC) -c $(CFLAGS) $(MCC_INCLUDE) $< $(OFFLAG)$@ + +$(OBJDEST)/%.o: %.cpp +ifeq ($(ARCH), WINNT) + $(CC) -c $(CFLAGS) $(MCC_INCLUDE) $(SETUPSDK_INCLUDE) $< $(OFFLAG)$@ +else + $(CXX) $(EXCEPTIONS) -c $(CFLAGS) $(MCC_INCLUDE) $(SETUPSDK_INCLUDE) $< $(OFFLAG)$@ +endif + +ifneq ($(ARCH), WINNT) +$(BINDIR)/%: $(OBJDEST)/%.o $(DEPLIBS) $(EXTRA_LIBS_DEP) $(GLUEOBJ) + $(LINK_EXE_NOLIBSOBJS) $< $(OBJDEST)/init_ds_env.o $(GLUEOBJ) $(EXTRA_LIBS) +else +$(BINDIR)/%.exe: $(OBJDEST)/%.o $(DEPLIBS) $(EXTRA_LIBS_DEP) + $(LINK_EXE) $(OBJDEST)/$*.o $(OBJDEST)/init_ds_env.o $(NSPRLINK) +endif + +$(LDAP_SERVER_RELDIR)/namegen.exe: $(OBJDEST)/namegen.o + $(LINK_EXE_NOLIBSOBJS) $^ + +$(LDAP_SERVER_RELDIR)/latest_file.exe: $(OBJDEST)/latest_file.o + $(LINK_EXE_NOLIBSOBJS) $^ + +installPerlFiles: $(BINDIR) $(BINDIR)/Install.pl + +$(BINDIR)/Install.pl: CreateInstall.pl $(PERL_SCRIPTS_DEST) + -@$(RM) $@ + $(CP) $< $@ + +$(BINDIR)/%: % + -@$(RM) $@ + $(CP) $< $@ + +$(LDAP_SERVER_RELDIR)/%: % $(LDAP_SERVER_RELDIR) + -@$(RM) $@ + $(CP) $< $@ + +$(INST_INCLUDES): install_keywords.h + -@$(RM) $@ + $(CP) $< $@ + +$(SCRIPTSDIR)/template-%: scripts/template-% $(SCRIPTSDIR) + -@$(RM) $@ + $(CP) $< $@ diff --git a/ldap/admin/src/addindex.c b/ldap/admin/src/addindex.c new file mode 100644 index 00000000..7e9e2671 --- /dev/null +++ b/ldap/admin/src/addindex.c @@ -0,0 +1,80 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * addindex.c: Creates one or more indexes for specified attributes + * + * Rob Weltman + */ + +#include <stdio.h> +#include <stdlib.h> +#include "libadminutil/admutil.h" +#include "dsalib.h" +#include "init_ds_env.h" +#include <string.h> + +int main(int argc, char *argv[]) +{ + int status; + char *attributes; + char *attrs; + char **attrList; + int nAttrs; + char *nextAttr = NULL; + char *backendName; + + + fprintf(stdout, "Content-type: text/html\n\n"); + + if ( init_ds_env() ) + return 1; + + /* + * Get value of the "attributes" variable. + */ + attributes = ds_get_cgi_var("attributes"); + if ( (NULL == attributes) || (strlen(attributes) < 1) ) { + rpt_err( DS_UNDEFINED_VARIABLE, "attributes", NULL, NULL ); + return 1; + } + + + backendName = ds_get_cgi_var("backendID"); + if ( (NULL == backendName) || (strlen(backendName) < 1) ) { + rpt_err( DS_UNDEFINED_VARIABLE, "backendName", NULL, NULL ); + return 1; + } + + + attrs = strdup( attributes ); + /* Allocate for worst possible case */ + attrList = (char **)malloc(sizeof(*attrList) * (strlen(attrs)+1)); + nAttrs = 0; + /* strtok() is not MT safe, but it is okay to call here because this is a command line */ + attrList[nAttrs++] = strtok( attrs, " " ); + do { + nextAttr = strtok( NULL, " " ); + attrList[nAttrs++] = nextAttr; + } while( nextAttr != NULL ); + + ds_send_status((nAttrs > 1) ? "Creating indexes ..." : + "Creating index ..."); + + status = ds_addindex( attrList, backendName ); + + if ( !status ) { + rpt_success((nAttrs > 1) ? "Success! The indexes have been created." : + "Success! The index has been created."); + status = 0; + } else { + char msg[BIG_LINE]; + sprintf( msg,"[%s] %s", backendName, attributes); + rpt_err( status, msg, NULL, NULL ); + status = 1; + } + + return status; +} diff --git a/ldap/admin/src/cfg_sspt.c b/ldap/admin/src/cfg_sspt.c new file mode 100644 index 00000000..2ff883d3 --- /dev/null +++ b/ldap/admin/src/cfg_sspt.c @@ -0,0 +1,1621 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <assert.h> +#include "ldap.h" +#include "dsalib.h" +#include "nspr.h" +#include "plstr.h" +#include <string.h> + +#define __CFG_SSPT_C + +#include "cfg_sspt.h" + +/*#define CGI_DEBUG 1*/ + +#define TEST_CONFIG /* for testing cn=config40 dummy entry instead of real one */ + +char* const class_top = "top"; +char* const class_organization = "organization"; +char* const class_organizationalUnit = "organizationalunit"; +char* const class_person = "person"; +char* const class_organizationalPerson = "organizationalperson"; +char* const class_inetOrgPerson = "inetorgperson"; +char* const class_groupOfUniqueNames = "groupofuniquenames"; +char* const class_domain = "domain"; +char* const class_extensibleObject = "extensibleObject"; +char* const class_adminDomain = "nsadmindomain"; +char* const class_country = "country"; +char* const class_locality = "locality"; + +char* const name_objectClass = "objectclass"; +char* const name_cn = "cn"; +char* const name_sn = "sn"; +char* const name_givenname = "givenname"; +char* const name_uid = "uid"; +char* const name_userPassword = "userpassword"; +char* const name_passwordExpirationTime = "passwordExpirationTime"; +char* const name_o = "o"; +char* const name_ou = "ou"; +char* const name_dc = "dc"; +char* const name_member = "member"; +char* const name_uniqueMember = "uniquemember"; +char* const name_aci = "aci"; +char* const name_description = "description"; +char* const name_adminDomain = "nsadmindomainname"; +char* const name_c = "c"; +char* const name_st = "st"; +char* const name_l = "l"; + +char* const value_configAdminGroupCN = "Configuration Administrators"; +char* const value_configAdminGroupRDN = "cn=Configuration Administrators"; +char* const value_configAdminCN = "Configuration Administrator"; +char* const value_configAdminSN = "Administrator"; +char* const value_configAdminGN = "Configuration"; +char* const value_globalPreferencesOU = "Global Preferences"; +char* const value_hostPreferencesOU = "Host Preferences"; +char* const value_netscapeConfigDesc = "Standard branch for configuration information"; +char* const value_peopleOU = "People"; +char* const value_peopleDesc = "Standard branch for people (uid) entries"; +char* const value_groupsOU = "Groups"; +char* const value_groupsDesc = "Standard Branch for group entries"; +#ifdef TEST_CONFIG +char* const value_config40 = "config40"; +char* const value_config40DN = "cn=config40"; +#endif /* TEST_CONFIG */ + +char* dbg_log_file = "ds_sscfg.log"; + +char* const name_netscaperoot = "NetscapeRoot"; +char* const name_netscaperootDN = "o=NetscapeRoot"; +char* const name_topology = "TopologyManagement"; +char* const name_topologyRDN = "ou=TopologyManagement"; +char* const value_topologyDESC = "Branch for Configuration Administration users and groups"; +char* const name_administratorsOU = "Administrators"; +char* const name_administratorsRDN = "ou=Administrators"; +char* const value_administratorsDESC = "Standard branch for Configuration Administrator (uid) entries"; +char* const name_localDAGroup = "Directory Administrators"; +char* const value_localDAGroupDesc = "Entities with administrative access to this directory server"; + +static char* const ACI_self_allow = "(targetattr=\"" + "carLicense ||" + "description ||" + "displayName ||" + "facsimileTelephoneNumber ||" + "homePhone ||" + "homePostalAddress ||" + "initials ||" + "jpegPhoto ||" + "labeledURL ||" + "mail ||" + "mobile ||" + "pager ||" + "photo ||" + "postOfficeBox ||" + "postalAddress ||" + "postalCode ||" + "preferredDeliveryMethod ||" + "preferredLanguage ||" + "registeredAddress ||" + "roomNumber ||" + "secretary ||" + "seeAlso ||" + "st ||" + "street ||" + "telephoneNumber ||" + "telexNumber ||" + "title ||" + "userCertificate ||" + "userPassword ||" + "userSMIMECertificate ||" + "x500UniqueIdentifier\")" + "(version 3.0; acl \"Enable self write for common attributes\"; allow (write) " + "userdn=\"ldap:///self\";)"; + +static char* const ACI_anonymous_allow = "(targetattr!=\"userPassword\")" + "(version 3.0; " + "acl \"Enable anonymous access\"; allow (read, search, compare)" + "userdn=\"ldap:///anyone\";)"; + +static char* const ACI_anonymous_allow_with_filter = + "(targetattr=\"*\")(targetfilter=(%s))" + "(version 3.0; acl \"Default anonymous access\"; " + "allow (read, search) userdn=\"ldap:///anyone\";)"; + +static char* const ACI_config_admin_group_allow_all = "(targetattr=\"*\")" + "(version 3.0; " + "acl \"Enable Configuration Administrator Group modification\"; " + "allow (all) groupdn=\"ldap:///%s, %s=%s, %s, %s\";)"; + +static char* const ACI_config_admin_group_allow = "(targetattr=\"*\")" + "(version 3.0; " + "acl \"Configuration Administrators Group\"; allow (%s) " + "groupdn=\"ldap:///%s\";)"; + +static char* const ACI_local_DA_allow = "(targetattr = \"*\")(version 3.0; " + "acl \"Local Directory Administrators Group\"; allow (%s) " + "groupdn=\"ldap:///%s\";)"; + +static char* const ACI_group_expansion = "(targetattr=\"*\")" + "(version 3.0; acl \"Enable Group Expansion\"; " + "allow (read, search, compare) groupdnattr=\"uniquemember\";)"; + +static char* const ACI_user_allow_1 = "(targetattr=\"*\")(version 3.0; " + "acl \"Configuration Administrator\"; allow (%s) " + "userdn=\"ldap:///uid=%s, %s\";)"; + +static char* const ACI_user_allow_2 = "(targetattr=\"*\")(version 3.0; " + "acl \"Configuration Administrator\"; allow (%s) " + "userdn=\"ldap:///%s\";)"; +/* + This is a list of DSE entries that the Configuration Admin Group has + access to and the access rights for that entry +*/ +static struct _DSEEntriesAndAccess { + char *entryDN; + char *access; +} entryAndAccessList[] = { + {"cn=config", "all"}, + {"cn=schema", "all"} +}; + +static int entryAndAccessListSize = + sizeof(entryAndAccessList)/sizeof(entryAndAccessList[0]); + +int +getEntryAndAccess(int index, const char **entry, const char **access) +{ + if (!entry || !access) + return 0; + + *entry = 0; + *access = 0; + + if (index < 0 || index >= entryAndAccessListSize) + return 0; + + *entry = entryAndAccessList[index].entryDN; + *access = entryAndAccessList[index].access; + + return 1; +} + +/* +** --------------------------------------------------------------------------- +** +** Utility Routines - Functions for performing string and file operations. +** +*/ + +#ifdef CGI_DEBUG +#include <stdarg.h> + +static void +debug_log (const char* file, const char* format, ...) +{ + va_list args; + FILE* fp = fopen(file, "a+"); + if (fp) { + va_start(args, format); + vfprintf(fp, format, args); + va_end(args); + fflush(fp); + fclose(fp); + } +} + +static void +debug_log_array (const char* file, char* name, char** vals) +{ + FILE* fp = fopen(file, "a+"); + + if (fp) { + if (vals != NULL) { + for (; *vals != NULL; LDAP_UTF8INC(vals)) { + fprintf (fp, "%s: %s\n", name, *vals); + } + fflush(fp); + } + fclose(fp); + } +} + +#endif /* CGI_DEBUG */ + +static char * +extract_name_from_dn(const char *dn) +{ + char **rdnList = 0; + char *ret = 0; + if (!dn) + return ret; + + rdnList = ldap_explode_dn(dn, 1); /* leave out types */ + if (!rdnList || !rdnList[0]) + ret = strdup(dn); /* the given dn is not really a dn */ + else + ret = strdup(rdnList[0]); + + if (rdnList) + ldap_value_free(rdnList); + + return ret; +} + +int +entry_exists(LDAP* ld, const char* entrydn) +{ + int exists = 0; + int err; + + struct timeval sto = { 10L, 0L }; + LDAPMessage* pLdapResult; + + err = ldap_search_st(ld, entrydn, LDAP_SCOPE_BASE, + "objectClass=*", NULL, 0, &sto, &pLdapResult); + + if (err == LDAP_SUCCESS) + { + LDAPMessage* pLdapEntry; + char* dn; + + for (pLdapEntry = ldap_first_entry(ld, pLdapResult); + pLdapEntry != NULL; + pLdapEntry = ldap_next_entry(ld, pLdapEntry)) + { + if ((dn = ldap_get_dn(ld, pLdapEntry)) != NULL) + { + exists = 1; + free(dn); + /*ldap_memfree(dn);*/ + break; + } + } + + ldap_msgfree(pLdapResult); + } + + return exists; +} + +int +add_aci(LDAP* ld, char* DN, char* privilege) +{ + int err; + int ret = 0; + LDAPMod mod; + LDAPMod* mods[2]; + char* aci[2]; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "add_aci('%s', '%s')\n", + DN ? DN : "NULL", + privilege ? privilege : "NULL"); +#endif + + if (ld == NULL || DN == NULL || privilege == NULL) + { + return -1; + } + + mods[0] = &mod; + mods[1] = NULL; + mod.mod_op = LDAP_MOD_ADD; + mod.mod_type = name_aci; + mod.mod_values = aci; + aci[0] = privilege; + aci[1] = NULL; + /* fprintf (stdout, "ldap_modify_s('%s')<br>\n",DN); fflush (stdout); */ + err = ldap_modify_s (ld, DN, mods); + if (err != LDAP_SUCCESS && err != LDAP_TYPE_OR_VALUE_EXISTS) { + char* exp = "can't add privilege. "; + char* format; + char* errmsg; + char* explanation; + format = "%s (%i) returned from ldap_modify_s(%s, %i). Privilege: %s"; + errmsg = ldap_err2string (err); + explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (DN) + 10 + strlen(aci[0])); + sprintf (explanation, format, errmsg, err, DN, LDAP_MOD_ADD, aci[0]); + ds_report_warning (DS_INCORRECT_USAGE, exp, explanation); + free (explanation); + ret = 1; + } + + return ret; +} + +/* + Same as add_aci, except that the 3rd parameter is a format string + in printf style format, and the 4th - Nth parameters are a NULL terminated + list of strings to substitute in the format; basically just constructs + the correct aci string and passes it to add_aci +*/ +int +add_aci_v(LDAP* ld, char* DN, char* format, ...) +{ + char* acistring = NULL; + int ii = 0; + int len = 0; + int status = 0; + int fudge = 10; /* a little extra just to make sure */ + char *s = 0; + va_list ap; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "add_aci_v('%s', '%s')\n", + DN ? DN : "NULL", + format ? format : "NULL"); +#endif + + if (ld == NULL || DN == NULL || format == NULL) + { + return -1; + } + + /* determine the length of the string to allocate to hold + the aci string + */ + len += strlen(format) + fudge; + va_start(ap, format); + s = va_arg(ap, char*); + while (s) + { + len += strlen(s) + 1; + s = va_arg(ap, char*); + } + va_end(ap); + + va_start(ap, format); + acistring = (char *)malloc(len); + vsprintf(acistring, format, ap); + va_end(ap); + status = add_aci(ld, DN, acistring); + + free(acistring); + + return status; +} + +/* + Make a dn from lists of dn components. The format argument is in the + standard printf format. The varargs list contains the various dn + components. The string returned is malloc()'d and must be free()'d by + the caller after use. example: + make_dn("cn=%s, ou=%s, %s", "Admins", "TopologyManagement", "o=NetscapeRoot", NULL) + returns + "cn=Admins, ou=TopologyManagement, o=NetscapeRoot" +*/ +char * +make_dn(const char* format, ...) +{ + char *s; + int len = 0; + int fudge = 3; + va_list ap; + char *dnstring; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "make_dn('%s', ...)\n", + format ? format : "NULL"); +#endif + + if (format == NULL) + { + return NULL; + } + + /* determine the length of the string to allocate to hold + the dn string + */ + len += strlen(format) + fudge; + va_start(ap, format); + s = va_arg(ap, char*); + while (s) + { + len += strlen(s) + 3; + s = va_arg(ap, char*); + } + va_end(ap); + + va_start(ap, format); + dnstring = (char *)malloc(len); + vsprintf(dnstring, format, ap); + va_end(ap); + + return dnstring; +} + +char * +admin_user_exists(LDAP* ld, char* base, char *userID) +{ + int exists = 0; + int err; + char search_str[MAX_STRING_LEN]; + + struct timeval sto = { 10L, 0L }; + LDAPMessage* pLdapResult; + sprintf (search_str, "uid=%s*", userID ? userID : "admin"); + + err = ldap_search_st(ld, base, LDAP_SCOPE_SUBTREE, + search_str, NULL, 0, &sto, &pLdapResult); + + if (err == LDAP_SUCCESS) + { + LDAPMessage* pLdapEntry; + char* dn = NULL; + + for (pLdapEntry = ldap_first_entry(ld, pLdapResult); + pLdapEntry != NULL; + pLdapEntry = ldap_next_entry(ld, pLdapEntry)) + { + if ((dn = ldap_get_dn(ld, pLdapEntry)) != NULL) + { + exists = 1; + /*ldap_memfree(dn);*/ + break; + } + } + + ldap_msgfree(pLdapResult); + return dn; + } + + return NULL; +} + +static void +getUIDFromDN(const char *userID, char *uid) +{ + char **rdnListTypes = 0; + char **rdnListNoTypes = 0; + int ii = 0; + int uidindex = -1; + uid[0] = 0; + + rdnListTypes = ldap_explode_dn(userID, 0); + if (!rdnListTypes) + return; /* userID is not a DN */ + + /* find the first rdn in the given userID DN which begins with + "uid=" */ + for (ii = 0; uidindex < 0 && rdnListTypes[ii]; ++ii) + { + if (!PL_strncasecmp(rdnListTypes[ii], "uid=", 4)) + uidindex = ii; + } + ldap_value_free(rdnListTypes); + + if (uidindex < 0) /* did not find an rdn beginning with "uid=" */ + return; + + rdnListNoTypes = ldap_explode_dn(userID, 1); + strcpy(uid, rdnListNoTypes[uidindex]); + ldap_value_free(rdnListNoTypes); + + return; +} + +static char * +create_ssadmin_user(LDAP* ld, char *base, char* userID, char* password) +{ + int err; + char *ret = 0; + char entrydn[1024] = {0}; + char realuid[1024] = {0}; + char *admin_dn = NULL; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "create_ssadmin_user('%s','%s','%s')\n", + base ? base : "NULL", userID ? userID : "NULL", + password ? password : "NULL"); +#endif + + if (ld == NULL || base == NULL || userID == NULL || *userID == '\0' || + password == NULL || *password == '\0') + { + return NULL; + } + + getUIDFromDN(userID, realuid); + if (realuid[0]) + { + sprintf(entrydn, userID); + if (entry_exists(ld, entrydn)) + admin_dn = entrydn; + } + else + { + sprintf(entrydn, "%s=%s, %s", name_uid, userID, base); + admin_dn = admin_user_exists(ld, base, userID); + strcpy(realuid, userID); + } + + if (admin_dn) + { + char error[BIG_LINE]; + sprintf(error, "A user with uid=%s \"%s\" already exists in the directory" + " and will not be overwritten.", realuid[0] ? realuid : "admin", admin_dn); + ds_send_error(error, 0); + return admin_dn; + } + else + { + LDAPMod* attrs[8]; + LDAPMod attr[7]; + char* objectClasses[5]; + char* cn[2]; + char* sn[2]; + char* givenname[2]; + char* uid[2]; + char* userPassword[2]; + char* passwordExpirationTime[2]; + + attrs[0] = &attr[0]; + attrs[1] = &attr[1]; + attrs[2] = &attr[2]; + attrs[3] = &attr[3]; + attrs[4] = &attr[4]; + attrs[5] = &attr[5]; + attrs[6] = &attr[6]; + attrs[7] = NULL; + attr[0].mod_op = LDAP_MOD_ADD; + attr[0].mod_type = name_objectClass; + attr[0].mod_values = objectClasses; + objectClasses[0] = class_top; + objectClasses[1] = class_person; + objectClasses[2] = class_organizationalPerson; + objectClasses[3] = class_inetOrgPerson; + objectClasses[4] = NULL; + attr[1].mod_op = LDAP_MOD_ADD; + attr[1].mod_type = name_cn; + attr[1].mod_values = cn; + cn[0] = value_configAdminCN; + cn[1] = NULL; + attr[2].mod_op = LDAP_MOD_ADD; + attr[2].mod_type = name_sn; + attr[2].mod_values = sn; + sn[0] = value_configAdminSN; + sn[1] = NULL; + attr[3].mod_op = LDAP_MOD_ADD; + attr[3].mod_type = name_givenname; + attr[3].mod_values = givenname; + givenname[0] = value_configAdminGN; + givenname[1] = NULL; + attr[4].mod_op = LDAP_MOD_ADD; + attr[4].mod_type = name_uid; + attr[4].mod_values = uid; + uid[0] = realuid; + uid[1] = NULL; + attr[5].mod_op = LDAP_MOD_ADD; + attr[5].mod_type = name_userPassword; + attr[5].mod_values = userPassword; + userPassword[0] = password; + userPassword[1] = NULL; + attr[6].mod_op = LDAP_MOD_ADD; + attr[6].mod_type = name_passwordExpirationTime; + attr[6].mod_values = passwordExpirationTime; + passwordExpirationTime[0] = "20380119031407Z"; + passwordExpirationTime[1] = NULL; + + /* fprintf (stdout, "ldap_add_s(%s)<br>\n", entrydn); fflush (stdout); */ + + err = ldap_add_s (ld, entrydn, attrs); + + if (err != LDAP_SUCCESS) + { + char* format = "Unable to create administrative user." + " (%s (%i) returned from ldap_add_s(%s))"; + char* errmsg = ldap_err2string (err); + char* explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (entrydn)); + sprintf (explanation, format, errmsg, err, entrydn); + ds_report_warning (DS_NETWORK_ERROR, " can't create user", explanation); + free (explanation); + ret = NULL; + } + } + + return NULL; +} + +static int +create_base_entry( + LDAP* ld, + char* basedn, + char *naming_attr_type, + char *naming_attr_value, + char *objectclassname +) +{ + int err; + int ret = 0; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "create_base_entry('%s','%s')\n", + basedn ? basedn : "NULL", naming_attr_value: "NULL"); +#endif + + if (ld == NULL || basedn == NULL || *basedn == '\0') + { + return -1; + } + + if (!entry_exists(ld, basedn)) + { + LDAPMod* attrs[3]; + LDAPMod attr[2]; + char* objectClasses[3]; + char* names[2]; + + attrs[0] = &attr[0]; + attrs[2] = NULL; + attr[0].mod_op = LDAP_MOD_ADD; + attr[0].mod_type = name_objectClass; + attr[0].mod_values = objectClasses; + objectClasses[0] = class_top; + objectClasses[1] = objectclassname; + objectClasses[2] = NULL; + attrs[1] = &attr[1]; + attr[1].mod_op = LDAP_MOD_ADD; + attr[1].mod_type = naming_attr_type; + attr[1].mod_values = names; + names[0] = naming_attr_value; + names[1] = NULL; + + /* fprintf (stdout, "ldap_add_s(%s)<br>\n", basedn); fflush (stdout); */ + + err = ldap_add_s (ld, basedn, attrs); + + if (err != LDAP_SUCCESS) + { + char* format = "Unable to create base entry." + " (%s (%i) returned from ldap_add_s(%s))"; + char* errmsg = ldap_err2string (err); + char* explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (basedn)); + sprintf (explanation, format, errmsg, err, basedn); + ds_report_warning (DS_NETWORK_ERROR, " can't create base entry", + explanation); + free (explanation); + ret = 1; + } + } + + return ret; +} + +static int +create_organization(LDAP* ld, char* base, char* org) +{ + return create_base_entry(ld, base, name_o, org, class_organization); +} + +static int +create_organizational_unit(LDAP* ld, char* base, char* unit, char *description, + char *extra_objectclassName, + char *extra_attrName, + char *extra_attrValue) +{ + int err; + int ret = 0; + char *entrydn = NULL; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "create_organizational_unit('%s','%s')\n", + base ? base : "NULL", unit ? unit : "NULL"); +#endif + + if (ld == NULL || unit == NULL || *unit == '\0') + { + return -1; + } + + /* + if base is null, assume the unit is the full DN of the entry + to create; this assumes the caller knows what he/she is doing + and has already created the parent entry(ies) + */ + if (!base) + entrydn = strdup(unit); + else + entrydn = make_dn("%s=%s, %s", name_ou, unit, base, 0); + + if (!entry_exists(ld, entrydn)) + { + LDAPMod* attrs[5]; + LDAPMod attr[4]; + char* objectClasses[4]; + char* names[2]; + char* desc[2]; + char* extra[2]; + char *baseName = unit; + int attrnum = 0; + if (base) + { + baseName = strdup(unit); + } + else + { + /* since the unit is in DN form, we need to extract something to + use for the ou: attribute */ + baseName = extract_name_from_dn(unit); + } + attrs[0] = &attr[0]; + attrs[1] = &attr[1]; + attrs[2] = NULL; + attr[0].mod_op = LDAP_MOD_ADD; + attr[0].mod_type = name_objectClass; + attr[0].mod_values = objectClasses; + objectClasses[0] = class_top; + objectClasses[1] = class_organizationalUnit; + objectClasses[2] = extra_objectclassName; /* may be null */ + objectClasses[3] = NULL; + attr[1].mod_op = LDAP_MOD_ADD; + attr[1].mod_type = name_ou; + attr[1].mod_values = names; + names[0] = baseName; + names[1] = NULL; + attrnum = 2; + if (description && *description) + { + attr[attrnum].mod_op = LDAP_MOD_ADD; + attr[attrnum].mod_type = name_description; + attr[attrnum].mod_values = desc; + desc[0] = description; + desc[1] = NULL; + attrs[attrnum] = &attr[attrnum]; + attrs[++attrnum] = NULL; + } + if (extra_attrName && extra_attrValue && + *extra_attrName && *extra_attrValue) + { + attr[attrnum].mod_op = LDAP_MOD_ADD; + attr[attrnum].mod_type = extra_attrName; + attr[attrnum].mod_values = extra; + extra[0] = extra_attrValue; + extra[1] = NULL; + attrs[attrnum] = &attr[attrnum]; + attrs[++attrnum] = NULL; + } + + /* fprintf (stdout, "ldap_add_s(%s)<br>\n", DN); fflush (stdout); */ + + err = ldap_add_s (ld, entrydn, attrs); + if (baseName) + free(baseName); + + if (err != LDAP_SUCCESS) + { + char* format = "Unable to create organizational unit." + " (%s (%i) returned from ldap_add_s(%s))"; + char* errmsg = ldap_err2string (err); + char* explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (entrydn)); + sprintf (explanation, format, errmsg, err, entrydn); + ds_report_warning (DS_NETWORK_ERROR, " can't create organizational unit", + explanation); + free (explanation); + ret = 1; + } + } + + if (entrydn) + free(entrydn); + + return ret; +} + +static int +create_domain_component(LDAP* ld, char* base, char* domcomp) +{ + return create_base_entry(ld, base, name_dc, domcomp, class_domain); +} + +static int +create_country(LDAP* ld, char* base, char* country) +{ + return create_base_entry(ld, base, name_c, country, class_country); +} + +static int +create_state(LDAP* ld, char* base, char* state) +{ + return create_base_entry(ld, base, name_st, state, class_locality); +} + +static int +create_locality(LDAP* ld, char* base, char* locality) +{ + return create_base_entry(ld, base, name_l, locality, class_locality); +} + +static int +create_base(LDAP* ld, char* base) +{ + int ret = 0; + char* attr; + char **rdnList = 0; + char **rdnListNoTypes = 0; + enum BASETYPE { unknown, org, orgunit, domcomp, country, state, locality } base_type = unknown; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "create_base('%s')\n", base ? base : "NULL"); +#endif + + if (ld == NULL || base == NULL || *base == '\0') + { + return -1; + } + + rdnList = ldap_explode_dn(base, 0); + if (!rdnList) + { + char error[BIG_LINE]; + sprintf(error, "The given base suffix [%s] is not a valid DN", base); + ds_send_error(error, 0); + return -1; + } + + if (PL_strncasecmp(rdnList[0], "o=", 2) == 0) + { + base_type = org; + } + else if (PL_strncasecmp(rdnList[0], "ou=", 3) == 0) + { + base_type = orgunit; + } + else if (PL_strncasecmp(rdnList[0], "dc=", 3) == 0) + { + base_type = domcomp; + } + else if (PL_strncasecmp(rdnList[0], "c=", 2) == 0) + { + base_type = country; + } + else if (PL_strncasecmp(rdnList[0], "st=", 3) == 0) + { + base_type = state; + } + else if (PL_strncasecmp(rdnList[0], "l=", 2) == 0) + { + base_type = locality; + } + else + { + ds_report_warning (DS_INCORRECT_USAGE, " Unable to create the root suffix.", + "In order to create the root suffix in the directory, you must " + "specify a distinguished name beginning with o=, ou=, dc=, c=, st=, or l=. " + "If you wish to use something else for your root suffix, you " + "should first create the directory with one of these suffixes, then you can " + "create additional suffixes in any form you choose." + ); + return -1; + } + + ldap_value_free(rdnList); + /* + We need to extract from the base the value to use for the attribute + name_attr e.g. ou: foo or o: org. + */ + rdnListNoTypes = ldap_explode_dn(base, 1); + attr = rdnListNoTypes[0]; + + if (!entry_exists(ld, base)) + { + if (base_type == org) + { + ret = create_organization(ld, base, attr); + } + else if (base_type == orgunit) + { + /* this function is smart enough to extract the name from the DN */ + ret = create_organizational_unit(ld, 0, base, 0, 0, 0, 0); + } + else if (base_type == domcomp) + { + ret = create_domain_component(ld, base, attr); + } + else if (base_type == country) + { + ret = create_country(ld, base, attr); + } + else if (base_type == state) + { + ret = create_state(ld, base, attr); + } + else if (base_type == locality) + { + ret = create_locality(ld, base, attr); + } + } + + ldap_value_free(rdnListNoTypes); + + /* now add the anon search and self mod acis */ + if (!ret) + { + ret = add_aci(ld, base, ACI_anonymous_allow); + if (!ret) + ret = add_aci(ld, base, ACI_self_allow); + } + + return ret; +} + +static int +create_NetscapeRoot(LDAP* ld, const char *DN) +{ +/* + dn: o=NetscapeRoot + o: NetscapeRoot + objectclass: top + objectclass: organization + */ + int err; + int ret = 0; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "create_NetscapeRoot()\n"); +#endif + + if (ld == NULL) + { + return -1; + } + + if (!entry_exists(ld, DN)) + { + LDAPMod* attrs[4]; + LDAPMod attr[3]; + char* objectClasses[4]; + char* names[2]; + + attrs[0] = &attr[0]; + attrs[3] = NULL; + attr[0].mod_op = LDAP_MOD_ADD; + attr[0].mod_type = name_objectClass; + attr[0].mod_values = objectClasses; + objectClasses[0] = class_top; + objectClasses[1] = class_organization; + objectClasses[2] = NULL; + attrs[1] = &attr[1]; + attr[1].mod_op = LDAP_MOD_ADD; + attr[1].mod_type = name_o; + attr[1].mod_values = names; + names[0] = name_netscaperoot; + names[1] = NULL; + attrs[2] = NULL; + + /* fprintf (stdout, "ldap_add_s(%s)<br>\n", DN); fflush (stdout); */ + + err = ldap_add_s (ld, DN, attrs); + + if (err != LDAP_SUCCESS) + { + char* format = "Unable to create %s." + " (%s (%i) returned from ldap_add_s(%s))"; + char* errmsg = ldap_err2string (err); + char* explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (name_netscaperoot)); + sprintf (explanation, format, name_netscaperoot, errmsg, err, + DN); + ds_report_warning (DS_NETWORK_ERROR, " can't create NetscapeRoot", + explanation); + free (explanation); + ret = 1; + } + + } + + return ret; +} + +static int +create_configEntry(LDAP* ld) +{ +/* + dn: cn=config40 + objectclass: top + objectclass: extensibleObject + cn: config40 + */ + char *entrydn = NULL; + int err; + int ret = 0; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "create_configEntry()\n"); +#endif + + if (ld == NULL) + { + return -1; + } + + entrydn = make_dn("%s=%s", name_cn, value_config40, 0); + if (!entry_exists(ld, entrydn)) + { + LDAPMod* attrs[3]; + LDAPMod attr[2]; + char* objectClasses[3]; + char* names[2]; + + attrs[0] = &attr[0]; + attrs[2] = NULL; + attr[0].mod_op = LDAP_MOD_ADD; + attr[0].mod_type = name_objectClass; + attr[0].mod_values = objectClasses; + objectClasses[0] = class_top; + objectClasses[1] = class_extensibleObject; + objectClasses[2] = NULL; + attrs[1] = &attr[1]; + attr[1].mod_op = LDAP_MOD_ADD; + attr[1].mod_type = name_cn; + attr[1].mod_values = names; + names[0] = value_config40; + names[1] = NULL; + + /* fprintf (stdout, "ldap_add_s(%s)<br>\n", DN); fflush (stdout); */ + + err = ldap_add_s (ld, entrydn, attrs); + + if (err != LDAP_SUCCESS) + { + char* format = "Unable to create %s." + " (%s (%i) returned from ldap_add_s(%s))"; + char* errmsg = ldap_err2string (err); + char* explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (name_netscaperoot)); + sprintf (explanation, format, value_config40, errmsg, err, entrydn); + ds_report_warning (DS_NETWORK_ERROR, " can't create config40", + explanation); + free (explanation); + ret = 1; + } + + } + + if (entrydn) + free(entrydn); + + return ret; +} + +int +create_group(LDAP* ld, char* base, char* group) +{ + int err; + int ret = 0; + LDAPMod* attrs[3]; + LDAPMod attr[2]; + char* objectClasses[3]; + char* names[2]; + char *entrydn = 0; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "create_group('%s','%s')\n", + base ? base : "NULL", group ? group : "NULL"); +#endif + + if (ld == NULL || base == NULL || *base == '\0' || + group == NULL || *group == '\0') + { + return -1; + } + + entrydn = make_dn("%s=%s, %s", name_cn, group, base, 0); + + if (!entry_exists(ld, entrydn)) + { + attrs[0] = &attr[0]; + attrs[1] = &attr[1]; + attrs[2] = NULL; + attr[0].mod_op = LDAP_MOD_ADD; + attr[0].mod_type = name_objectClass; + attr[0].mod_values = objectClasses; + objectClasses[0] = class_top; + objectClasses[1] = class_groupOfUniqueNames; + objectClasses[2] = NULL; + attr[1].mod_op = LDAP_MOD_ADD; + attr[1].mod_type = name_cn; + attr[1].mod_values = names; + names[0] = group; + names[1] = NULL; + /* fprintf (stdout, "ldap_add_s(%s)<br>\n", entrydn); fflush (stdout); */ + + err = ldap_add_s (ld, entrydn, attrs); + + if (err != LDAP_SUCCESS) + { + char* format = "Unable to create group." + " (%s (%i) returned from ldap_add_s(%s))"; + char* errmsg = ldap_err2string (err); + char* explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (entrydn)); + sprintf (explanation, format, errmsg, err, entrydn); + ds_report_warning (DS_NETWORK_ERROR, " can't create group", explanation); + free (explanation); + ret = 1; + } + } + + if (entrydn) + free(entrydn); + + return ret; +} + +int +create_consumer_dn(LDAP* ld, char* dn, char* hashedpw) +{ + int err; + int ret = 0; + LDAPMod* attrs[7]; + LDAPMod attr[6]; + char* objectClasses[3]; + char* names[2]; + char* snames[2]; + char* desc[2]; + char* pwd[2]; + char* passwordExpirationTime[2]; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "create_consumer_dn('%s','%s')\n", + dn ? dn : "NULL", hashedpw ? hashedpw : "NULL"); +#endif + + if (ld == NULL || dn == NULL || hashedpw == NULL) + { + return -1; + } + + if (!entry_exists(ld, dn)) + { + attrs[0] = &attr[0]; + attrs[1] = &attr[1]; + attrs[2] = &attr[2]; + attrs[3] = &attr[3]; + attrs[4] = &attr[4]; + attrs[5] = &attr[5]; + attrs[6] = NULL; + + attr[0].mod_op = LDAP_MOD_ADD; + attr[0].mod_type = name_objectClass; + attr[0].mod_values = objectClasses; + objectClasses[0] = class_top; + objectClasses[1] = class_person; + objectClasses[2] = NULL; + + attr[1].mod_op = LDAP_MOD_ADD; + attr[1].mod_type = name_cn; + attr[1].mod_values = names; + names[0] = "Replication Consumer"; + names[1] = NULL; + + attr[2].mod_op = LDAP_MOD_ADD; + attr[2].mod_type = name_sn; + attr[2].mod_values = snames; + snames[0] = "Consumer"; + snames[1] = NULL; + + attr[3].mod_op = LDAP_MOD_ADD; + attr[3].mod_type = name_description; + attr[3].mod_values = desc; + desc[0] = "Replication Consumer bind entity"; + desc[1] = NULL; + + attr[4].mod_op = LDAP_MOD_ADD; + attr[4].mod_type = name_userPassword; + attr[4].mod_values = pwd; + pwd[0] = hashedpw; + pwd[1] = NULL; + + attr[5].mod_op = LDAP_MOD_ADD; + attr[5].mod_type = name_passwordExpirationTime; + attr[5].mod_values = passwordExpirationTime; + passwordExpirationTime[0] = "20380119031407Z"; + passwordExpirationTime[1] = NULL; + + /* fprintf (stdout, "ldap_add_s(%s)<br>\n", DN); fflush (stdout); */ + + err = ldap_add_s (ld, dn, attrs); + + if (err != LDAP_SUCCESS) + { + char* format = "Unable to create consumer dn." + " (%s (%i) returned from ldap_add_s(%s))"; + char* errmsg = ldap_err2string (err); + char* explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (dn)); + sprintf (explanation, format, errmsg, err, dn); + ds_report_warning (DS_NETWORK_ERROR, " can't create consumer dn", explanation); + free (explanation); + ret = 1; + } + } + + return ret; +} + +static int +add_group_member(LDAP* ld, char* DN, char* attr, char* member) +{ + int err; + int ret = 0; + LDAPMod mod; + LDAPMod* mods[2]; + char* members[2]; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "add_group_member('%s', '%s', '%s')\n", + DN ? DN : "NULL", + attr ? attr : "NULL", + member ? member : "NULL"); +#endif + + if (ld == NULL || DN == NULL || attr == NULL || member == NULL) + { + return -1; + } + + mods[0] = &mod; + mods[1] = NULL; + mod.mod_op = LDAP_MOD_ADD; + mod.mod_type = attr; + mod.mod_values = members; + members[0] = member; + members[1] = NULL; + /* fprintf (stdout, "ldap_modify_s('%s')<br>\n",DN); fflush (stdout); */ + err = ldap_modify_s (ld, DN, mods); + if (err != LDAP_SUCCESS && err != LDAP_TYPE_OR_VALUE_EXISTS) { + char* exp = "can't add member. "; + char* format; + char* errmsg; + char* explanation; + format = "%s (%i) returned from ldap_modify_s(%s, %i)."; + errmsg = ldap_err2string (err); + explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (DN) + 10); + sprintf (explanation, format, errmsg, err, DN, LDAP_MOD_ADD); + ds_report_warning (DS_INCORRECT_USAGE, exp, explanation); + free (explanation); + ret = 1; + } + + return ret; +} + +static LDAP* +do_bind(SLAPD_CONFIG* slapd, char* rootdn, char* rootpw) +{ + LDAP* connection = NULL; + int retrymax = 1800; /* wait up to 30 min; init dbcache could be slow. */ + int err = LDAP_SUCCESS; + + /* added error retry to work around the slow start introduced + by blackflag 624053 */ + while ( retrymax-- ) + { + if (connection == NULL) { + connection = ldap_open ("127.0.0.1", slapd->port); + } + + if (connection) { + err = ldap_simple_bind_s (connection, rootdn, rootpw ? rootpw : ""); + if (LDAP_SUCCESS == err) + break; + } + + PR_Sleep(PR_SecondsToInterval(1)); + } + + if (connection == NULL) { + char* format = " Cannot connect to server."; + ds_report_warning (DS_NETWORK_ERROR, format, ""); + } else if (err != LDAP_SUCCESS) { + char* errmsg = ldap_err2string (err); + char* format = "Unable to bind to server." + " (%s (%i) returned from ldap_simple_bind_s(%s))"; + char* explanation = malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (rootdn) + 1); + sprintf (explanation, format, errmsg, err, rootdn); + ds_report_warning (DS_NETWORK_ERROR, " can't bind to server", + explanation); + free (explanation); + ldap_unbind (connection); + connection = NULL; + } + fflush (stdout); + return connection; +} + +static int +write_ldap_info(SLAPD_CONFIG* slapd, char* base, char* admnm) +{ + FILE* fp; + int ret = 0; + + char* fmt = "%s/shared/config/ldap.conf"; + char* infoFileName; + + infoFileName = (char*)malloc(strlen(fmt) + strlen(slapd->slapd_server_root) + 1); + sprintf(infoFileName, fmt, slapd->slapd_server_root); + + if ((fp = fopen(infoFileName, "w")) == NULL) + { + ret = -1; + } + else + { + fprintf(fp, "url\tldap://%s:%d/", + slapd->host, slapd->port); + + if (base) + fprintf(fp, "%s", base); + + fprintf(fp, "\n"); + + fprintf(fp, "admnm\t%s\n", admnm); + + fclose(fp); + } + + free(infoFileName); + + return ret; +} + +int +config_configEntry(LDAP* connection, QUERY_VARS* query) +{ + /* initial ACIs for o=NetscapeRoot */ + + int ret = add_aci_v (connection, value_config40DN, ACI_self_allow, 0); + return ret; +} + +int +config_suitespot(SLAPD_CONFIG* slapd, QUERY_VARS* query) +{ + LDAP* connection; + const char* DN_formatUID = "uid=%s,%s"; + char* usageShortMsg = " Required field missing."; + char* usageErrorMsg = NULL; + int status = 0; + char *admin_domainDN = 0; + int ii = 0; + char *configAdminDN = 0; + char *adminGroupDN = 0; + char *parentDN = 0; + char *localDAGroupDN = 0; + + if (!query->rootDN || *query->rootDN == '\0') { + usageErrorMsg = "You must enter the distinguished name of a user with " + "unrestricted access to the directory."; + } else if (!query->rootPW || *query->rootPW == '\0') { + usageErrorMsg = "You must enter the password of the user with " + "unrestricted access to the directory."; + } + + if (usageErrorMsg) { + ds_report_warning (DS_INCORRECT_USAGE, usageShortMsg, usageErrorMsg); + return -1; + } + + if (!(connection = do_bind (slapd, query->rootDN, query->rootPW))) + return 1; + + /* parent dn of admin uid entry */ + parentDN = make_dn("%s, %s, %s", name_administratorsRDN, + name_topologyRDN, query->netscaperoot, 0); + if (query->suffix) + { + status = create_base(connection, query->suffix); + if (!status) + { + add_aci_v(connection, query->suffix, ACI_user_allow_1, + "all", query->config_admin_uid, parentDN, 0); + + status = create_group(connection, query->suffix, name_localDAGroup); + } + } + + if (!status && query->consumerDN && query->consumerPW && + PL_strcasecmp(query->consumerDN, query->rootDN)) + status = create_consumer_dn(connection, + query->consumerDN, query->consumerPW); + + if (!status) + { + char realuid[1024] = {0}; + getUIDFromDN(query->config_admin_uid, realuid); + if (realuid[0]) + { + /* admid is already a DN */ + configAdminDN = strdup(query->config_admin_uid); + } + else + { + /* create a DN for admid */ + configAdminDN = make_dn(DN_formatUID, query->config_admin_uid, parentDN, 0); + } + + /* + Give the Configuration Admin group access to the root DSE entries + */ + adminGroupDN = make_dn("%s, %s=%s, %s, %s", value_configAdminGroupRDN, + name_ou, value_groupsOU, + name_topologyRDN, + query->netscaperoot, 0); + if (query->suffix) + { + localDAGroupDN = make_dn("cn=%s, %s", name_localDAGroup, + query->suffix, 0); + } + else + { + localDAGroupDN = NULL; + } + for (ii = 0; ii < entryAndAccessListSize; ++ii) + { + if (query->cfg_sspt) { + add_aci_v(connection, entryAndAccessList[ii].entryDN, + ACI_config_admin_group_allow, + entryAndAccessList[ii].access, + adminGroupDN, 0); + } + add_aci_v(connection, entryAndAccessList[ii].entryDN, + ACI_user_allow_2, + entryAndAccessList[ii].access, + configAdminDN, 0); + if (localDAGroupDN) + { + add_aci_v(connection, entryAndAccessList[ii].entryDN, + ACI_local_DA_allow, + entryAndAccessList[ii].access, + localDAGroupDN, 0); + } + } + } + + if (query->cfg_sspt) + { + /* create and set ACIs for o=netscaperoot entry */ + if (!status) + status = create_NetscapeRoot(connection, query->netscaperoot); + + if (!status) + status = add_aci_v(connection, query->netscaperoot, + ACI_config_admin_group_allow_all, + value_configAdminGroupRDN, + name_ou, value_groupsOU, name_topologyRDN, + query->netscaperoot, 0); + + if (!status) + status = add_aci_v(connection, query->netscaperoot, + ACI_anonymous_allow_with_filter, + query->netscaperoot, 0); + + if (!status) + status = add_aci_v(connection, query->netscaperoot, ACI_group_expansion, + query->netscaperoot, 0); + + /* create "topologyOU, netscaperoot" entry and set ACIs */ + if (!status) + { + char *dn = make_dn("%s, %s", name_topologyRDN, + query->netscaperoot, 0); + status = create_organizational_unit(connection, NULL, dn, + value_topologyDESC, + 0, 0, 0); + + if (!status) + add_aci(connection, dn, ACI_anonymous_allow); + + free(dn); + } + + /* create "ou=Groups, ..." */ + if (!status) + { + char *dn = make_dn("%s=%s, %s, %s", name_ou, value_groupsOU, + name_topologyRDN, query->netscaperoot, 0); + status = create_organizational_unit (connection, NULL, dn, + value_groupsDesc, 0, 0, 0); + free(dn); + } + + /* create "ou=Administrators, ..." */ + if (!status) + { + char *dn = make_dn("%s, %s, %s", name_administratorsRDN, + name_topologyRDN, query->netscaperoot, 0); + status = create_organizational_unit (connection, NULL, dn, + value_administratorsDESC, + 0, 0, 0); + free(dn); + } + + /* create "cn=Configuration Administrators, ou=Groups, ..." */ + if (!status) + { + char *dn = make_dn("%s=%s, %s, %s", name_ou, value_groupsOU, + name_topologyRDN, + query->netscaperoot, 0); + status = create_group (connection, dn, value_configAdminGroupCN); + free(dn); + } + + /* create the ss admin user */ + if (!status) + { + /* group to add the uid to */ + char *groupdn = make_dn("%s, %s=%s, %s, %s", value_configAdminGroupRDN, + name_ou, value_groupsOU, name_topologyRDN, + query->netscaperoot, 0); + create_ssadmin_user(connection, parentDN, + query->ssAdmID, query->ssAdmPW1); + + status = add_group_member (connection, groupdn, + name_uniqueMember, configAdminDN); + free (groupdn); + } + + admin_domainDN = make_dn("%s=%s, %s", name_ou, query->admin_domain, + query->netscaperoot, 0); + + if (!status) + status = create_organizational_unit (connection, 0, + admin_domainDN, + value_netscapeConfigDesc, + class_adminDomain, + name_adminDomain, + query->admin_domain); + + if (!status) { + status = create_organizational_unit(connection, + admin_domainDN, + value_globalPreferencesOU, 0, + 0, 0, 0); + } + if (!status) { + status = create_organizational_unit(connection, + admin_domainDN, + value_hostPreferencesOU, 0, + 0, 0, 0); + } + + /* + ** Write the ldap.info file and the SuiteSpot.ldif file + */ + + write_ldap_info(slapd, query->suffix, query->ssAdmID); + } + + if (!status && query->testconfig) + status = create_configEntry(connection); + + if (!status && query->testconfig) + status = config_configEntry(connection, query); + + if (connection) + ldap_unbind (connection); + if (adminGroupDN) + free(adminGroupDN); + if (configAdminDN) + free(configAdminDN); + if (parentDN) + free(parentDN); + if (localDAGroupDN) + free(localDAGroupDN); + + return status; +} diff --git a/ldap/admin/src/cfg_sspt.h b/ldap/admin/src/cfg_sspt.h new file mode 100644 index 00000000..a27d9891 --- /dev/null +++ b/ldap/admin/src/cfg_sspt.h @@ -0,0 +1,110 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#ifndef __cfg_sspt_h +#define __cfg_sspt_h + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +#include "ldap.h" +#include "dsalib.h" + +#define MAX_STRING_LEN 512 + +typedef struct _SLAPD_CONFIG { + char slapd_server_root[MAX_STRING_LEN + 1]; + int port; + char host[MAX_STRING_LEN]; + char root_dn[MAX_STRING_LEN]; +#define MAX_SUFFIXES 1024 + char* suffixes[MAX_SUFFIXES]; + int num_suffixes; +} SLAPD_CONFIG; + +typedef struct _query_vars { + char* suffix; + char* ssAdmID; + char* ssAdmPW1; + char* ssAdmPW2; + char* rootDN; + char* rootPW; + char* consumerDN; + char* consumerPW; + char* netscaperoot; + char* testconfig; + char* admin_domain; + int cfg_sspt; + char* config_admin_uid; +} QUERY_VARS; + +extern int +entry_exists(LDAP* ld, const char* entrydn); + +extern int +config_suitespot(SLAPD_CONFIG* slapd, QUERY_VARS* query); + +extern int +create_group(LDAP* ld, char* base, char* group); + +#ifndef __CFG_SSPT_C + +extern char* const class_top; +extern char* const class_organization; +extern char* const class_organizationalUnit; +extern char* const class_person; +extern char* const class_organizationalPerson; +extern char* const class_inetOrgPerson; +extern char* const class_groupOfUniqueNames; + +extern char* const name_objectClass; +extern char* const name_cn; +extern char* const name_sn; +extern char* const name_givenname; +extern char* const name_uid; +extern char* const name_userPassword; +extern char* const name_o; +extern char* const name_ou; +extern char* const name_member; +extern char* const name_uniqueMember; +extern char* const name_subtreeaci; +extern char* const name_netscaperoot; +extern char* const name_netscaperootDN; + +extern char* const value_suiteSpotAdminCN; +extern char* const value_suiteSpotAdminSN; +extern char* const value_suiteSpotAdminGN; +extern char* const value_adminGroupCN; +extern char* const value_netscapeServersOU; + +extern char* const field_suffix; +extern char* const field_ssAdmID; +extern char* const field_ssAdmPW1; +extern char* const field_ssAdmPW2; +extern char* const field_rootDN; +extern char* const field_rootPW; +extern char* const format_DN; +extern char* const format_simpleSearch; + +extern char* const insize_text; + +extern char* html_file; +extern char* dbg_log_file; + +#endif /* __CFG_SSPT_C */ + +/* + * iterate over the root DSEs we need to setup special ACIs for + * return true if entry and access are valid, false when the list + * is empty and entry and access are null + */ +int getEntryAndAccess(int index, const char **entry, const char **access); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __cfg_sspt_h */ diff --git a/ldap/admin/src/configure_instance.cpp b/ldap/admin/src/configure_instance.cpp new file mode 100644 index 00000000..db356e7f --- /dev/null +++ b/ldap/admin/src/configure_instance.cpp @@ -0,0 +1,1969 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/********************************************************************* +** +** +** NAME: +** configure_instance.cpp +** +** DESCRIPTION: +** Netscape Directory Server Configuration Program +** +** NOTES: +** Derived from the original ux-config.cc +** +** +*********************************************************************/ + +#include <iostream.h> +#include <fstream.h> +#include <stdio.h> /* printf, file I/O */ +#include <string.h> /* strlen */ +#include <ctype.h> +#include <sys/stat.h> +#ifdef XP_UNIX +#include <strings.h> +#include <pwd.h> +#include <grp.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#else +#include <io.h> +#endif +#include <stdlib.h> /* memset, rand stuff */ +#include <sys/types.h> +#include <errno.h> +#include <stdarg.h> +#include <time.h> + +extern "C" { +#include "ldap.h" +#include "dsalib.h" +} + +#include "prprf.h" + +#include "setupapi.h" +#ifdef XP_UNIX +#include "ux-util.h" +#endif +#include "ldapu.h" +#include "install_keywords.h" +#include "create_instance.h" +#include "cfg_sspt.h" +#include "configure_instance.h" +#include "dirver.h" + +#undef FILE_PATHSEP +#ifdef XP_WIN32 +#define FILE_PATHSEP "\\" +#else +#define FILE_PATHSEP "/" +#endif + +#ifdef XP_WIN32 +#define DEFAULT_TASKCONF "bin\\slapd\\install\\ldif\\tasks.ldif" +#define ROLEDIT_EXTENSION "bin\\slapd\\install\\ldif\\roledit.ldif" +#define COMMON_TASKS "bin\\slapd\\install\\ldif\\commonTasks.ldif" +#define SAMPLE_LDIF "bin\\slapd\\install\\ldif\\Example.ldif" +#define TEMPLATE_LDIF "bin\\slapd\\install\\ldif\\template.ldif" +#else +#define DEFAULT_TASKCONF "bin/slapd/install/ldif/tasks.ldif" +#define ROLEDIT_EXTENSION "bin/slapd/install/ldif/roledit.ldif" +#define COMMON_TASKS "bin/slapd/install/ldif/commonTasks.ldif" +#define SAMPLE_LDIF "bin/slapd/install/ldif/Example.ldif" +#define TEMPLATE_LDIF "bin/slapd/install/ldif/template.ldif" +#endif + +#ifndef PATH_MAX +#define PATH_MAX 256 +#endif + +// location of java runtime relative to server root +#ifdef XP_WIN32 +#define JAVA_RUNTIME "bin\\base\\jre\\bin\\jre" +#else +#define JAVA_RUNTIME "bin/base/jre/bin/jre" +#endif + +// location of class files for java +#define JAVA_DIR "java" +// location of jar files relative to java dir +#define JARS_DIR "jars" +// full name of class with main() for running admin console +#define CONSOLE_CLASS_NAME "com.netscape.management.client.console.Console" +// name of script file to generate relative to slapd instance directory +#define SCRIPT_FILE_NAME "start-console" + +#define DS_JAR_FILE_NAME "ds70.jar" +#define DS_CONSOLE_CLASS_NAME "com.netscape.admin.dirserv.DSAdmin" + +#ifdef XP_WIN32 +#define strtok_r(x,y,z) strtok(x,y) +#include "proto-ntutil.h" +#endif + +#define SERVER_MIGRATION_CLASS "com.netscape.admin.dirserv.task.MigrateCreate" +#define SERVER_CREATION_CLASS "com.netscape.admin.dirserv.task.MigrateCreate" + +static InstallMode installMode = Interactive; +static InstallInfo *installInfo = NULL; +static InstallInfo *slapdInfo = NULL; +static InstallInfo *slapdINFFileInfo = NULL; +static InstallInfo *adminInfo = NULL; +static const char *infoFile = NULL; +static const char *logFile = NULL; + +static InstallLog *installLog = NULL; +static int reconfig = 0; // set to 1 if we are reconfiguring +/* + * iDSISolaris is set to 1 for Solaris 9+ specific installation. + * This can be done by passing -S as the command line argument. + */ +int iDSISolaris = 0; + +/* + * There is currently a bug in LdapEntry->printEntry - it will crash if given a NULL argument + * This is a workaround + */ +static void +my_printEntry(LdapEntry *ent, const char *filename, int which) +{ + ostream *os = NULL; + if (filename && ent) + { + // just use LdapEntry, which should work given a good filename + ent->printEntry(filename); + return; + } + else if (which) + { + os = &cerr; + } + else + { + os = &cout; + } + + if (!ent || !ent->entryDN() || ent->isEmpty()) + { + *os << "Error: entry to print is empty" << endl; + } + else + { + *os << "dn: " << ent->entryDN() << endl; + char **attrs = ent->getAttributeNames(); + for (int ii = 0; attrs && attrs[ii]; ++ii) + { + char **values = ent->getAttributes(attrs[ii]); + for (int jj = 0; values && values[jj]; jj++) + { + *os << attrs[ii] << ": " << values[jj] << endl; + } + + if (values) + { + ent->freeAttributes(values); + } + } + if (attrs) + { + ent->freeAttributeNames(attrs); + } + } +} + +// changes empty strings ("") to NULLs (0) +static char * +my_strdup(const char *s) +{ + char *n = 0; + if (s && *s) + { + n = new char[strlen(s) + 1]; + strcpy(n, s); + } + + return n; +} + +// changes empty strings ("") to NULLs (0) +static char * +my_c_strdup(const char *s) +{ + char *n = 0; + if (s && *s) + { + n = (char *)malloc(strlen(s) + 1); + strcpy(n, s); + } + + return n; +} + +static int +isAValidDN(const char *dn_to_test) +{ + int ret = 1; + + if (!dn_to_test || !*dn_to_test) + { + ret = 0; + } + else + { + char **rdnList = ldap_explode_dn(dn_to_test, 0); + char **rdnNoTypes = ldap_explode_dn(dn_to_test, 1); + if (!rdnList || !rdnList[0] || !rdnNoTypes || !rdnNoTypes[0] || + !strcasecmp(rdnList[0], rdnNoTypes[0])) + { + ret = 0; + } + if (rdnList) + ldap_value_free(rdnList); + if (rdnNoTypes) + ldap_value_free(rdnNoTypes); + } + + return ret; +} + +static void +initMessageLog(const char *filename) +{ + if (filename && !installLog) + { + logFile = my_c_strdup(filename); +#ifdef XP_UNIX + if (!logFile && installMode != Silent) + { + logFile = "/dev/tty"; + } +#endif + installLog = new InstallLog(logFile); + } +} + +static void +dsLogMessage(const char *level, const char *which, + const char *format, ...) +{ + char bigbuf[BIG_BUF*4]; + va_list ap; + va_start(ap, format); + PR_vsnprintf(bigbuf, BIG_BUF*4, format, ap); + va_end(ap); +#ifdef _WIN32 // always output to stdout (for CGIs), and always log + // if a log is available + fprintf(stdout, "%s %s %s\n", level, which, bigbuf); + fflush(stdout); + if (installLog) + installLog->logMessage(level, which, bigbuf); +#else // not Windows + if (installMode == Interactive) + { + fprintf(stdout, "%s %s %s\n", level, which, bigbuf); + fflush(stdout); + } + else + { + if (installLog) + installLog->logMessage(level, which, bigbuf); + else + fprintf(stdout, "%s %s %s\n", level, which, bigbuf); + fflush(stdout); + } +#endif + + return; +} + +static char * +getGMT() +{ + static char buf[20]; + time_t curtime; + struct tm ltm; + + curtime = time( (time_t *)0 ); +#ifdef _WIN32 + ltm = *gmtime( &curtime ); +#else + gmtime_r( &curtime, <m ); +#endif + strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", <m ); + return buf; +} + +static void +normalizeDNs() +{ + static const char *DN_VALUED_ATTRS[] = { + SLAPD_KEY_SUFFIX, + SLAPD_KEY_ROOTDN, + SLAPD_KEY_REPLICATIONDN, + SLAPD_KEY_CONSUMERDN, + SLAPD_KEY_SIR_SUFFIX, + SLAPD_KEY_SIR_BINDDN + }; + static const int N = sizeof(DN_VALUED_ATTRS)/sizeof(DN_VALUED_ATTRS[0]); + static const char *URL_ATTRS[] = { + SLAPD_KEY_K_LDAP_URL, + SLAPD_KEY_USER_GROUP_LDAP_URL + }; + static const int NURLS = sizeof(URL_ATTRS)/sizeof(URL_ATTRS[0]); + + int ii; + for (ii = 0; slapdInfo && (ii < N); ++ii) + { + const char *attr = DN_VALUED_ATTRS[ii]; + char *dn = my_strdup(slapdInfo->get(attr)); + if (dn) + { + slapdInfo->set(attr, dn_normalize_convert(dn)); + delete [] dn; + } + } + + for (ii = 0; installInfo && (ii < NURLS); ++ii) + { + const char *attr = URL_ATTRS[ii]; + const char *url = installInfo->get(attr); + LDAPURLDesc *desc = 0; + if (url && !ldap_url_parse((char *)url, &desc) && desc) + { + char *dn = dn_normalize_convert(my_strdup(desc->lud_dn)); + int isSSL = !strncmp(url, "ldaps:", strlen("ldaps:")); + if (dn) + { + char port[6]; + sprintf(port, "%d", desc->lud_port); + NSString newurl = NSString("ldap") + + (isSSL ? "s" : "") + + "://" + desc->lud_host + + ":" + port + "/" + dn; + installInfo->set(attr, newurl); + delete [] dn; + } + } + if (desc) + ldap_free_urldesc(desc); + } +} + + +static int +featureIsEnabled(const char *s) +{ + if (!s || !*s || !strncasecmp(s, "no", strlen(s))) + return 0; // feature is disabled + + return 1; // feature is enabled +} + +/* + * The following escape LDAP URL is from ldapserver/ldap/clients/dsgw/htmlout.c + */ + +#define HREF_CHAR_ACCEPTABLE( c ) (( c >= '-' && c <= '9' ) || \ + ( c >= '@' && c <= 'Z' ) || \ + ( c == '_' ) || \ + ( c >= 'a' && c <= 'z' )) +static void +escape_ldap_uri(char *s1, const char *s2) +{ + unsigned char *q; + char *p; + const char *hexdig = "0123456789ABCDEF"; + + p = s1 + strlen(s1); + for (q = (unsigned char *) s2; *q != '\0'; ++q) + { + if (HREF_CHAR_ACCEPTABLE(*q)) + { + *p++ = *q; + } + else + { + *p++ = '%'; + *p++ = hexdig[*q >> 4]; + *p++ = hexdig[*q & 0x0F]; + } + } + + *p = '\0'; +} + +static LdapErrorCode +add_sample_entries(const char *sroot, LdapEntry *ldapEntry) +{ + char tmp[MED_BUF]; + + if (sroot) + sprintf(tmp, "%s%s%s", sroot, FILE_PATHSEP, SAMPLE_LDIF); + else + strcpy(tmp, "test.ldif"); + + return insertLdifEntries(ldapEntry->ldap(), NULL, tmp, NULL); + +} + + +// in the given string s, replace all occurrances of token with replace +// the string return is allocated with new char [] +static char * +replace_token(const char *s, const char *token, int tokenlen, + const char *replace, int replacelen) +{ + char *ptr = (char*)strstr(s, token); + char *n = 0; + if (!ptr) + { + n = my_strdup(s); + return n; + } + + // count the number of occurances of the token + int ntokens = 1; + while (ptr && *ptr) + { + ptr = (char*)strstr(ptr+1, token); + ++ntokens; + } + + n = new char [strlen(s) + (ntokens * replacelen)]; + char *d = n; + const char *begin = s; + for (ptr = (char*)strstr(s, token); ptr && *ptr;) + { + int len = int(ptr - begin); + strncpy(d, begin, len); + d += len; + begin = ptr + tokenlen; + len = replacelen; + strncpy(d, replace, len); + d += len; + ptr = strstr(ptr+1, token); + } + // no more occurances of token in string; copy the rest + for (ptr = (char *)begin; ptr && *ptr; LDAP_UTF8INC(ptr)) + { + *d = *ptr; + LDAP_UTF8INC(d); + } + *d = 0; + + return n; +} + +static void +add_org_entries(const char *sroot, LdapEntry *ldapEntry, + const char *initialLdifFile, const char *org_size, + NSString sieDN) +{ + org_size = org_size; + + char tmp[MED_BUF]; + char *dn; + + LdapError ldapError; + char **vals; + static const char *TOKEN[] = { + "%%%SUFFIX%%%", + "%%%ORG%%%", + "%%%CONFIG_ADMIN_DN%%%" + }; + static const int TOKENLEN[] = { 12, 9, 21 }; + static const int NTOKENS = 3; + static const char *REPLACE[] = { 0, 0, 0 }; + static int REPLACELEN[] = { 0, 0, 0 }; + + REPLACE[0] = slapdInfo->get(SLAPD_KEY_SUFFIX); + const char *org = strchr(REPLACE[0], '='); + if (org) + REPLACE[1] = org+1; + + REPLACE[2] = slapdInfo->get(SLAPD_KEY_CONFIG_ADMIN_DN); + for (int ii = 0; ii < NTOKENS; ++ii) + { + if (REPLACE[ii]) + REPLACELEN[ii] = strlen(REPLACE[ii]); + } + + if (sroot) + { + if (!initialLdifFile || !*initialLdifFile || + !strncasecmp(initialLdifFile, "suggest", strlen(initialLdifFile))) + sprintf(tmp, "%s%s%s", sroot, FILE_PATHSEP, TEMPLATE_LDIF); + else + strcpy(tmp, initialLdifFile); + } + else + strcpy(tmp, "test.ldif"); + + LdifEntry ldif(tmp); + + if (!ldif.isValid() || ldif.nextEntry() == -1) + { + dsLogMessage(SETUP_LOG_WARN, "Slapd", "File %s\ndoes not" + " appear to be a valid LDIF file.", tmp); + return; + } + + int entry_num = 0; + + do + { + entry_num++; + if (ldapEntry) + ldapEntry->clear(); + + for (int i = 0; i < ldif.numList(); i++) + { + const char *name = ldif.list(i); + if (!name || !*name) + continue; + + vals = ldif.getListItems(name); + if (!vals || !*vals) + continue; + + int n = ldif.numListItems(name); + if (!n) + continue; + + char **newvals = new char* [n+1]; + newvals[n] = 0; // null terminated + // go through the values replacing the token string with the value + for (int iii = 0; iii < n; ++iii) + { + newvals[iii] = my_strdup(vals[iii]); + for (int jj = 0; jj < NTOKENS; ++jj) + { + char *oldnewvals = newvals[iii]; + newvals[iii] = replace_token(newvals[iii], TOKEN[jj], TOKENLEN[jj], + REPLACE[jj], REPLACELEN[jj]); + delete [] oldnewvals; + } + } + + if (!strcasecmp(name, "dn")) + { + dn = my_strdup(newvals[0]); + } + else if (ldapEntry) + { + ldapEntry->addAttributes(name, (const char **) newvals); + } + else /* this is for debugging only */ + { + cerr << "name = " << name << " dn = " << dn << endl; + for (int jj = 0; jj < n; ++jj) + { + cerr << "old entry[" << jj << "] = " << vals[jj] << endl; + cerr << "new entry[" << jj << "] = " << newvals[jj] << endl; + } + cerr << "####" << endl; + } + ldif.freeListItems(vals); + for (int jj = 0; jj < n; ++jj) + delete [] newvals[jj]; + delete [] newvals; + } + + if (!ldapEntry) + continue; + + if (!dn || !*dn) + { + dsLogMessage(SETUP_LOG_WARN, "Slapd", "Entry number %d in file %s\ndoes not" + " contain a valid dn: attribute.\nThe file may be" + " corrupted or not in valid LDIF format.", + entry_num, tmp); + continue; + } + + if (entry_num == 1) + { + NSString aci = NSString( + "(targetattr = \"*\")(version 3.0; " + "acl \"SIE Group\"; allow (all)" + "groupdn = \"ldap:///") + sieDN + "\";)"; + // add the aci for the SIE group + ldapEntry->addAttribute("aci", aci); + } + + if (ldapEntry->exists(dn) == False) + { + ldapError = ldapEntry->insert(dn); + } + else + { + ldapError = ldapEntry->update(dn); + } + + if (ldapError != OKAY) + { + sprintf(tmp, "%d", ldapError.errorCode()); + dsLogMessage(SETUP_LOG_WARN, "Slapd", "Could not write entry %s (%s:%s)", dn, tmp, ldapError.msg()); + } + delete [] dn; + } while (ldif.nextEntry() != -1); +} + +// dsSIEDN will be something like: +// cn=slapd-foo, cn=NDS, cn=SS4.0, cn=FQDN, ou=admindomain, o=netscaperoot +static void +getAdminSIEDN(const char *dsSIEDN, const char *hostname, NSString& adminSIEDN) +{ + char *editablehostname = my_strdup(hostname); + char *eptr = strchr(editablehostname, '.'); + if (eptr) + *eptr = 0; + + char **rdnList = ldap_explode_dn(dsSIEDN, 0); + char *baseDN = 0; + if (rdnList && rdnList[0] && rdnList[1] && rdnList[2]) // dsSIEDN is a valid DN + { + int len = 0; + int ii; + for (ii = 2; rdnList[ii]; ++ii) + len += strlen(rdnList[ii]) + 3; + + baseDN = (char *)malloc(len+1); + baseDN[0] = 0; + for (ii = 2; rdnList[ii]; ++ii) + { + if (ii > 2) + strcat(baseDN, ", "); + strcat(baseDN, rdnList[ii]); + } + } + else + { + baseDN = my_c_strdup(dsSIEDN); + } + + if (rdnList) + ldap_value_free(rdnList); + + adminSIEDN = NSString("cn=admin-serv-") + editablehostname + + ", cn=Netscape Administration Server, " + baseDN; + + delete [] editablehostname; + free(baseDN); + + return; +} + +static void +setAppEntryInformation(LdapEntry *appEntry) +{ + // required attributes + if (!appEntry->getAttribute("objectclass")) + appEntry->addAttribute("objectclass", "nsApplication"); + appEntry->setAttribute("cn", slapdINFFileInfo->get("Name")); + appEntry->setAttribute("nsProductname", slapdINFFileInfo->get("Name")); + appEntry->setAttribute("nsProductversion", PRODUCTTEXT); + // optional attributes +/* + NSString temp = slapdINFFileInfo->get("Description"); + if ((NSString)NULL != temp) + appEntry->setAttribute("description", temp); +*/ + NSString temp = slapdINFFileInfo->get("NickName"); + if ((NSString)NULL == temp) + temp = "slapd"; + appEntry->setAttribute("nsNickName", temp); + temp = slapdINFFileInfo->get("BuildNumber"); + if ((NSString)NULL != temp) + appEntry->setAttribute("nsBuildNumber", temp); + temp = slapdINFFileInfo->get("Revision"); + if ((NSString)NULL != temp) + appEntry->setAttribute("nsRevisionNumber", temp); + temp = slapdINFFileInfo->get("SerialNumber"); + if ((NSString)NULL != temp) + appEntry->setAttribute("nsSerialNumber", temp); + temp = slapdINFFileInfo->get("Vendor"); + if ((NSString)NULL != temp) + appEntry->setAttribute("nsVendor", temp); + + if (!appEntry->getAttribute("nsInstalledLocation")) + appEntry->addAttribute("nsInstalledLocation", + installInfo->get(SLAPD_KEY_SERVER_ROOT)); + appEntry->setAttribute("installationTimeStamp", getGMT()); + temp = slapdINFFileInfo->get("Expires"); + if ((NSString)NULL != temp) + appEntry->setAttribute("nsExpirationDate", temp); + temp = slapdINFFileInfo->get("Security"); + if ((NSString)NULL != temp) + appEntry->setAttribute("nsBuildSecurity", temp); + + return; +} + +static LdapError +create_sie_and_isie(LdapEntry *sieEntry, LdapEntry *appEntry, NSString& sieDN) +{ + LdapError ldapError; // return value + + // Prepare sieEntry + sieEntry->clear(); + + sieEntry->addAttribute("objectclass", "netscapeServer"); + sieEntry->addAttribute("objectclass", "nsDirectoryServer"); + sieEntry->addAttribute("objectclass", "nsResourceRef"); + sieEntry->addAttribute("objectclass", "nsConfig"); + sieEntry->addAttribute("nsServerSecurity", "off"); + NSString serverID = NSString("slapd-") + slapdInfo->get(SLAPD_KEY_SERVER_IDENTIFIER); + sieEntry->addAttribute("nsServerID", serverID); + sieEntry->addAttribute("nsBindDN", slapdInfo->get(SLAPD_KEY_ROOTDN)); + sieEntry->addAttribute("nsBaseDN", slapdInfo->get(SLAPD_KEY_SUFFIX)); + char *hashedPwd = (char *)ds_salted_sha1_pw_enc ( + (char *)slapdInfo->get(SLAPD_KEY_ROOTDNPWD)); + if (hashedPwd) + sieEntry->addAttribute("userPassword", hashedPwd); +// sieEntry->addAttribute("AuthenticationPassword", slapdInfo->get(SLAPD_KEY_ROOTDNPWD)); + sieEntry->addAttribute("serverHostName", installInfo->get(SLAPD_KEY_FULL_MACHINE_NAME)); + sieEntry->addAttribute("serverRoot", installInfo->get(SLAPD_KEY_SERVER_ROOT)); + sieEntry->addAttribute("nsServerPort", slapdInfo->get(SLAPD_KEY_SERVER_PORT)); + sieEntry->addAttribute("nsSecureServerPort", "636"); +/* + NSString temp = slapdINFFileInfo->get("Description"); + if ((NSString)NULL != temp) + sieEntry->addAttribute("description", temp); +*/ + NSString name = NSString(slapdINFFileInfo->get("InstanceNamePrefix")) + " (" + + slapdInfo->get(SLAPD_KEY_SERVER_IDENTIFIER) + ")"; + sieEntry->addAttribute("serverProductName", name); + sieEntry->addAttribute("serverVersionNumber", slapdINFFileInfo->get("Version")); + sieEntry->addAttribute("installationTimeStamp", getGMT()); + NSString temp = installInfo->get(SLAPD_KEY_SUITESPOT_USERID); + if ((NSString)NULL != temp) // may not be present on NT . . . + sieEntry->addAttribute("nsSuiteSpotUser", temp); + + // Prepare appEntry + appEntry->clear(); + setAppEntryInformation(appEntry); + + NSString ssDN = installInfo->get(SLAPD_KEY_ADMIN_DOMAIN); + + // to make a disposable copy + char *fqdn = my_strdup(installInfo->get(SLAPD_KEY_FULL_MACHINE_NAME)); + + LdapErrorCode code = createSIE(sieEntry, appEntry, fqdn, + installInfo->get(SLAPD_KEY_SERVER_ROOT), + ssDN); + delete [] fqdn; + + if (code != OKAY) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "createSIE returned error code %d for ssDN=%s machinename=%s " + "server root=%s", (int)code, (const char *)ssDN, + installInfo->get(SLAPD_KEY_FULL_MACHINE_NAME), + installInfo->get(SLAPD_KEY_SERVER_ROOT)); +#ifdef XP_UNIX + cerr << "Here is the sieEntry:" << endl; + my_printEntry(sieEntry, 0, 1); // output to cerr +#else + dsLogMessage(SETUP_LOG_FATAL, "Slapd", "SIE entry printed to c:/temp/SIE.out"); + sieEntry->printEntry("c:/temp/SIE.out"); +#endif +#ifdef XP_UNIX + cerr << "Here is the appEntry:" << endl; + my_printEntry(appEntry, 0, 1); // output to cerr +#else + dsLogMessage(SETUP_LOG_FATAL, "Slapd", "APP entry printed to c:/temp/APP.out"); + appEntry->printEntry("c:/temp/APP.out"); +#endif + return code; + } + +// dsLogMessage("Info", "Slapd", "Created configuration entry for server %s", +// (const char *)serverID); + + sieDN = sieEntry->entryDN(); + + NSString configDN, configTaskDN, opTaskDN, adminSIEDN; + getAdminSIEDN(sieDN, installInfo->get(SLAPD_KEY_FULL_MACHINE_NAME), + adminSIEDN); + + // append the adminSIE to the create and migrate class names + appEntry->clear(); + NSString classname = NSString(SERVER_MIGRATION_CLASS"@"DS_JAR_FILE_NAME"@") + + adminSIEDN; + appEntry->addAttribute("nsServerMigrationClassname", classname); + classname = NSString(SERVER_CREATION_CLASS"@"DS_JAR_FILE_NAME"@") + + adminSIEDN; + appEntry->addAttribute("nsServerCreationClassname", classname); + if ((ldapError = appEntry->update(appEntry->entryDN())) != OKAY) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", "Error: Could not modify nsServerMigrationClassname " + "and/or nsServerCreationClassname in entry %s: error code %d\n", + appEntry->entryDN(), (int)ldapError); + return (int)ldapError; + } + + // Write configuration parameters (see ns-admin.conf) + sieEntry->clear(); + + sieEntry->addAttribute("objectclass", "nsResourceRef"); + sieEntry->addAttribute("objectclass", "nsAdminObject"); + sieEntry->addAttribute("objectclass", "nsDirectoryInfo"); + + /* + * Mandatory fields here + */ + NSString description = NSString("Configuration information for directory server ") + + serverID; + sieEntry->addAttribute ("cn", "configuration"); + NSString nsclassname = NSString(DS_CONSOLE_CLASS_NAME) + "@" + + DS_JAR_FILE_NAME + "@" + adminSIEDN; + sieEntry->addAttribute ("nsclassname", nsclassname); + sieEntry->addAttribute ("nsjarfilename", + DS_JAR_FILE_NAME); + char** rdnList = ldap_explode_dn(appEntry->entryDN(), 0); + if (rdnList) + { + int ii = 0; + int len = 0; + for (ii = 1; rdnList[ii]; ++ii) // skip first rdn + len += (strlen(rdnList[ii]) + 3); + char *adminGroupDN = (char *)calloc(1, len); + for (ii = 1; rdnList[ii]; ++ii) { + if (ii > 1) + strcat(adminGroupDN, ", "); + strcat(adminGroupDN, rdnList[ii]); + } + ldap_value_free(rdnList); + sieEntry->addAttribute("nsDirectoryInfoRef", adminGroupDN); + free(adminGroupDN); + } + + configDN = NSString("cn=configuration") + "," + sieDN; + + // allow modification by kingpin topology + createACIForConfigEntry(sieEntry, sieDN); + + if (sieEntry->exists(configDN) == False) + { + ldapError = sieEntry->insert(configDN); + } + else + { + ldapError = sieEntry->update(configDN); + } + + if (ldapError != OKAY) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "Could not update the configuration entry %s: error code %d", + (const char *)configDN, ldapError.errorCode()); + return (int)ldapError; + } else { +// dsLogMessage("Info", "Slapd", "Updated configuration entry for server %s", +// (const char *)serverID); + } + + // Write Tasks nodes + installInfo->toLocal(SLAPD_KEY_SERVER_ROOT); // path needs local encoding + NSString filename = NSString(installInfo->get(SLAPD_KEY_SERVER_ROOT)) + + FILE_PATHSEP + DEFAULT_TASKCONF; + ldapError = insertLdifEntries(sieEntry->ldap(), sieDN, filename, + adminSIEDN); + installInfo->toUTF8(SLAPD_KEY_SERVER_ROOT); // back to utf8 + + if (ldapError != OKAY) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "Could not update the instance specific tasks entry %s: error code %d", + (const char *)sieDN, ldapError.errorCode()); + return ldapError; + } else { +// dsLogMessage("Info", "Slapd", "Added task information for server %s", +// (const char *)serverID); + } + + installInfo->toLocal(SLAPD_KEY_SERVER_ROOT); // path needs local encoding + filename = NSString(installInfo->get(SLAPD_KEY_SERVER_ROOT)) + + FILE_PATHSEP + COMMON_TASKS; + ldapError = insertLdifEntries(sieEntry->ldap(), appEntry->entryDN(), + filename, adminSIEDN); + installInfo->toUTF8(SLAPD_KEY_SERVER_ROOT); // back to utf8 + + if (ldapError != OKAY) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "Could not update the general tasks entry %s: error code %d", + (const char *)appEntry->entryDN(), ldapError.errorCode()); + } else { +// dsLogMessage("Info", "Slapd", "Updated common task information for server %s", +// (const char *)serverID); + } + + return ldapError; +} + + +static LdapErrorCode +create_roledit_extension(Ldap* ldap) +{ + // + // If needed, we create "ou=Global Preferences,ou=<domain>,o=NetscapeRoot". + // The following code has been duplicated from setupGlobalPreferences() in + // setupldap.cpp + // + LdapEntry ldapEntry(ldap); + LdapError err; + NSString globalPref = DEFAULT_GLOBAL_PREFS_RDN; + NSString adminDomain = installInfo->get(SLAPD_KEY_ADMIN_DOMAIN); + char * domain = setupFormAdminDomainDN(adminDomain); + + globalPref = globalPref + LDAP_PATHSEP + domain; + +// dsLogMessage("Info", "Slapd", "Beginning update console role editor extensions"); + if (ldapEntry.retrieve(globalPref) != OKAY) + { + ldapEntry.setAttribute("objectclass", DEFAULT_GLOBAL_PREFS_OBJECT); + ldapEntry.setAttribute("ou", DEFAULT_GLOBAL_PREFS); + ldapEntry.setAttribute("aci", DEFAULT_GLOBAL_PREFS_ACI); + ldapEntry.setAttribute("description", "Default branch for Netscape Server Products Global Preferences"); +// dsLogMessage("Info", "Slapd", "Updating global preferences for console role editor extensions"); + err = ldapEntry.insert(globalPref); + } + else + { + ldapEntry.setAttribute("aci", DEFAULT_GLOBAL_PREFS_ACI); + ldapEntry.setAttribute("description", "Default branch for Netscape Server Products Global Preferences"); +// dsLogMessage("Info", "Slapd", "Updating global preferences for console role editor extensions"); + err = ldapEntry.replace(globalPref); + } + + if (err == OKAY) { +// dsLogMessage("Info", "Slapd", "Updated global console preferences for role editor extensions"); + } + + // + // Now let try to add the AdminResourceExtension entries. + // They are defined in the LDIF file named ROLEDIT_EXTENSION. + // + if (err == OKAY) + { +// dsLogMessage("Info", "Slapd", "Updating console role editor extensions"); + + installInfo->toLocal(SLAPD_KEY_SERVER_ROOT); // path needs local encoding + NSString filename = NSString(installInfo->get(SLAPD_KEY_SERVER_ROOT)) + + FILE_PATHSEP + ROLEDIT_EXTENSION; + err = insertLdifEntries(ldap, domain, filename, NULL); + installInfo->toUTF8(SLAPD_KEY_SERVER_ROOT); // back to utf8 + } + + if(domain) free(domain); + + if (err.errorCode() == OKAY) { +// dsLogMessage("Info", "Slapd", "Updated console role editor extensions"); + } + + return err.errorCode(); +} + + +static int +create_ss_dir_tree(const char *hostname, NSString &sieDN) +{ + int status = 0; + + LdapError ldapError = OKAY; + NSString adminID = installInfo->get(SLAPD_KEY_SERVER_ADMIN_ID); + NSString adminPwd = installInfo->get(SLAPD_KEY_SERVER_ADMIN_PWD); + Ldap ldap (ldapError, installInfo->get(SLAPD_KEY_K_LDAP_URL), + adminID, adminPwd, 0, 0); + + if (ldapError != OKAY) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "ERROR: Ldap authentication failed for url %s user id %s (%d:%s)" , + installInfo->get(SLAPD_KEY_K_LDAP_URL), adminID.data(), + ldapError.errorCode(), ldapError.msg()); + return ldapError.errorCode(); + } + + LdapEntry *sieEntry = new LdapEntry(&ldap); + LdapEntry *appEntry = new LdapEntry(&ldap); + + LdapErrorCode code = create_sie_and_isie(sieEntry, appEntry, sieDN); + + if (code != OKAY) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "ERROR: failed to register Directory server as a Netscape server (%d)", + code); + return code; + } + + code = create_roledit_extension(&ldap); + + if (code != OKAY) + { + dsLogMessage(SETUP_LOG_WARN, "Slapd", + "WARNING: failed to add extensions for role edition (%d)", + code); + code = OKAY; // We can continue anyway + } + + const char *user_ldap_url = installInfo->get(SLAPD_KEY_USER_GROUP_LDAP_URL); + if (!user_ldap_url) + user_ldap_url = installInfo->get(SLAPD_KEY_K_LDAP_URL); + + code = addGlobalUserDirectory(&ldap, + installInfo->get(SLAPD_KEY_ADMIN_DOMAIN), + user_ldap_url, 0, 0); + + if (code != OKAY) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "ERROR: failed to add Global User Directory (%d)", + code); + return code; + } + + // we need to add some ACIs which will allow the SIE group to have + // admin access to the newly created directory + Ldap *new_ldap = 0; + int port = atoi(slapdInfo->get(SLAPD_KEY_SERVER_PORT)); + if (strcasecmp(ldap.host(), hostname) || ldap.port() != port) + { + const char *suffix = 0; + if (featureIsEnabled(slapdInfo->get(SLAPD_KEY_USE_EXISTING_UG))) + suffix = DEFAULT_ROOT_DN; + else + suffix = slapdInfo->get(SLAPD_KEY_SUFFIX); + NSString new_url = NSString("ldap://") + + hostname + ":" + slapdInfo->get(SLAPD_KEY_SERVER_PORT) + + "/" + suffix; + const char *userDN; + const char *userPwd; + if (!(userDN = slapdInfo->get(SLAPD_KEY_ROOTDN))) + userDN = ldap.userDN(); + if (!(userPwd = slapdInfo->get(SLAPD_KEY_ROOTDNPWD))) + userPwd = ldap.userPassword(); + new_ldap = new Ldap(ldapError, new_url, userDN, userPwd, + userDN, userPwd); + if (ldapError != OKAY) + { + dsLogMessage(SETUP_LOG_WARN, "Slapd", + "Could not open the new directory server [%s:%s] to add an aci [%d].", + (const char *)new_url, userDN, ldapError.errorCode()); + delete new_ldap; + new_ldap = 0; + } + } + else + new_ldap = &ldap; + + if (new_ldap) + { + const char *entry = 0; + const char *access = 0; + LdapEntry ent(new_ldap); + int ii = 0; + while (getEntryAndAccess(ii, &entry, &access)) + { + ++ii; + NSString aci = NSString( + "(targetattr = \"*\")(version 3.0; " + "acl \"SIE Group\"; allow (") + access + ")" + "groupdn = \"ldap:///" + sieDN + "\";)"; + ent.clear(); + ent.addAttribute("aci", aci); + ldapError = ent.update(entry); + if (ldapError != OKAY) + dsLogMessage(SETUP_LOG_WARN, "Slapd", + "Could not add aci %s to entry %s [%d].", + (const char *)aci, entry, ldapError.errorCode()); + } + } + + if (new_ldap && new_ldap != &ldap) + delete new_ldap; + + destroyLdapEntry(sieEntry); + destroyLdapEntry(appEntry); + + if (status == OKAY) { +// dsLogMessage("Info", "Slapd", "Updated console administration access controls"); + } + + return status; +} + +static void +create_console_script() +{ +#if 0 // does not work right now +#ifdef XP_UNIX + const char *sroot = installInfo->get(SLAPD_KEY_SERVER_ROOT); + const char *sid = slapdInfo->get(SLAPD_KEY_SERVER_IDENTIFIER); + const char *hn = installInfo->get(SLAPD_KEY_FULL_MACHINE_NAME); + const char *port = slapdInfo->get(SLAPD_KEY_SERVER_PORT); + const char *suf = slapdInfo->get(SLAPD_KEY_SUFFIX); + const char *classpathSeparator = ":"; + + NSString scriptFilename = NSString(sroot) + FILE_PATHSEP + "slapd-" + + sid + FILE_PATHSEP + SCRIPT_FILE_NAME; + ofstream ofs(scriptFilename); + if (!ofs) + return; + + ofs << "#!/bin/sh" << endl; + ofs << "#" << endl; + ofs << "# This script will invoke the Netscape Console" << endl; + ofs << "#" << endl; + // see if there are any other .jar or .zip files in the java directory + // and add them to our class path too + ofs << "for file in " << sroot << FILE_PATHSEP << JAVA_DIR << FILE_PATHSEP + << JARS_DIR << FILE_PATHSEP << "*.jar ; do" << endl; + ofs << "\tCLASSPATH=${CLASSPATH}" << classpathSeparator << "$file" << endl; + ofs << "done" << endl; + + ofs << "for file in " << sroot << FILE_PATHSEP << JAVA_DIR << FILE_PATHSEP + << "*.jar ; do" << endl; + ofs << "\tCLASSPATH=${CLASSPATH}" << classpathSeparator << "$file" << endl; + ofs << "done" << endl; + + ofs << "for file in " << sroot << FILE_PATHSEP << JAVA_DIR << FILE_PATHSEP + << "*.zip ; do" << endl; + ofs << "\tCLASSPATH=${CLASSPATH}" << classpathSeparator << "$file" << endl; + ofs << "done" << endl; + + ofs << "export CLASSPATH" << endl; + + // go to the java dir + ofs << "cd " << sroot << FILE_PATHSEP << JAVA_DIR << endl; + // now, invoke the java runtime environment + ofs << sroot << FILE_PATHSEP << JAVA_RUNTIME + << " -classpath \"$CLASSPATH\" " + << CONSOLE_CLASS_NAME << " -d " << hn << " -p " << port << " -b " + << "\"" << suf << "\"" << endl; + + ofs.flush(); + ofs.close(); + + chmod(scriptFilename, 0755); +#endif +#endif // if 0 + + return; +} + +// check the install info read in to see if we have valid data +static int +info_is_valid() +{ + static const char *requiredFields[] = { + SLAPD_KEY_FULL_MACHINE_NAME, + SLAPD_KEY_SERVER_ROOT, + SLAPD_KEY_SERVER_IDENTIFIER, + SLAPD_KEY_SERVER_PORT, + SLAPD_KEY_ROOTDN, + SLAPD_KEY_ROOTDNPWD, + SLAPD_KEY_K_LDAP_URL, + SLAPD_KEY_SUFFIX, + SLAPD_KEY_SERVER_ADMIN_ID, + SLAPD_KEY_SERVER_ADMIN_PWD, + SLAPD_KEY_ADMIN_DOMAIN + }; + static int numRequiredFields = sizeof(requiredFields) / sizeof(requiredFields[0]); + + if (!installInfo || !slapdInfo) + return 0; + + for (int ii = 0; ii < numRequiredFields; ++ii) + { + const char *val = installInfo->get(requiredFields[ii]); + if (val && *val) + continue; + val = slapdInfo->get(requiredFields[ii]); + if (val && *val) + continue; + + // if we got here, the value was not found in either the install info or + // the slapd info + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "The required field %s is not present in the install info file.", + requiredFields[ii]); + return 0; + } + + return 1; +} + +static int +parse_commandline(int argc, char *argv[]) +{ + int opt; + + while ((opt = getopt(argc, argv, "rsSl:f:")) != EOF) + { + switch (opt) + { + case 'r': + reconfig = 1; + break; + case 's': + installMode = Silent; + break; + case 'S': + /* + * Solaris 9+ specific installation + */ + iDSISolaris = 1; + break; + case 'l': + initMessageLog(optarg); /* Log file to use */ + break; + case 'f': + infoFile = strdup(optarg); /* Install script */ + installInfo = new InstallInfo(infoFile); + installInfo->toUTF8(); + break; + default: + break; + } + } + + return 0; +} + +static const char * +changeYesNo2_0_1(const char *old) +{ + if (old && !strncasecmp(old, "yes", strlen(old))) + return "1"; + + return "0"; +} + +static void +init_from_config(server_config_s *cf) +{ + if (!cf) + return; + + if (!installInfo) + installInfo = new InstallInfo; + + if (!slapdInfo) + slapdInfo = new InstallInfo; + +#ifdef XP_WIN32 + ds_unixtodospath( cf->sroot); +#endif + + installInfo->set(SLAPD_KEY_SERVER_ROOT, cf->sroot); + installInfo->set(SLAPD_KEY_FULL_MACHINE_NAME, cf->servname); + + slapdInfo->set(SLAPD_KEY_SERVER_PORT, cf->servport); + installInfo->set(SLAPD_KEY_SERVER_ADMIN_ID, cf->cfg_sspt_uid); + installInfo->set(SLAPD_KEY_SERVER_ADMIN_PWD, cf->cfg_sspt_uidpw); + slapdInfo->set(SLAPD_KEY_SERVER_IDENTIFIER, cf->servid); + +#ifdef XP_UNIX + installInfo->set(SLAPD_KEY_SUITESPOT_USERID, cf->servuser); +#endif + + slapdInfo->set(SLAPD_KEY_SUFFIX, cf->suffix); + slapdInfo->set(SLAPD_KEY_ROOTDN, cf->rootdn); + slapdInfo->set(SLAPD_KEY_ROOTDNPWD, cf->rootpw); + + installInfo->set(SLAPD_KEY_ADMIN_DOMAIN, cf->admin_domain); + LDAPURLDesc *desc = 0; + if (cf->config_ldap_url && + !ldap_url_parse(cf->config_ldap_url, &desc) && desc) + { + const char *suffix = DEFAULT_ROOT_DN; + int isSSL = !strncmp(cf->config_ldap_url, "ldaps:", strlen("ldaps:")); + char port[6]; + sprintf(port, "%d", desc->lud_port); + NSString url = NSString("ldap") + + (isSSL ? "s" : "") + + "://" + desc->lud_host + + ":" + port + "/" + suffix; + installInfo->set(SLAPD_KEY_K_LDAP_URL, url); + ldap_free_urldesc(desc); + } + + if (cf->suitespot3x_uid) + slapdInfo->set(SLAPD_KEY_CONFIG_ADMIN_DN, cf->suitespot3x_uid); + else + slapdInfo->set(SLAPD_KEY_CONFIG_ADMIN_DN, cf->cfg_sspt_uid); + + /* + If we are here, that means we have been called as a CGI, which + means that there must already be an MC host, which means that + we are not creating an MC host, which means we must be creating + a UG host + */ + NSString UGLDAPURL = NSString("ldap://") + cf->servname + + ":" + cf->servport + "/" + cf->suffix; + installInfo->set(SLAPD_KEY_USER_GROUP_LDAP_URL, UGLDAPURL); + installInfo->set(SLAPD_KEY_USER_GROUP_ADMIN_ID, cf->rootdn); + installInfo->set(SLAPD_KEY_USER_GROUP_ADMIN_PWD, cf->rootpw); + + installInfo->addSection("slapd", slapdInfo); + + return; +} + +/* ----------------------- main ------------------------ */ + +/* + Initialize the cf structure based on data in the inf file, and also initialize + our static objects. Return 0 if everything was OK, and non-zero if there + were errors, like parsing a bogus inf file +*/ +extern "C" int create_config_from_inf( + server_config_s *cf, + int argc, + char *argv[] +) +{ + InstallInfo *admInfo; + if (parse_commandline(argc, argv)) + return 1; + + admInfo = installInfo->getSection("admin"); + slapdInfo = installInfo->getSection("slapd"); + if (!slapdInfo->get(SLAPD_KEY_SUFFIX)) + slapdInfo->set(SLAPD_KEY_SUFFIX, DEFAULT_ROOT_DN); + + if (installInfo->get(SLAPD_KEY_SERVER_ADMIN_ID)) + slapdInfo->set(SLAPD_KEY_CONFIG_ADMIN_DN, + installInfo->get(SLAPD_KEY_SERVER_ADMIN_ID)); + + if (!info_is_valid()) + return 1; + + normalizeDNs(); + + installInfo->toLocal(SLAPD_KEY_SERVER_ROOT); + cf->sroot = my_c_strdup(installInfo->get(SLAPD_KEY_SERVER_ROOT)); + installInfo->toUTF8(SLAPD_KEY_SERVER_ROOT); + cf->servname = my_c_strdup(installInfo->get(SLAPD_KEY_FULL_MACHINE_NAME)); + + cf->servport = my_c_strdup(slapdInfo->get(SLAPD_KEY_SERVER_PORT)); + + if (admInfo && admInfo->get(SLAPD_KEY_ADMIN_SERVER_PORT)) { + cf->adminport = my_c_strdup(admInfo->get(SLAPD_KEY_ADMIN_SERVER_PORT)); + } else { + cf->adminport = my_c_strdup("80"); + } + + cf->cfg_sspt = my_c_strdup( + changeYesNo2_0_1(slapdInfo->get(SLAPD_KEY_SLAPD_CONFIG_FOR_MC))); + cf->suitespot3x_uid = my_c_strdup(installInfo->get(SLAPD_KEY_SERVER_ADMIN_ID)); + cf->cfg_sspt_uid = my_c_strdup(installInfo->get(SLAPD_KEY_SERVER_ADMIN_ID)); + cf->cfg_sspt_uidpw = my_c_strdup(installInfo->get(SLAPD_KEY_SERVER_ADMIN_PWD)); + cf->servid = my_c_strdup(slapdInfo->get(SLAPD_KEY_SERVER_IDENTIFIER)); + +#ifdef XP_UNIX + cf->servuser = my_c_strdup(installInfo->get(SLAPD_KEY_SUITESPOT_USERID)); +#endif + + cf->suffix = my_c_strdup(slapdInfo->get(SLAPD_KEY_SUFFIX)); + cf->rootdn = my_c_strdup(slapdInfo->get(SLAPD_KEY_ROOTDN)); + /* Encode the password in SSHA by default */ + cf->rootpw = my_c_strdup(slapdInfo->get(SLAPD_KEY_ROOTDNPWD)); + cf->roothashedpw = (char *)ds_salted_sha1_pw_enc (cf->rootpw); + + const char *test = slapdInfo->get(SLAPD_KEY_REPLICATIONDN); + const char *testpw = slapdInfo->get(SLAPD_KEY_REPLICATIONPWD); + if (test && *test && testpw && *testpw) + { + cf->replicationdn = my_c_strdup(slapdInfo->get(SLAPD_KEY_REPLICATIONDN)); + cf->replicationpw = my_c_strdup(slapdInfo->get(SLAPD_KEY_REPLICATIONPWD)); + cf->replicationhashedpw = (char *)ds_salted_sha1_pw_enc (cf->replicationpw); + } + + test = slapdInfo->get(SLAPD_KEY_CONSUMERDN); + testpw = slapdInfo->get(SLAPD_KEY_CONSUMERPWD); + if (test && *test && testpw && *testpw) + { + cf->consumerdn = my_c_strdup(test); + cf->consumerpw = my_c_strdup(testpw); + cf->consumerhashedpw = (char *)ds_salted_sha1_pw_enc (cf->consumerpw); + } + + cf->changelogdir = my_c_strdup(slapdInfo->get(SLAPD_KEY_CHANGELOGDIR)); + cf->changelogsuffix = my_c_strdup(slapdInfo->get(SLAPD_KEY_CHANGELOGSUFFIX)); + cf->admin_domain = my_c_strdup(installInfo->get(SLAPD_KEY_ADMIN_DOMAIN)); + cf->disable_schema_checking = + my_c_strdup( + changeYesNo2_0_1(slapdInfo->get(SLAPD_KEY_DISABLE_SCHEMA_CHECKING))); + + /* + Don't create dc=example,dc=com if the user did not select to add the + sample entries + */ + if (!featureIsEnabled(slapdInfo->get(SLAPD_KEY_ADD_SAMPLE_ENTRIES))) + { + cf->samplesuffix = NULL; + } + + cf->config_ldap_url = (char *)installInfo->get(SLAPD_KEY_K_LDAP_URL); + LDAPURLDesc *desc = 0; + if (cf->config_ldap_url && + !ldap_url_parse(cf->config_ldap_url, &desc) && desc) + { + const char *suffix = DEFAULT_ROOT_DN; + int isSSL = !strncmp(cf->config_ldap_url, "ldaps:", strlen("ldaps:")); + char port[6]; + sprintf(port, "%d", desc->lud_port); + NSString url = NSString("ldap") + + (isSSL ? "s" : "") + + "://" + desc->lud_host + + ":" + port + "/" + suffix; + installInfo->set(SLAPD_KEY_K_LDAP_URL, url); + cf->config_ldap_url = my_c_strdup(url); + ldap_free_urldesc(desc); + } + + if (test = installInfo->get(SLAPD_KEY_USER_GROUP_LDAP_URL)) + cf->user_ldap_url = my_c_strdup(test); + else + cf->user_ldap_url = my_c_strdup(cf->config_ldap_url); + + cf->use_existing_config_ds = + featureIsEnabled(slapdInfo->get(SLAPD_KEY_USE_EXISTING_MC)); + + cf->use_existing_user_ds = + featureIsEnabled(slapdInfo->get(SLAPD_KEY_USE_EXISTING_UG)); + + if ((test = slapdInfo->get(SLAPD_KEY_INSTALL_LDIF_FILE)) && + !access(test, 0)) + { + cf->install_ldif_file = my_c_strdup(test); + // remove the fields from the slapdInfo so we don't try + // to handle this case later + slapdInfo->remove(SLAPD_KEY_ADD_ORG_ENTRIES); + slapdInfo->remove(SLAPD_KEY_INSTALL_LDIF_FILE); + } + + /* we also have to setup the environment to mimic a CGI */ + static char netsiteRoot[PATH_MAX+32]; + PR_snprintf(netsiteRoot, PATH_MAX+32, "NETSITE_ROOT=%s", cf->sroot); + putenv(netsiteRoot); + + /* set the admin SERVER_NAMES = slapd-slapdIdentifier */ + static char serverNames[PATH_MAX+32]; + PR_snprintf(serverNames, PATH_MAX+32, "SERVER_NAMES=slapd-%s", cf->servid); + putenv(serverNames); + + /* get and set the log file */ + /* use the one given on the command line by default, otherwise, use + the one from the inf file */ + if (logFile || (test = slapdInfo->get(SLAPD_INSTALL_LOG_FILE_NAME))) + { + static char s_logfile[PATH_MAX+32]; + if (logFile) + { + PR_snprintf(s_logfile, PATH_MAX+32, "DEBUG_LOGFILE=%s", logFile); + } + else + { + PR_snprintf(s_logfile, PATH_MAX+32, "DEBUG_LOGFILE=%s", test); + /* also init the C++ api message log */ + initMessageLog(test); + } + putenv(s_logfile); + } + + return 0; +} + +extern "C" int +configure_instance_with_config( + server_config_s *cf, + int verbose, // if false, silent; if true, verbose + const char *lfile +) +{ + if (!cf) + return 1; + + infoFile = 0; + initMessageLog(lfile); + + if (!verbose) + installMode = Silent; + + init_from_config(cf); + + return configure_instance(); +} + +extern "C" int +configure_instance() +{ + char hn[BUFSIZ]; + int status = 0; + + dsLogMessage(SETUP_LOG_START, "Slapd", "Starting Slapd server configuration."); + + if (!info_is_valid()) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", "Missing Configuration Parameters."); + return 1; + } + + if (installInfo == NULL || slapdInfo == NULL) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", "Answer cache not found or invalid"); + return 1; + } + + adminInfo = installInfo->getSection("admin"); + + // next, find the slapd.inf file; it is in the dir <server root>/setup/slapd + installInfo->toLocal(SLAPD_KEY_SERVER_ROOT); // path needs local encoding + NSString slapdinffile = NSString(installInfo->get(SLAPD_KEY_SERVER_ROOT)) + + FILE_PATHSEP + "setup" + FILE_PATHSEP + "slapd" + FILE_PATHSEP + + "slapd.inf"; + InstallInfo temp(slapdinffile); + if (!(slapdINFFileInfo = temp.getSection("slapd")) || + slapdINFFileInfo->isEmpty()) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", "Missing configuration file %s", + (const char *)slapdinffile); + return 1; + } + installInfo->toUTF8(SLAPD_KEY_SERVER_ROOT); // back to utf8 + + hn[0] = '\0'; + + /* + * Get the full hostname. + */ + + if (!installInfo->get(SLAPD_KEY_FULL_MACHINE_NAME)) + { + NSString h; + /* Force automatic detection of host name */ +#ifdef XP_UNIX + h = InstUtil::guessHostname(); +#else + /* stevross: figure out NT equivalent */ +#endif + strcpy(hn, h); + installInfo->set(SLAPD_KEY_FULL_MACHINE_NAME, hn); + } + else + { + strcpy(hn,installInfo->get(SLAPD_KEY_FULL_MACHINE_NAME)); + } + + NSString sieDN; + if (status = create_ss_dir_tree(hn, sieDN)) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "Did not add Directory Server information to Configuration Server."); + return status; + } + else + dsLogMessage(SETUP_LOG_SUCCESS, "Slapd", + "Added Directory Server information to Configuration Server."); + + // at this point we should be finished talking to the Mission Control LDAP + // server; we may need to establish a connection to the new instance + // we just created in order to write some of this optional stuff to it + + Ldap *ldap = 0; + LdapEntry *entry = 0; + LdapError ldapError = 0; + NSString newURL = NSString("ldap://") + hn + ":" + + slapdInfo->get(SLAPD_KEY_SERVER_PORT) + "/" + + slapdInfo->get(SLAPD_KEY_SUFFIX); + const char *bindDN = slapdInfo->get(SLAPD_KEY_ROOTDN); + const char *bindPwd = slapdInfo->get(SLAPD_KEY_ROOTDNPWD); + // install a sample tree + if (featureIsEnabled(slapdInfo->get(SLAPD_KEY_ADD_SAMPLE_ENTRIES))) + { + if (!ldap) + { + ldapError = 0; + ldap = new Ldap (ldapError, newURL, bindDN, bindPwd, 0, 0); + if (ldapError.errorCode()) + { + delete ldap; + ldap = 0; + dsLogMessage(SETUP_LOG_WARN, "Slapd", + "Could not add sample entries, ldap error code %d", + ldapError.errorCode()); + } + else + { + entry = new LdapEntry(ldap); + } + } + + if (entry) + { + installInfo->toLocal(SLAPD_KEY_SERVER_ROOT); // path needs local + ldapError = add_sample_entries(installInfo->get(SLAPD_KEY_SERVER_ROOT), + entry); + installInfo->toUTF8(SLAPD_KEY_SERVER_ROOT); // back to utf8 + if (ldapError.errorCode()) + { + delete ldap; + ldap = 0; + dsLogMessage(SETUP_LOG_WARN, "Slapd", + "Could not add sample entries, ldap error code %d", + ldapError.errorCode()); + destroyLdapEntry(entry); + entry = 0; + } + } + } + + // create some default organizational entries based on org size, but only + // if we're creating the User Directory + if (!featureIsEnabled(slapdInfo->get(SLAPD_KEY_USE_EXISTING_UG)) && + featureIsEnabled(slapdInfo->get(SLAPD_KEY_ADD_ORG_ENTRIES))) + { + if (!ldap) + { + ldapError = 0; + ldap = new Ldap (ldapError, newURL, bindDN, bindPwd, 0, 0); + if (ldapError.errorCode()) + { + delete ldap; + ldap = 0; + dsLogMessage(SETUP_LOG_WARN, "Slapd", + "Could not populate with ldif file %s error code %d", + slapdInfo->get(SLAPD_KEY_ADD_ORG_ENTRIES), + ldapError.errorCode()); + } + else + { + entry = new LdapEntry(ldap); + } + } + + if (!isAValidDN(slapdInfo->get(SLAPD_KEY_CONFIG_ADMIN_DN))) + { + // its a uid + NSString adminDN = NSString("uid=") + + slapdInfo->get(SLAPD_KEY_CONFIG_ADMIN_DN) + + ", ou=Administrators, ou=TopologyManagement, " + + DEFAULT_ROOT_DN; + slapdInfo->set(SLAPD_KEY_CONFIG_ADMIN_DN, adminDN); + } + + if (entry) + { + installInfo->toLocal(SLAPD_KEY_SERVER_ROOT); // path needs local + add_org_entries(installInfo->get(SLAPD_KEY_SERVER_ROOT), entry, + slapdInfo->get(SLAPD_KEY_INSTALL_LDIF_FILE), + slapdInfo->get(SLAPD_KEY_ORG_SIZE), sieDN); + installInfo->toUTF8(SLAPD_KEY_SERVER_ROOT); // back to utf8 + } + } + + if (ldap) + delete ldap; + if (entry) + destroyLdapEntry(entry); + + // create executable shell script to run the console + create_console_script(); + + return status; +} + +extern "C" int +reconfigure_instance(int argc, char *argv[]) +{ + char hn[BUFSIZ]; + int status = 0; + + dsLogMessage(SETUP_LOG_START, "Slapd", "Starting Slapd server reconfiguration."); + + if (parse_commandline(argc, argv)) + return 1; + + if (installInfo == NULL) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", "Answer cache not found or invalid"); + return 1; + } + + // next, find the slapd.inf file; it is in the dir <server root>/setup/slapd + installInfo->toLocal(SLAPD_KEY_SERVER_ROOT); // path needs local + NSString slapdinffile = NSString(installInfo->get(SLAPD_KEY_SERVER_ROOT)) + + FILE_PATHSEP + "setup" + FILE_PATHSEP + "slapd" + FILE_PATHSEP + + "slapd.inf"; + InstallInfo temp(slapdinffile); + if (!(slapdINFFileInfo = temp.getSection("slapd")) || + slapdINFFileInfo->isEmpty()) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", "Missing configuration file %s", + (const char *)slapdinffile); + return 1; + } + installInfo->toUTF8(SLAPD_KEY_SERVER_ROOT); // path needs local + + hn[0] = '\0'; + + /* + * Get the full hostname. + */ + + if (!installInfo->get(SLAPD_KEY_FULL_MACHINE_NAME)) + { + NSString h; + /* Force automatic detection of host name */ +#ifdef XP_UNIX + h = InstUtil::guessHostname(); +#else + /* stevross: figure out NT equivalent */ +#endif + strcpy(hn, h); + installInfo->set(SLAPD_KEY_FULL_MACHINE_NAME, hn); + } + else + { + strcpy(hn,installInfo->get(SLAPD_KEY_FULL_MACHINE_NAME)); + } + + // search for the app entry for the DS installation we just replaced + // open an LDAP connection to the Config Directory + LdapError le; + Ldap ldap(le, + installInfo->get(SLAPD_KEY_K_LDAP_URL), + installInfo->get(SLAPD_KEY_SERVER_ADMIN_ID), + installInfo->get(SLAPD_KEY_SERVER_ADMIN_PWD)); + if (le != OKAY) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "ERROR: Ldap authentication failed for url %s user id %s (%d:%s)", + installInfo->get(SLAPD_KEY_K_LDAP_URL), + installInfo->get(SLAPD_KEY_SERVER_ADMIN_ID), + le.errorCode(), le.msg()); + return le.errorCode(); + } + + // construct the base of the search + NSString baseDN = NSString("cn=") + hn + ", ou=" + + installInfo->get(SLAPD_KEY_ADMIN_DOMAIN) + ", " + + DEFAULT_ROOT_DN; + + // find the nsApplication entry corresponding to the slapd installation + // in the given server root +#ifdef XP_WIN32 + + char *pszServerRoot = my_strdup(installInfo->get(SLAPD_KEY_SERVER_ROOT)); + char *pszEscapedServerRoot = (char *)malloc(2*strlen(installInfo->get(SLAPD_KEY_SERVER_ROOT)) ); + char *p,*q; + + for(p=pszServerRoot,q=pszEscapedServerRoot; p && *p; p++) + { + *q = *p; + if(*p == '\\') + { + q++; + *q='\\'; + } + q++; + } + /* null terminate it */ + *q= *p; + + + NSString filter = + NSString("(&(objectclass=nsApplication)") + + "(nsnickname=slapd)(nsinstalledlocation=" + + pszEscapedServerRoot + "))"; + + if(pszServerRoot) + { + free(pszServerRoot); + } + + if(pszEscapedServerRoot) + { + free(pszEscapedServerRoot); + } +#else + NSString filter = + NSString("(&(objectclass=nsApplication)") + + "(nsnickname=slapd)(nsinstalledlocation=" + + installInfo->get(SLAPD_KEY_SERVER_ROOT) + "))"; +#endif + + int scope = LDAP_SCOPE_SUBTREE; + + LdapEntry ldapent(&ldap); + le = ldapent.retrieve(filter, scope, baseDN); + if (le != OKAY) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "ERROR: Could not find Directory Server Configuration\n" + "URL %s user id %s DN %s (%d:%s)" , + installInfo->get(SLAPD_KEY_K_LDAP_URL), + installInfo->get(SLAPD_KEY_SERVER_ADMIN_ID), + (const char *)baseDN, + le.errorCode(), le.msg()); + return le.errorCode(); + } + + setAppEntryInformation(&ldapent); + + le = ldapent.replace(ldapent.entryDN()); + if (le != OKAY) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "ERROR: Could not update Directory Server Configuration\n" + "URL %s user id %s DN %s (%d:%s)" , + installInfo->get(SLAPD_KEY_K_LDAP_URL), + installInfo->get(SLAPD_KEY_SERVER_ADMIN_ID), + (const char *)baseDN, + le.errorCode(), le.msg()); + return le.errorCode(); + } + + // now update the values in the SIEs under the ISIE + filter = NSString("(objectclass=nsDirectoryServer)"); + scope = LDAP_SCOPE_ONELEVEL; + baseDN = NSString(ldapent.entryDN()); + + ldapent.clear(); + le = ldapent.retrieve(filter, scope, baseDN); + if (le != OKAY) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "ERROR: Could not find Directory Server Instances\n" + "URL %s user id %s DN %s (%d:%s)", + installInfo->get(SLAPD_KEY_K_LDAP_URL), + installInfo->get(SLAPD_KEY_SERVER_ADMIN_ID), + (const char *)baseDN, + le.errorCode(), le.msg()); + return le.errorCode(); + } + + // ldapent holds the search results, but ldapent.replace will wipe out that + // information; so, create a new entry to actually do the replace operation + // while we use the original ldapent to iterate the search results + + do + { + LdapEntry repEntry(ldapent.ldap()); + repEntry.retrieve(ldapent.entryDN()); + repEntry.setAttribute("serverVersionNumber", slapdINFFileInfo->get("Version")); + repEntry.setAttribute("installationTimeStamp", getGMT()); + + le = repEntry.replace(repEntry.entryDN()); + if (le != OKAY) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "ERROR: Could not update Directory Server Instance\n" + "URL %s user id %s DN %s (%d:%s)" , + installInfo->get(SLAPD_KEY_K_LDAP_URL), + installInfo->get(SLAPD_KEY_SERVER_ADMIN_ID), + (const char *)repEntry.entryDN(), + le.errorCode(), le.msg()); + return le.errorCode(); + } + } + while (ldapent.next() == OKAY); + + // we have a new jar file dsXX.jar so we need to update all + // references to the old jar file name + filter = NSString("(|(nsclassname=*)(nsjarfilename=*)" + "(nsservermigrationclassname=*)" + "(nsservercreationclassname=*))"); + scope = LDAP_SCOPE_SUBTREE; + + ldapent.clear(); + le = ldapent.retrieve(filter, scope, baseDN); + if (le != OKAY) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "ERROR: Could not find Directory Server Instances\n" + "URL %s user id %s DN %s (%d:%s)", + installInfo->get(SLAPD_KEY_K_LDAP_URL), + installInfo->get(SLAPD_KEY_SERVER_ADMIN_ID), + (const char *)baseDN, + le.errorCode(), le.msg()); + return le.errorCode(); + } + + do + { + LdapEntry repEntry(ldapent.ldap()); + repEntry.retrieve(ldapent.entryDN()); + + const char *replace[] = { + "nsclassname", + "nsservermigrationclassname", + "nsservercreationclassname" + }; + const int replaceSize = sizeof(replace)/sizeof(replace[0]); + + if (repEntry.getAttribute("nsjarfilename")) + { + repEntry.setAttribute("nsjarfilename", DS_JAR_FILE_NAME); + } + + for (int ii = 0; ii < replaceSize; ++ii) + { + char *val = repEntry.getAttribute(replace[ii]); + // the class name is of the form + // full class path and name[@jar file[@admin SIE]] + // so here's what we'll do: + // search for the first @ in the string; if there's not one, just + // skip it + // save the full class path and name to a temp var + // create the new classname by appending @new jar file to the full class + // name + // if there is a second @ in the original string, grab the rest of the + // original string after the second @ and append @string to the new + // classname + + const char *ptr = 0; + if (val && *val && (ptr = strstr(val, "@"))) + { + int len = int(ptr - val); + NSString newClass = NSString(val, len) + "@" + + DS_JAR_FILE_NAME; + ++ptr; + if (*ptr && (ptr = strstr(ptr, "@"))) { + newClass = NSString(val, len) + "@" + + DS_JAR_FILE_NAME + ptr; + } + repEntry.setAttribute(replace[ii], newClass); + } + } + + le = repEntry.replace(repEntry.entryDN()); + if (le != OKAY) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "ERROR: Could not update Directory Server Instance\n" + "URL %s user id %s DN %s (%d:%s)" , + installInfo->get(SLAPD_KEY_K_LDAP_URL), + installInfo->get(SLAPD_KEY_SERVER_ADMIN_ID), + (const char *)repEntry.entryDN(), + le.errorCode(), le.msg()); + return le.errorCode(); + } + } + while (ldapent.next() == OKAY); + + return 0; +} diff --git a/ldap/admin/src/configure_instance.h b/ldap/admin/src/configure_instance.h new file mode 100644 index 00000000..3da7670d --- /dev/null +++ b/ldap/admin/src/configure_instance.h @@ -0,0 +1,53 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/*********************************************************************** +** +** +** NAME +** configure_instance.h +** +** DESCRIPTION +** +** +** AUTHOR +** Rich Megginson <richm@netscape.com> +** +***********************************************************************/ + +#ifndef _CONFIGURE_INSTANCE_H_ +#define _CONFIGURE_INSTANCE_H_ + +#include "create_instance.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int +create_config_from_inf( + server_config_s *cf, + int argc, + char *argv[] +); + +int +configure_instance_with_config( + server_config_s *cf, + int verbose, /* if false, silent; if true, verbose */ + const char *lfile /* log file */ +); + +int +configure_instance(); + +int +reconfigure_instance(int argc, char *argv[]); + +#ifdef __cplusplus +} +#endif + +#endif /* _CONFIGURE_INSTANCE_H_ */ diff --git a/ldap/admin/src/create_instance.c b/ldap/admin/src/create_instance.c new file mode 100644 index 00000000..20064b00 --- /dev/null +++ b/ldap/admin/src/create_instance.c @@ -0,0 +1,4640 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * create_instance.c: Routines for creating an instance of a Directory Server + * + * These routines are not thread safe. + * + * Rob McCool + */ + +#define GW_CONF 1 +#define PB_CONF 2 + +#include "create_instance.h" +#include "cfg_sspt.h" + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +#include <sys/stat.h> +#include <ctype.h> + +#define PATH_SIZE 1024 +#define ERR_SIZE 8192 + +/* delay time in seconds between referential integrity updates + 0 means continues */ +#define REFERINT_DELAY 0 + +/* 1=log changes for replaction, 0=don't replicate changes */ +#define REFERINT_LOG_CHANGES 0 + +#include "dsalib.h" +#include "dirver.h" + +#include "nspr.h" +#include "plstr.h" + +#ifdef XP_WIN32 +#define NOT_ABSOLUTE_PATH(str) \ + ((str[0] != '/') && (str[0] != '\\') && (str[2] != '/') && (str[2] != '\\')) +#define EADDRINUSE WSAEADDRINUSE +#define EACCES WSAEACCES +#include <winsock.h> +#include <io.h> +#include <regparms.h> +#include <nt/ntos.h> +#define SHLIB_EXT "dll" +#else +#define NOT_ABSOLUTE_PATH(str) (str[0] != '/') +#include <errno.h> +#include <sys/types.h> + +#if !defined(HPUX) && !defined(LINUX2_0) +#include <sys/select.h> /* FD_SETSIZE */ +#else +#include <sys/types.h> /* FD_SETSIZE is in types.h on HPUX */ +#endif + +#if !defined(_WIN32) && !defined(AIX) +#include <sys/resource.h> /* get/setrlimit stuff */ +#endif + +#include <sys/socket.h> /* socket flags */ +#include <netinet/in.h> /* sockaddr_in */ +#include <arpa/inet.h> /* inet_addr */ +#ifdef HPUX +#define SHLIB_EXT "sl" +#else +#define SHLIB_EXT "so" +#endif + +#endif + +/* + NT doesn't strictly need these, but the libadmin API which is emulated + below uses them. + */ +#define NEWSCRIPT_MODE 0755 +#define NEWFILE_MODE 0644 +#define NEWDIR_MODE 0755 +#define NEWSECDIR_MODE 0700 + +#include <stdarg.h> + +#ifdef XP_WIN32 + +OS_TYPE NS_WINAPI INFO_GetOperatingSystem (); +DWORD NS_WINAPI SERVICE_ReinstallNTService( LPCTSTR szServiceName, + LPCTSTR szServiceDisplayName, + LPCTSTR szServiceExe ); + + +#endif +static void ds_gen_index(FILE* f, char* belowdn); +static char *ds_gen_orgchart_conf(char *sroot, char *cs_path, server_config_s *cf); +static char *ds_gen_gw_conf(char *sroot, char *cs_path, server_config_s *cf, int conf_type); +static char *install_ds(char *sroot, server_config_s *cf, char *param_name); + +static int write_ldap_info(char *slapd_server_root, server_config_s *cf); +static char *gen_presence_init_script(char *sroot, server_config_s *cf, + char *cs_path); +static int init_presence(char *sroot, server_config_s *cf, char *cs_path); + +#if defined( SOLARIS ) +/* + * Solaris 9+ specific installation + */ +extern int iDSISolaris; +static char *sub_token(const char *, const char *, int, const char *, int); +/* + * If for some reasons, sub_token fails to generate the + * "etc" and "var" server_root from the actual "server_root", + * then the following hard-coded pathnames will be used. + */ +#define SOLARIS_ETC_DIR "/etc/iplanet/ds5" +#define SOLARIS_VAR_DIR "/var/ds5" + +/* + * Solaris 9+ specific installation + * The following function replaces the first occurence + * of "token" in the string "s" by "replace" + */ +static char * +sub_token(const char *s, const char *token, int tokenlen, + const char *replace, int replacelen) +{ + char *n = 0, *d; + char *ptr = (char*)strstr(s, token); + const char *begin; + int len; + if (!ptr) + return n; + + d = n = (char *) calloc(strlen(s) + replacelen + 1, 1); + if (!n) + return n; + begin = s; + len = (int)(ptr - begin); + strncpy(d, begin, len); + d += len; + begin = ptr + tokenlen; + len = replacelen; + strncpy(d, replace, len); + d += len; + for (ptr = (char *)begin; ptr && *ptr; LDAP_UTF8INC(ptr)) + { + *d = *ptr; + LDAP_UTF8INC(d); + } + *d = 0; + return n; +} +#endif /* SOLARIS */ + +static char *make_error(char *fmt, ...) +{ + static char errbuf[ERR_SIZE]; + va_list args; + + va_start(args, fmt); + vsprintf(errbuf, fmt, args); + va_end(args); + return errbuf; +} + + +/* This is to determine if we can skip the port number checks. During +migration or server cloning, we may want to copy over an old configuration, +including the old port number, which may not currently have permission to +use; if we don't need to start the server right away, we can skip +certain checks +*/ +static int needToStartServer(server_config_s *cf) +{ + if (cf && ( + (cf->cfg_sspt && !strcmp(cf->cfg_sspt, "1")) || + (cf->start_server && !strcmp(cf->start_server, "1")) + )) + { + return 1; + } + + return 0; +} + +static char * +myStrdup(const char *s) +{ + if (s == NULL) + return (char *)s; + + return strdup(s); +} + +static int getSuiteSpotUserGroup(server_config_s* cf) +{ +#ifdef XP_UNIX + static const char *ssUsersFile = "shared/config/ssusers.conf"; + char realFile[PATH_SIZE]; + char buf[1024]; + FILE *fp = NULL; + int status = 1; + + if (cf->servuser) + return 0; + + sprintf(realFile, "%s/%s", cf->sroot, ssUsersFile); + if (!(fp = fopen(realFile, "r"))) + return 1; + + while (fgets(buf, sizeof(buf), fp)) + { + char *p = NULL; + + if (buf[0] == '#' || buf[0] == '\n') + continue; + + buf[strlen(buf) - 1] = 0; + if (p = strstr(buf, "SuiteSpotUser")) + { + p += strlen("SuiteSpotUser"); + while (ldap_utf8isspace(p)) + LDAP_UTF8INC(p); + cf->servuser = strdup(p); + status = 0; + break; + } + } + + if (fp) + fclose(fp); + + return status; +#else + return 0; +#endif +} + +/* ----------------------- Create default settings ------------------------ */ + + +void set_defaults(char *sroot, char *hn, server_config_s *conf) +{ + char *id = 0, *t = 0; + + conf->sroot = sroot; + + if (hn) + { + if( (t = strchr(hn, '.')) ) + *t = '\0'; + id = (char *) malloc(strlen(hn) + 1); + sprintf(id, "%s", hn); + if(t) + *t = '.'; + } + + conf->servname = hn; + conf->bindaddr = ""; + conf->servport = "80"; + conf->cfg_sspt = NULL; + conf->suitespot3x_uid = NULL; + conf->cfg_sspt_uid = NULL; + conf->cfg_sspt_uidpw = NULL; + conf->servport = "389"; + conf->secserv = "off"; + conf->secservport = "636"; + conf->ntsynch = "off"; + conf->ntsynchssl = "on"; + conf->ntsynchport = "5009"; + conf->rootpw = ""; + conf->roothashedpw = ""; + conf->loglevel = NULL; + if (getenv("DEBUG_DS_LOG_LEVEL")) + conf->loglevel = getenv("DEBUG_DS_LOG_LEVEL"); + conf->suffix = "dc=example, dc=com"; +#ifndef DONT_ALWAYS_CREATE_NETSCAPEROOT + conf->netscaperoot = name_netscaperootDN; +#endif /* DONT_ALWAYS_CREATE_NETSCAPEROOT */ +#define CREATE_SAMPLE_SUFFIX +#ifdef CREATE_SAMPLE_SUFFIX + conf->samplesuffix = "dc=example, dc=com"; +#endif /* CREATE_SAMPLE_SUFFIX */ +#ifdef TEST_CONFIG + conf->netscaperoot = "cn=config40"; +#endif /* TEST_CONFIG */ + +#define ROOT_RDN "cn=Directory Manager" + conf->rootdn = ROOT_RDN; +/* conf->rootdn = malloc(strlen(ROOT_RDN) + 2 + strlen(conf->suffix) + 1); + sprintf(conf->rootdn, "%s, %s", ROOT_RDN, conf->suffix);*/ + conf->servid = id; + +#ifdef XP_UNIX + conf->servuser = NULL; +#ifdef THREAD_NSPR_KERNEL + conf->numprocs = "1"; + conf->maxthreads = "128"; +#else + conf->numprocs = "4"; + conf->maxthreads = "32"; +#endif +#else /* XP_WIN32 */ + conf->maxthreads = "32"; +#endif + conf->minthreads = "4"; + + conf->upgradingServer = 0; + + conf->start_server = "1"; + conf->admin_domain = NULL; + conf->config_ldap_url = NULL; + conf->user_ldap_url = NULL; + conf->use_existing_config_ds = 0; + conf->use_existing_user_ds = 0; + conf->consumerdn = NULL; + conf->disable_schema_checking = NULL; + conf->install_ldif_file = NULL; +} + + +/* ----------------- Sanity check a server configuration ------------------ */ + + +char *create_instance_checkport(char *, char *); +char *create_instance_checkuser(char *); +int create_instance_numbers(char *); +int create_instance_exists(char *fn); +char *create_instance_copy(char *, char *, int); +char *create_instance_concatenate(char *, char *, int); +int create_instance_mkdir(char *, int); +char *create_instance_mkdir_p(char *, int); + +#if defined( SOLARIS ) +/* + * Solaris 9+ specific installation + */ +int create_instance_symlink(char *, char *); +#endif /* SOLARIS */ + + +/* + returns NULL if the given dn is a valid dn, or an error string +*/ +static char * +isAValidDN(const char *dn_to_test) +{ + char *t = 0; + + if (!dn_to_test || !*dn_to_test) + { + t = "No value specified for the parameter."; + } + else + { + char **rdnList = ldap_explode_dn(dn_to_test, 0); + char **rdnNoTypes = ldap_explode_dn(dn_to_test, 1); + if (!rdnList || !rdnList[0] || !rdnNoTypes || !rdnNoTypes[0] || + !*rdnNoTypes[0] || !PL_strcasecmp(rdnList[0], rdnNoTypes[0])) + { + t = make_error("The given value [%s] is not a valid DN.", + dn_to_test); + } + if (rdnList) + ldap_value_free(rdnList); + if (rdnNoTypes) + ldap_value_free(rdnNoTypes); + } + + if (t) + return t; + + return NULL; +} + +/* + prints a message if the given dn uses LDAPv2 style quoting +*/ +void +checkForLDAPv2Quoting(const char *dn_to_test) +{ + if (ds_dn_uses_LDAPv2_quoting(dn_to_test)) + { + char *newdn = strdup(dn_to_test); + char *t; + dn_normalize_convert(newdn); + t = make_error( + "The given value [%s] is quoted in the deprecated LDAPv2 style\n" + "quoting format. It will be automatically converted to use the\n" + "LDAPv3 style escaped format [%s].", dn_to_test, newdn); + free(newdn); + ds_show_message(t); + } + + return; +} + +/* + returns NULL if the given string contains no 8 bit chars, otherwise an + error message +*/ +static char * +contains8BitChars(const char *s) +{ + char *t = 0; + + if (s && *s) + { + for (; !t && *s; ++s) + { + if (*s & 0x80) + { + t = make_error("The given value [%s] contains invalid 8 bit characters.", + s); + } + } + } + + return t; +} + +static char *sanity_check(server_config_s *cf, char *param_name) +{ + char *t, fn[PATH_SIZE]; + register int x; + + if (!param_name) + return "Parameter param_name is null"; + + /* if we don't need to start the server right away, we can skip the + port number checks + */ + if (!needToStartServer(cf)) + { + if( (t = create_instance_checkport(cf->bindaddr, cf->servport)) ) + { + strcpy(param_name, "servport"); + return t; + } + + if ( cf->secserv && (strcmp(cf->secserv, "on") == 0) && (cf->secservport != NULL) && + (*(cf->secservport) != '\0') ) { + if ( (t = create_instance_checkport(cf->bindaddr, cf->secservport)) ) { + strcpy(param_name, "secservport"); + return t; + } + } + if ( cf->ntsynch && (strcmp(cf->ntsynch, "on") == 0) && (cf->ntsynchport != NULL) && + (*(cf->ntsynchport) != '\0') ) { + if ( (t = create_instance_checkport(cf->bindaddr, cf->ntsynchport)) ) { + strcpy(param_name, "ntsynchport"); + return t; + } + } + } + + /* is the server identifier good? */ + for(x=0; cf->servid[x]; x++) { + if(strchr("/ &;`'\"|*!?~<>^()[]{}$\\", cf->servid[x])) { + strcpy(param_name, "servid"); + return make_error("You used a shell-specific character in " + "your server id (the character was %c).", + cf->servid[x]); + } + } + /* has that identifier already been used? */ + sprintf(fn, "%s%c%s-%s", cf->sroot, FILE_PATHSEP, + PRODUCT_NAME, cf->servid); + +/* Not an error to upgrade! ??? + if ( !cf->upgradingServer ) { + if(create_instance_exists(fn)) { + strcpy(param_name, "servid"); + return make_error ("A server named '%s' already exists." + "\nPlease choose another server identifier.", + cf->servid); + } + } + */ + +#ifdef XP_UNIX + if( (t = create_instance_checkuser(cf->servuser)) ) + { + strcpy(param_name, "servuser"); + return t; + } +#endif + + /* make sure some drooling imbecile doesn't put in bogus numbers */ +#ifdef XP_UNIX + if((!create_instance_numbers(cf->numprocs)) || (atoi(cf->numprocs) <= 0)) + { + strcpy(param_name, "numprocs"); + return ("The number of processes must be not be zero or " + "negative."); + } +#endif + if((!create_instance_numbers(cf->maxthreads)) || (atoi(cf->maxthreads) <= 0)) + { + strcpy(param_name, "maxthreads"); + return ("The maximum threads must be not be zero or negative."); + } + if((!create_instance_numbers(cf->minthreads)) || (atoi(cf->minthreads) <= 0)) + { + strcpy(param_name, "minthreads"); + return ("The minumum threads must be not be zero or negative."); + } + + if((atoi(cf->minthreads)) > (atoi(cf->maxthreads))) + { + strcpy(param_name, "minthreads"); + return ("Minimum threads must be less than maximum threads."); + } + + /* see if the DN parameters are valid DNs */ + if (!cf->use_existing_user_ds && (t = isAValidDN(cf->suffix))) + { + strcpy(param_name, "suffix"); + return t; + } + checkForLDAPv2Quoting(cf->suffix); + + if (t = isAValidDN(cf->rootdn)) + { + strcpy(param_name, "rootdn"); + return t; + } + checkForLDAPv2Quoting(cf->rootdn); + + if (cf->replicationdn && *cf->replicationdn && (t = isAValidDN(cf->replicationdn))) + { + strcpy(param_name, "replicationdn"); + return t; + } + checkForLDAPv2Quoting(cf->replicationdn); + + if (cf->consumerdn && *cf->consumerdn && (t = isAValidDN(cf->consumerdn))) + { + strcpy(param_name, "consumerdn"); + return t; + } + checkForLDAPv2Quoting(cf->consumerdn); + + if (cf->changelogsuffix && *cf->changelogsuffix && + (t = isAValidDN(cf->changelogsuffix))) + { + strcpy(param_name, "changelogsuffix"); + return t; + } + checkForLDAPv2Quoting(cf->changelogsuffix); + + if (cf->netscaperoot && *cf->netscaperoot && + (t = isAValidDN(cf->netscaperoot))) + { + strcpy(param_name, "netscaperoot"); + return t; + } + checkForLDAPv2Quoting(cf->netscaperoot); + + if (cf->samplesuffix && *cf->samplesuffix && + (t = isAValidDN(cf->samplesuffix))) + { + strcpy(param_name, "samplesuffix"); + return t; + } + checkForLDAPv2Quoting(cf->samplesuffix); + + if (t = contains8BitChars(cf->rootpw)) + { + strcpy(param_name, "rootpw"); + return t; + } + + if (t = contains8BitChars(cf->cfg_sspt_uidpw)) + { + strcpy(param_name, "cfg_sspt_uidpw"); + return t; + } + + if (t = contains8BitChars(cf->replicationpw)) + { + strcpy(param_name, "replicationpw"); + return t; + } + + if (t = contains8BitChars(cf->consumerpw)) + { + strcpy(param_name, "consumerpw"); + return t; + } + + if (cf->cfg_sspt_uid && *cf->cfg_sspt_uid) + { + /* + If it is a valid DN, ok. Otherwise, it should be a uid, and should + be checked for 8 bit chars + */ + if (t = isAValidDN(cf->cfg_sspt_uid)) + { + if (t = contains8BitChars(cf->cfg_sspt_uid)) + { + strcpy(param_name, "cfg_sspt_uid"); + return t; + } + } + else + checkForLDAPv2Quoting(cf->cfg_sspt_uid); + } + + return NULL; +} + +/* ----- From a configuration, set up a new server in the server root ----- */ + +/* ------------------ UNIX utilities for server creation ------------------ */ + +#ifdef XP_UNIX + +#include <unistd.h> +#include <pwd.h> + +char* +chownfile (struct passwd* pw, char* fn) +{ + if (pw != NULL && chown (fn, pw->pw_uid, pw->pw_gid) == -1) { + if (pw->pw_name != NULL) { + return make_error ("Could not change owner of %s to %s.", + fn, pw->pw_name); + } else { + return make_error ("Could not change owner of %s to (UID %li, GID %li).", + fn, (long)(pw->pw_uid), (long)(pw->pw_gid)); + } + } + return NULL; +} + +char *chownlogs(char *sroot, char *user) +{ + struct passwd *pw; + char fn[PATH_SIZE]; + if(user && *user && !geteuid()) { + if(!(pw = getpwnam(user))) + return make_error("Could not find UID and GID of user '%s'.", + user); + sprintf(fn, "%s%clogs", sroot, FILE_PATHSEP); + return chownfile (pw, fn); + } + return NULL; +} + +char *chownconfig(char *sroot, char *user) +{ + struct passwd *pw; + char fn[PATH_SIZE]; + if(user && *user && !geteuid()) { + if(!(pw = getpwnam(user))) + return make_error("Could not find UID and GID of user '%s'.", + user); + sprintf(fn, "%s%cconfig", sroot, FILE_PATHSEP); + return chownfile (pw, fn); + } + return NULL; +} + +#else + +#define chownfile(a, b) +#define chownlogs(a, b) +#define chownconfig(a, b) +#define chownsearch(a, b) + +#endif + +char *gen_script(char *s_root, char *name, char *fmt, ...) +{ + char fn[PATH_SIZE]; + FILE *f; + char *shell = "/bin/sh"; + va_list args; + + sprintf(fn, "%s%c%s", s_root, FILE_PATHSEP, name); + if(!(f = fopen(fn, "w"))) + return make_error("Could not write to %s (%s).", fn, ds_system_errmsg()); + va_start(args, fmt); +#if !defined( XP_WIN32 ) +#if defined( OSF1 ) + /* + The standard /bin/sh has some rather strange behavior with "$@", + so use the posix version wherever possible. OSF1 4.0D should + always have this one available. + */ + if (!access("/usr/bin/posix/sh", 0)) + shell = "/usr/bin/posix/sh"; +#endif /* OSF1 */ + fprintf(f, "#!%s\n\n", shell); + /* + Neutralize shared library access. + + On HP-UX, SHLIB_PATH is the historical variable. + However on HP-UX 64 bit, LD_LIBRARY_PATH is also used. + We unset both too. + */ +#if defined( SOLARIS ) || defined( OSF1 ) || defined( LINUX2_0 ) + fprintf(f, "unset LD_LIBRARY_PATH\n"); +#endif +#if defined( HPUX ) + fprintf(f, "unset SHLIB_PATH\n"); + fprintf(f, "unset LD_LIBRARY_PATH\n"); +#endif +#if defined( AIX ) + fprintf(f, "unset LIBPATH\n"); +#endif +#endif + vfprintf(f, fmt, args); + +#if defined( XP_UNIX ) + fchmod(fileno(f), NEWSCRIPT_MODE); +#endif + fclose(f); +#if defined( XP_WIN32 ) + chmod( fn, NEWSCRIPT_MODE); +#endif + return NULL; +} + +char *gen_perl_script(char *s_root, char *cs_path, char *name, char *fmt, ...) +{ + char myperl[PATH_SIZE]; + char fn[PATH_SIZE]; + FILE *f; + va_list args; + + sprintf(fn, "%s%c%s", cs_path, FILE_PATHSEP, name); + sprintf(myperl, "%s%cbin%cslapd%cadmin%cbin%cperl", + s_root, FILE_PATHSEP, FILE_PATHSEP, + FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP); + if(!(f = fopen(fn, "w"))) + return make_error("Could not write to %s (%s).", fn, ds_system_errmsg()); + va_start(args, fmt); +#if !defined( XP_WIN32 ) + fprintf(f, "#!%s\n\n", myperl); +#endif + vfprintf(f, fmt, args); + +#if defined( XP_UNIX ) + fchmod(fileno(f), NEWSCRIPT_MODE); +#endif + fclose(f); +#if defined( XP_WIN32 ) + chmod( fn, NEWSCRIPT_MODE); +#endif + +#if defined( SOLARIS ) + /* + * Solaris 9+ specific installation + * Log all non <server_root>/slapd-identifier files/directories + * created by the post_installer so that they can be removed + * during un-install. + */ + if (iDSISolaris) + logUninstallInfo(s_root, PRODUCT_NAME, PRODUCT_NAME, fn); +#endif + + return NULL; +} + +char *gen_perl_script_auto(char *s_root, char *cs_path, char *name, + server_config_s *cf) +{ + char myperl[PATH_SIZE]; + char fn[PATH_SIZE], ofn[PATH_SIZE]; + const char *table[10][2]; + + sprintf(ofn, "%s%cbin%cslapd%cadmin%cscripts%ctemplate-%s", s_root, + FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, + FILE_PATHSEP, name); + sprintf(fn, "%s%c%s", cs_path, FILE_PATHSEP, name); + sprintf(myperl, "!%s%cbin%cslapd%cadmin%cbin%cperl", + s_root, FILE_PATHSEP, FILE_PATHSEP, + FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP); + + table[0][0] = "DS-ROOT"; + table[0][1] = s_root; + table[1][0] = "MY-DS-ROOT"; + table[1][1] = cs_path; + table[2][0] = "SEP"; + table[2][1] = FILE_PATHSEPP; + table[3][0] = "SERVER-NAME"; + table[3][1] = cf->servname; + table[4][0] = "SERVER-PORT"; + table[4][1] = cf->servport; + table[5][0] = "PERL-EXEC"; + table[6][0] = "DEV-NULL"; +#if !defined( XP_WIN32 ) + table[5][1] = myperl; + table[6][1] = " /dev/null "; +#else + table[5][1] = " perl script"; + table[6][1] = " NUL "; +#endif + table[7][0] = "ROOT-DN"; + table[7][1] = cf->rootdn; + table[8][0] = table[8][1] = NULL; + + if (generate_script(ofn, fn, NEWSCRIPT_MODE, table) != 0) { + return make_error("Could not write %s to %s (%s).", ofn, fn, + ds_system_errmsg()); + } +#if defined( SOLARIS ) + /* + * Solaris 9+ specific installation + */ + if (iDSISolaris) + logUninstallInfo(s_root, PRODUCT_NAME, PRODUCT_NAME, fn); +#endif + + return NULL; +} + +char *gen_perl_script_auto_for_migration(char *s_root, char *cs_path, char *name, + server_config_s *cf) +{ + char myperl[PATH_SIZE]; + char fn[PATH_SIZE], ofn[PATH_SIZE]; + const char *table[10][2]; + + sprintf(ofn, "%s%cbin%cslapd%cadmin%cscripts%ctemplate-%s", s_root, + FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, + FILE_PATHSEP, name); + sprintf(fn, "%s%cbin%cslapd%cadmin%cbin%c%s", s_root, FILE_PATHSEP, + FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, name); + sprintf(myperl, "!%s%cbin%cslapd%cadmin%cbin%cperl", + s_root, FILE_PATHSEP, FILE_PATHSEP, + FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP); + + table[0][0] = "DS-ROOT"; + table[0][1] = s_root; + table[1][0] = "MY-DS-ROOT"; + table[1][1] = cs_path; + table[2][0] = "SEP"; + table[2][1] = FILE_PATHSEPP; + table[3][0] = "SERVER-NAME"; + table[3][1] = cf->servname; + table[4][0] = "SERVER-PORT"; + table[4][1] = cf->servport; + table[5][0] = "PERL-EXEC"; + table[6][0] = "DEV-NULL"; +#if !defined( XP_WIN32 ) + table[5][1] = myperl; + table[6][1] = " /dev/null "; +#else + table[5][1] = " perl script"; + table[6][1] = " NUL "; +#endif + table[7][0] = "ROOT-DN"; + table[7][1] = cf->rootdn; + table[8][0] = table[8][1] = NULL; + + if (generate_script(ofn, fn, NEWSCRIPT_MODE, table) != 0) { + return make_error("Could not write %s to %s (%s).", ofn, fn, + ds_system_errmsg()); + } + +#if defined( SOLARIS ) + /* + * Solaris 9+ specific installation + */ + if (iDSISolaris) + logUninstallInfo(s_root, PRODUCT_NAME, PRODUCT_NAME, fn); +#endif + + return NULL; +} + +/* ------------------ NT utilities for server creation ------------------ */ + +#ifdef XP_WIN32 + +char * +service_exists(char *servid) +{ + DWORD status, lasterror = 0; + char szServiceName[MAX_PATH] = {0}; + sprintf(szServiceName,"%s-%s", SVR_ID_SERVICE, servid); + /* if the service already exists, error */ + status = SERVICE_GetNTServiceStatus(szServiceName, &lasterror ); + if ( (lasterror == ERROR_SERVICE_DOES_NOT_EXIST) || + (status == SERVRET_ERROR) || (status == SERVRET_REMOVED) ) { + return 0; + } else { return + make_error("Server %s already exists: cannot create another. " + "Please choose a different name or delete the " + "existing server.", + szServiceName); + } + + return 0; +} + +void setup_nteventlogging(char *szServiceId, char *szMessageFile) +{ + HKEY hKey; + char szKey[MAX_PATH]; + DWORD dwData; + + sprintf(szKey, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s", szServiceId); + + if(RegCreateKey(HKEY_LOCAL_MACHINE, szKey, &hKey) == ERROR_SUCCESS) + { + if(RegSetValueEx(hKey, "EventMessageFile", 0, REG_SZ, (LPBYTE)szMessageFile, strlen(szMessageFile) + 1) == ERROR_SUCCESS) + { + dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; + RegSetValueEx(hKey, "TypesSupported", 0, REG_DWORD, (LPBYTE) &dwData, sizeof(DWORD)); + } + RegCloseKey(hKey); + } +} + + +char *add_ntservice(server_config_s *cf) +{ + char szMessageFile[MAX_PATH]; + char szServiceExe[MAX_PATH], szServiceDisplayName[MAX_PATH], szServiceName[MAX_PATH]; + DWORD dwLastError; + + sprintf ( szServiceExe, "%s/bin/%s/server/%s", cf->sroot, + SVR_DIR_ROOT, SVR_EXE); + sprintf ( szServiceName,"%s-%s", SVR_ID_SERVICE, cf->servid); + sprintf ( szServiceDisplayName, "%s (%s)", SVR_NAME_FULL_VERSION, + cf->servid); + + /* install new service - if already installed, try and remove and + then reinstall */ + dwLastError = SERVICE_ReinstallNTService( szServiceName, + szServiceDisplayName, szServiceExe ); + if ( dwLastError != NO_ERROR ) { + return make_error ( "While installing %s Service, the " + "NT Service Manager reported error %d (%s)", + szServiceDisplayName, dwLastError, ds_system_errmsg() ); + } + + // setup event logging registry keys, do this after service creation + sprintf(szMessageFile, "%s\\bin\\%s\\server\\%s", cf->sroot, + SVR_DIR_ROOT, "slapdmessages30.dll"); + setup_nteventlogging(szServiceName, szMessageFile); + + // TODO: add perfmon setup code -ahakim 11/22/96 + return NULL; +} + +char *setup_ntserver(server_config_s *cf) +{ + char line[MAX_PATH], *sroot = cf->sroot; + char subdir[MAX_PATH]; + char NumValuesBuf[3]; + DWORD Result; + HKEY hServerKey; + DWORD NumValues; + DWORD iterator; + int value_already_exists = 0; + DWORD type_buffer; + char value_data_buffer[MAX_PATH]; + DWORD sizeof_value_data_buffer; + + /* MLM - Adding ACL directories authdb and authdb/default */ + sprintf(subdir, "%s%cauthdb", sroot, FILE_PATHSEP); + if( (create_instance_mkdir(subdir, NEWDIR_MODE)) ) + return make_error("mkdir %s failed (%s)", subdir, ds_system_errmsg()); + + sprintf(subdir, "%s%cauthdb%cdefault", sroot, FILE_PATHSEP, FILE_PATHSEP); + if( (create_instance_mkdir(subdir, NEWDIR_MODE)) ) + return make_error("mkdir %s failed (%s)", subdir, ds_system_errmsg()); + + /* Create DS-nickname (corresponding to ServiceID) key in registry */ + sprintf(line, "%s\\%s\\%s-%s", KEY_SOFTWARE_NETSCAPE, SVR_KEY_ROOT, + SVR_ID_SERVICE, cf->servid); + + Result = RegCreateKey(HKEY_LOCAL_MACHINE, line, &hServerKey); + if (Result != ERROR_SUCCESS) { + return make_error("Could not create registry server key %s - error %d (%s)", + line, GetLastError(), ds_system_errmsg()); + } + + // note that SVR_ID_PRODUCT is being used here, which is of the form dsX + // as opposed to SVR_ID_SERVICE, which is of the form dsX30 + sprintf(line, "%s\\%s-%s\\config", sroot, SVR_ID_PRODUCT, cf->servid); + Result = RegSetValueEx(hServerKey, VALUE_CONFIG_PATH, 0, REG_SZ, + line, strlen(line) + 1); + + RegCloseKey(hServerKey); + + /* Create SNMP key in registry */ + sprintf(line, "%s\\%s\\%s", KEY_SOFTWARE_NETSCAPE, SVR_KEY_ROOT, + KEY_SNMP_CURRENTVERSION); + + Result = RegCreateKey(HKEY_LOCAL_MACHINE, line, &hServerKey); + if (Result != ERROR_SUCCESS) { + return make_error("Could not create registry server key %s - error %d (%s)", + line, GetLastError(), ds_system_errmsg()); + } + + + /* Create the SNMP Pathname value */ + sprintf(line, "%s\\%s", sroot, SNMP_PATH); + Result = RegSetValueEx(hServerKey, VALUE_APP_PATH, 0, REG_SZ, + line, strlen(line) + 1); + RegCloseKey(hServerKey); + + /* write SNMP extension agent value to Microsoft SNMP Part of Registry) */ + sprintf(line, "%s\\%s", KEY_SERVICES, KEY_SNMP_SERVICE); + Result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + line, + 0, + KEY_ALL_ACCESS, + &hServerKey); + /* if its there set the value, otherwise go on to the next thing */ + if (Result == ERROR_SUCCESS) + { + /* extension agents should have linearly increasing value, + make sure it doesn't already exist, find last one and increment + value for new key */ + + sprintf(line, "%s\\%s\\%s", KEY_SOFTWARE_NETSCAPE, SVR_KEY_ROOT, KEY_SNMP_CURRENTVERSION); + + Result = RegQueryInfoKey(hServerKey, NULL, NULL, NULL, NULL, NULL, + NULL, &NumValues, NULL, NULL, NULL, NULL); + + if (Result == ERROR_SUCCESS){ + for(iterator = 0; iterator <= NumValues; iterator++) + { + /* initialize to max size to avoid + ERROR_MORE_DATA because size gets set + to actual size of key after call + to RegQueryValueEx, previously there + was a bug if last key was smaller + than this one it would return ERROR_MORE_DATA + and it would not find the key if it was already there + */ + sizeof_value_data_buffer=MAX_PATH; + sprintf(NumValuesBuf, "%d", iterator); + Result = RegQueryValueEx(hServerKey, + NumValuesBuf, + NULL, + &type_buffer, + value_data_buffer, + &sizeof_value_data_buffer + ); + + if(!strcmp(value_data_buffer, line)) + { + value_already_exists = 1; + } + } + } + + if(!value_already_exists) + { + sprintf(NumValuesBuf, "%d", NumValues + 1); + Result = RegSetValueEx(hServerKey, NumValuesBuf, 0, REG_SZ, + line, strlen(line) + 1); + + /* couldn't set this value, so there is a real problem */ + if (Result != ERROR_SUCCESS) + { + return make_error("Could not set value %s (%d)", + line, Result); + } + } + + } + RegCloseKey(hServerKey); + + return NULL; +} +#endif + +/* ---------------------- Create configuration files ---------------------- */ + + +char *create_server(server_config_s *cf, char *param_name) +{ + char line[PATH_SIZE], *t, *sroot = cf->sroot; + char subdir[PATH_SIZE]; + +#if defined( SOLARIS ) + /* + * Solaris 9+ specific installation + */ + char otherline[PATH_SIZE]; + char subdirvar[PATH_SIZE]; + char subdiretc[PATH_SIZE]; + char *sub; +#endif /* SOLARIS */ + + if (param_name) + param_name[0] = 0; /* init to empty string */ + +#ifdef XP_UNIX + if (!cf->servuser) + getSuiteSpotUserGroup(cf); +#else + /* Abort if the service exists on NT */ + if (t = service_exists(cf->servid)) { + strcpy(param_name, "servid"); + return t; + } +#endif + + if( (t = sanity_check(cf, param_name)) ) + return t; + + /* Create slapd-nickname directory */ +#if defined( SOLARIS ) + /* + * Verify if configuration is for native solaris packages + * This is because if console is used to create instance + * then -S is not passed to ds_create. + * <server_root>/.native_solaris file acts as the flag + */ + if (!iDSISolaris) { + sprintf(otherline, "%s%c.native_solaris", sroot, FILE_PATHSEP); + if (create_instance_exists(otherline)) { + iDSISolaris = 1; + } + } + + if (iDSISolaris) { + /* + * Create the slapd-nickname directory under "var" + */ + sub = sub_token(sroot,"/usr/iplanet/",13,"/var/",5); + if (sub) { + sprintf(subdirvar, "%s/"PRODUCT_NAME"-%s", sub, cf->servid); + free(sub); + } + else { + sprintf(subdirvar, "%s/"PRODUCT_NAME"-%s", SOLARIS_VAR_DIR, cf->servid); + } + if( (create_instance_mkdir_p(subdirvar, NEWDIR_MODE)) ) + return make_error("mkdir %s failed (%s)", subdirvar, ds_system_errmsg()); + + /* + * Create the slapd-nickname directory under "etc" + */ + sub = sub_token(sroot,"/usr/",5,"/etc/",5); + if (sub) { + sprintf(subdiretc, "%s/"PRODUCT_NAME"-%s", sub, cf->servid); + free(sub); + } + else { + sprintf(subdiretc, "%s/"PRODUCT_NAME"-%s", SOLARIS_ETC_DIR, cf->servid); + } + if( (create_instance_mkdir_p(subdiretc, NEWDIR_MODE)) ) + return make_error("mkdir %s failed (%s)", subdiretc, ds_system_errmsg()); + sprintf(subdir, "%s%c"PRODUCT_NAME"-%s", sroot, FILE_PATHSEP, + cf->servid); + if( (create_instance_symlink(subdirvar, subdir)) ) + return make_error("symlink %s ==> %s failed (%s)", subdir, subdirvar, ds_system_errmsg()); + } + else { + sprintf(subdir, "%s%c"PRODUCT_NAME"-%s", sroot, FILE_PATHSEP, + cf->servid); + if( (create_instance_mkdir(subdir, NEWDIR_MODE)) ) + return make_error("mkdir %s failed (%s)", subdir, ds_system_errmsg()); + } +#else + sprintf(subdir, "%s%c"PRODUCT_NAME"-%s", sroot, FILE_PATHSEP, + cf->servid); + if( (create_instance_mkdir(subdir, NEWDIR_MODE)) ) + return make_error("mkdir %s failed (%s)", subdir, ds_system_errmsg()); +#endif /* SOLARIS */ + + /* Create slapd-nickname/config directory */ + sprintf(line, "%s%cconfig", subdir, FILE_PATHSEP); + if( (create_instance_mkdir(line, NEWDIR_MODE)) ) + return make_error("mkdir %s failed (%s)", line, ds_system_errmsg()); +#if defined( SOLARIS ) + if (iDSISolaris) { + sprintf(line, "%s%cconfig", subdirvar, FILE_PATHSEP); + sprintf(otherline, "%s%cconfig", subdiretc, FILE_PATHSEP); + if( (create_instance_symlink(line, otherline)) ) + return make_error("symlink %s ==> %s failed (%s)", otherline, line, ds_system_errmsg()); + } +#endif /* SOLARIS */ + + /* Create slapd-nickname/config/schema directory */ + sprintf(line, "%s%cconfig%cschema", subdir, FILE_PATHSEP, FILE_PATHSEP); + if( (create_instance_mkdir(line, NEWDIR_MODE)) ) + return make_error("mkdir %s failed (%s)", line, ds_system_errmsg()); + + /* Create slapd-nickname/config/presence directory */ + sprintf(line, "%s%cconfig%cpresence", subdir, FILE_PATHSEP, FILE_PATHSEP); + if( (create_instance_mkdir(line, NEWDIR_MODE)) ) + return make_error("mkdir %s failed (%s)", line, ds_system_errmsg()); + + /* Create slapd-nickname/logs directory */ + sprintf(line, "%s%clogs", subdir, FILE_PATHSEP); + if( (create_instance_mkdir(line, NEWSECDIR_MODE)) ) + return make_error("mkdir %s failed (%s)", line, ds_system_errmsg()); + + /* Create httpacl directory */ + sprintf(line, "%s%chttpacl", cf->sroot, FILE_PATHSEP); + if( (create_instance_mkdir(line, NEWDIR_MODE)) ) + return make_error("mkdir %s failed (%s)", line, ds_system_errmsg()); +#if defined( SOLARIS ) + if (iDSISolaris) + logUninstallInfo(sroot, PRODUCT_NAME, PRODUCT_NAME, line); +#endif /* SOLARIS */ + +#ifdef XP_UNIX + /* Start/stop/rotate/restart scripts */ +#if defined( SOLARIS ) + if (getenv("USE_DEBUGGER") && !iDSISolaris) +#else + if (getenv("USE_DEBUGGER")) +#endif /* SOLARIS */ + { + char *debugger = getenv("DSINST_DEBUGGER"); + char *debugger_command = getenv("DSINST_DEBUGGER_CMD"); + if (! debugger) { + debugger = "/tools/ns/workshop/bin/dbx"; + } + if (! debugger_command) { + debugger_command = "echo"; /* e.g. do nothing */ + } +#ifdef OSF1 + printf("-D %s -i %s/logs/pid -d %s -z\n", subdir, subdir, + cf->loglevel ? cf->loglevel : "0"); + t = gen_script(subdir, START_SCRIPT, + "\n" + "# Script that starts the ns-slapd server.\n" + "# Exit status can be:\n" + "# 0: Server started successfully\n" + "# 1: Server could not be started\n" + "# 2: Server already running\n" + "\n" + "NETSITE_ROOT=%s\n" + "export NETSITE_ROOT\n" + "PIDFILE=%s/logs/pid\n" + "if test -f $PIDFILE ; then\n" + " PID=`cat $PIDFILE`\n" + " if kill -0 $PID > /dev/null 2>&1 ; then\n" + " echo There is an ns-slapd process already running: $PID\n" + " exit 2;\n" + " else\n" + " rm -f $PIDFILE\n" + " fi\n" + "fi\n" + "cd %s/bin/%s/server; ./%s -D %s -i %s/logs/pid -d %s -z \"$@\" &\n" + "loop_counter=1\n" + "max_count=120\n" + "while test $loop_counter -le $max_count; do\n" + " loop_counter=`expr $loop_counter + 1`\n" + " if test ! -f $PIDFILE ; then\n" + " sleep 1;\n" + " else\n" + " PID=`cat $PIDFILE`\n" + /* rbyrne: setupsdk takes any message here as an error: + " echo Server has been started. ns-slapd process started: $PID\n"*/ + " exit 0;\n" + " fi\n" + "done\n" + "echo Server not running!! Failed to start ns-slapd process.\n" + "exit 1\n", + sroot, subdir, sroot, PRODUCT_NAME, PRODUCT_BIN, subdir, + subdir, + cf->loglevel ? cf->loglevel : "0" + ); +/* + t = gen_script(subdir, START_SCRIPT, + "NETSITE_ROOT=%s\n" + "export NETSITE_ROOT\n" + "cd %s/bin/%s/server; /usr/bin/X11/xterm -fn 10x20 -sb -sl 2000 -e /bin/ladebug " + "-I /u/richm/ds50/ldapserver/ldap/servers/slapd/back-ldbm " + "-I /u/richm/ds50/ldapserver/ldap/servers/slapd " + "%s &\n", + sroot, sroot, PRODUCT_NAME, PRODUCT_BIN + ); +*/ +#else + t = gen_script(subdir, START_SCRIPT, + "\n" + "# Script that starts the ns-slapd server.\n" + "# Exit status can be:\n" + "# 0: Server started successfully\n" + "# 1: Server could not be started\n" + "# 2: Server already running\n" + "\n" + "NETSITE_ROOT=%s\n" + "export NETSITE_ROOT\n" + "PIDFILE=%s/logs/pid\n" + "if test -f $PIDFILE ; then\n" + " PID=`cat $PIDFILE`\n" + " if kill -0 $PID > /dev/null 2>&1 ; then\n" + " echo There is an ns-slapd process already running: $PID\n" + " exit 2;\n" + " else\n" + " rm -f $PIDFILE\n" + " fi\n" + "fi\n" + "if [ -x /usr/local/bin/xterm ]; then\n" + " xterm=/usr/local/bin/xterm\n" + "else\n" + " xterm=/usr/openwin/bin/xterm\n" + "fi\n" + "cd %s/bin/%s/server; $xterm -title debugger -e %s -c \"dbxenv follow_fork_mode child ; stop in main ; %s ; run -D %s -i %s/logs/pid -d %s -z $*\" %s &\n" + "loop_counter=1\n" + "max_count=120\n" + "while test $loop_counter -le $max_count; do\n" + " loop_counter=`expr $loop_counter + 1`\n" + " if test ! -f $PIDFILE ; then\n" + " sleep 1;\n" + " else\n" + " PID=`cat $PIDFILE`\n" + /* rbyrne: setupsdk takes any message here as an error: + " echo Server has been started. ns-slapd process started: $PID\n"*/ + " exit 0;\n" + " fi\n" + "done\n" + "echo Server not running!! Failed to start ns-slapd process.\n" + "exit 1\n", + sroot, subdir, sroot, PRODUCT_NAME, debugger, debugger_command, + subdir, + subdir, cf->loglevel ? cf->loglevel : "0", PRODUCT_BIN + ); +#endif + } + else + { + t = gen_script(subdir, START_SCRIPT, + "\n" + "# Script that starts the ns-slapd server.\n" + "# Exit status can be:\n" + "# 0: Server started successfully\n" + "# 1: Server could not be started\n" + "# 2: Server already running\n" + "\n" + "NETSITE_ROOT=%s\n" + "export NETSITE_ROOT\n" + "PIDFILE=%s/logs/pid\n" + "STARTPIDFILE=%s/logs/startpid\n" + "if test -f $STARTPIDFILE ; then\n" + " PID=`cat $STARTPIDFILE`\n" + " if kill -0 $PID > /dev/null 2>&1 ; then\n" + " echo There is an ns-slapd process already running: $PID\n" + " exit 2;\n" + " else\n" + " rm -f $STARTPIDFILE\n" + " fi\n" + "fi\n" + "if test -f $PIDFILE ; then\n" + " PID=`cat $PIDFILE`\n" + " if kill -0 $PID > /dev/null 2>&1 ; then\n" + " echo There is an ns-slapd process already running: $PID\n" + " exit 2;\n" + " else\n" + " rm -f $PIDFILE\n" + " fi\n" + "fi\n" + "cd %s/bin/%s/server; ./%s -D %s -i %s/logs/pid -w $STARTPIDFILE \"$@\"\n" + "if [ $? -ne 0 ]; then\n" + " exit 1\n" + "fi\n" + "\n" + "loop_counter=1\n" + "# wait for 10 seconds for the start pid file to appear\n" + "max_count=10\n" + "while test $loop_counter -le $max_count; do\n" + " loop_counter=`expr $loop_counter + 1`\n" + " if test ! -f $STARTPIDFILE ; then\n" + " sleep 1;\n" + " else\n" + " PID=`cat $STARTPIDFILE`\n" + " fi\n" + "done\n" + "if test ! -f $STARTPIDFILE ; then\n" + " echo Server failed to start !!! Please check errors log for problems\n" + " exit 1\n" + "fi\n" + "loop_counter=1\n" + "# wait for 10 minutes (600 times 1 seconds)\n" + "max_count=600\n" /* 10 minutes */ + "while test $loop_counter -le $max_count; do\n" + " loop_counter=`expr $loop_counter + 1`\n" + " if test ! -f $PIDFILE ; then\n" + " if kill -0 $PID > /dev/null 2>&1 ; then\n" + " sleep 1\n" + " else\n" + " echo Server failed to start !!! Please check errors log for problems\n" + " exit 1\n" + " fi\n" + " else\n" + " PID=`cat $PIDFILE`\n" + /* rbyrne: setupsdk takes any message here as an error: + " echo Server has been started. ns-slapd process started: $PID\n"*/ + " exit 0;\n" + " fi\n" + "done\n" + "echo Server not running!! Failed to start ns-slapd process. Please check the errors log for problems.\n" + "exit 1\n", + sroot, subdir, subdir, sroot, PRODUCT_NAME, PRODUCT_BIN, subdir, + subdir + ); + } + if(t) return t; + + t = gen_script(subdir, STOP_SCRIPT, + "\n" + "# Script that stops the ns-slapd server.\n" + "# Exit status can be:\n" + "# 0: Server stopped successfully\n" + "# 1: Server could not be stopped\n" + "# 2: Server was not running\n" + "\n" + "PIDFILE=%s/logs/pid\n" + "if test ! -f $PIDFILE ; then\n" + " echo No ns-slapd PID file found. Server is probably not running\n" + " exit 2\n" + "fi\n" + "PID=`cat $PIDFILE`\n" + "# see if the server is already stopped\n" + "kill -0 $PID > /dev/null 2>&1 || {\n" + " echo Server not running\n" + " if test -f $PIDFILE ; then\n" + " rm -f $PIDFILE\n" + " fi\n" + " exit 2\n" + "}\n" + "# server is running - kill it\n" + "kill $PID\n" + "loop_counter=1\n" + "# wait for 10 minutes (600 times 1 second)\n" + "max_count=600\n" /* 10 minutes */ + "while test $loop_counter -le $max_count; do\n" + " loop_counter=`expr $loop_counter + 1`\n" + " if kill -0 $PID > /dev/null 2>&1 ; then\n" + " sleep 1;\n" + " else\n" + " if test -f $PIDFILE ; then\n" + " rm -f $PIDFILE\n" + " fi\n" + /* rbyrne: setupsdk takes any message here as an error: + " echo Server has been stopped. ns-slapd process stopped: $PID\n"*/ + " exit 0\n" + " fi\n" + "done\n" + "if test -f $PIDFILE ; then\n" + " echo Server still running!! Failed to stop the ns-slapd process: $PID. Please check the errors log for problems.\n" + "fi\n" + "exit 1\n", + subdir); + if(t) return t; + + t = gen_script(subdir, RESTART_SCRIPT, + "\n" + "# Script that restarts the ns-slapd server.\n" + "# Exit status can be:\n" + "# 0: Server restarted successfully\n" + "# 1: Server could not be started\n" + "# 2: Server started successfully (was not running)\n" + "# 3: Server could not be stopped\n" + "\n" + "server_already_stopped=0\n" + "%s/stop-slapd\n" + "status=$?\n" + "if [ $status -eq 1 ] ; then\n" + " exit 3;\n" + "else\n" + " if [ $status -eq 2 ] ; then\n" + " server_already_stopped=1\n" + " fi\n" + "fi\n" + "%s/start-slapd\n" + "status=$?\n" + "if [ $server_already_stopped -eq 1 ] && [ $status -eq 0 ] ; then\n" + " exit 2;\n" + "fi\n" + "exit $status\n", + subdir, subdir ); + if(t) return t; + + /* logs subdir owned by server user */ + if( (t = chownlogs(subdir, cf->servuser)) ) + return t; + + /* config subdir owned by server user */ + if( (t = chownconfig(subdir, cf->servuser)) ) + return t; +#if defined( SOLARIS ) + if (iDSISolaris) { + /* Need to change owner of the etc link too */ + if( (t = chownconfig(subdiretc, cf->servuser)) ) + return t; + } +#endif /* SOLARIS */ + + +#else /* XP_WIN32 */ + /* Windows platforms have some extra setup */ + if( (t = setup_ntserver(cf)) ) + return t; + + /* generate start script */ + t = gen_script(subdir, START_SCRIPT".bat", "net start slapd-%s\n", cf->servid); + if(t) return t; + + /* generate stop script */ + t = gen_script(subdir, STOP_SCRIPT".bat", "net stop slapd-%s\n", cf->servid); + if(t) return t; + + /* generate restart script */ + t = gen_script(subdir, RESTART_SCRIPT".bat", "net stop slapd-%s\n" + "net start slapd-%s\n", cf->servid, cf->servid); + if(t) return t; + + +#endif /* XP_WIN32 */ + +#ifdef XP_WIN32 + + if ( INFO_GetOperatingSystem () == OS_WINNT ) { + + if( (t = add_ntservice(cf)) ) + return t; + } +#endif + + /* Create subdirectories and config files for directory server */ + if( (t = install_ds(sroot, cf, param_name)) ) + return t; + + /* XXXrobm using link to start script instead of automatically doing it */ + return NULL; +} + + + + +/* ------------------------- Copied from libadmin ------------------------- */ + + +/* + These replace the versions in libadmin to allow error returns. + + XXXrobm because libadmin calls itself a lot, I'm replacing ALL the + functions this file requires + */ + + +int create_instance_exists(char *fn) +{ + struct stat finfo; + + if(stat(fn, &finfo) < 0) + return 0; + else + return 1; +} + + +int create_instance_mkdir(char *dir, int mode) +{ + if(!create_instance_exists(dir)) { +#ifdef XP_UNIX + if(mkdir(dir, mode) == -1) +#else /* XP_WIN32 */ + if(!CreateDirectory(dir, NULL)) +#endif /* XP_WIN32 */ + return -1; + } + return 0; +} + + +char *create_instance_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(create_instance_mkdir(dir, mode) == -1) { + sprintf(errmsg, "mkdir %s failed (%s)", dir, ds_system_errmsg()); + return errmsg; + } + } + if(t) + { + *t = FILE_PATHSEP; + LDAP_UTF8INC(t); + } + else break; + } + return NULL; +} + + +int create_instance_numbers(char *target) +{ + char *p; + for(p=target; *p; LDAP_UTF8INC(p) ) + { + if(!ldap_utf8isdigit(p)) + return 0; + } + return 1; +} + +#if defined( SOLARIS ) +/* + * Solaris 9+ specific installation + */ +int create_instance_symlink(char *actualpath, char *sympath) +{ + if(symlink(actualpath, sympath) == -1) + return -1; + return 0; +} +#endif /* SOLARIS */ + + +/* --------------------------------- try* --------------------------------- */ + + +/* robm This doesn't use net_ abstractions because they drag in SSL */ +int trybind(char *addr, int port) +{ + int sd; + struct sockaddr_in sa_server; + int one = 1, ret; + +#ifdef XP_WIN32 + WSADATA wsd; + + if(WSAStartup(MAKEWORD(1, 1), &wsd) != 0) + return -1; +#endif + + if ((sd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1) + goto you_lose; + + if (addr == NULL) + addr = "127.0.0.1"; /* use the local loopback address */ + + memset((char *) &sa_server, 0, sizeof(sa_server)); + sa_server.sin_family=AF_INET; + sa_server.sin_addr.s_addr = inet_addr(addr); + sa_server.sin_port=htons((short)port); + ret = connect(sd, (struct sockaddr *) &sa_server,sizeof(sa_server)); + if (ret == -1) + ret = 0; /* could not connect, so port is not in use; that's good */ + else + { + ret = -1; /* connection succeeded, port in use, bad */ + errno = EADDRINUSE; + } +#ifdef XP_UNIX + close(sd); +#else + closesocket(sd); + WSACleanup(); +#endif + return ret; + + you_lose: +#ifdef XP_WIN32 + WSACleanup(); +#endif + return -1; +} + + +#ifdef XP_UNIX +#include <pwd.h> +#include <fcntl.h> + +int tryuser(char *user) +{ + struct passwd *pw; + char fn[128]; + int fd, ret; + + setpwent(); + if(!(pw = getpwnam(user))) + return -1; + + endpwent(); + + if(geteuid()) + return 0; + + sprintf(fn, "/tmp/trychown.%ld", (long)getpid()); + if( (fd = creat(fn, 0777)) == -1) + return 0; /* Hmm. */ + ret = chown(fn, pw->pw_uid, pw->pw_gid); + close(fd); + unlink(fn); + return (ret == -1 ? -2 : 0); +} +#endif /* XP_UNIX */ + + +/* --------------------------- create_instance_check* ---------------------------- */ + + +char *create_instance_checkport(char *addr, char *sport) +{ + int port; + + port = atoi(sport); + if((port < 1) || (port > 65535)) { + return ("Valid port numbers are between 1 and 65535"); + } + if(trybind(addr, port) == -1) { + if(errno == EADDRINUSE) { + return make_error("Port %d is already in use", port); + } + /* XXXrobm if admin server not running as root, you lose. */ + else if(errno == EACCES) { + return ("Ports below 1024 require super user access. " + "You must run the installation as root to install " + "on that port."); + } else { + ds_report_warning(DS_WARNING, "port", "That port is not available"); + } + } + return NULL; +} + +#ifdef XP_UNIX +char *create_instance_checkuser(char *user) +{ + if (user && *user) switch(tryuser(user)) { + case -1: + return make_error ("Can't find a user named '%s'." + "\nPlease select or create another user.", + user); + case -2: + return make_error ("Can't change a file to be owned by %s." + "\nPlease select or create another user.", + user); + } + return NULL; +} +#endif + + +/* --------------------------------- copy --------------------------------- */ + +#define COPY_BUFFER_SIZE 4096 + +#ifdef XP_UNIX + + +char *create_instance_copy(char *sfile, char *dfile, int mode) +{ + int sfd, dfd, len; + struct stat fi; + + char copy_buffer[COPY_BUFFER_SIZE]; + unsigned long read_len; + +/* Make sure we're in the right umask */ + umask(022); + + if( (sfd = open(sfile, O_RDONLY)) == -1) + return make_error("Cannot open %s for reading (%s)", sfile, + ds_system_errmsg()); + + fstat(sfd, &fi); + if(!(S_ISREG(fi.st_mode))) { + close(sfd); + return make_error("%s is not a regular file", sfile); + } + len = fi.st_size; + + if( (dfd = open(dfile, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1) + return make_error("Cannot open file %s for writing (%s)", dfile, + ds_system_errmsg()); + + while(len) { + read_len = len>COPY_BUFFER_SIZE?COPY_BUFFER_SIZE:len; + + if ( (read_len = read(sfd, copy_buffer, read_len)) == -1) { + make_error("Cannot read from file %s (%s)", + sfile, ds_system_errmsg()); + } + + if ( write(dfd, copy_buffer, read_len) != read_len) { + make_error("Error writing to file %s from copy of %s (%s)", + dfile, sfile, ds_system_errmsg()); + } + + len -= read_len; + } + close(sfd); + close(dfd); + /* BERT! */ + return NULL; +} + +#else /* XP_WIN32 */ +char *create_instance_copy(char *sfile, char *dfile, int mode) +{ + HANDLE sfd, dfd, MapHandle; + PCHAR fp; + PCHAR fpBase; + DWORD BytesWritten = 0; + DWORD len; + + if( (sfd = CreateFile(sfile, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) + == INVALID_HANDLE_VALUE) { + return make_error("Cannot open file %s for reading (%s)", sfile, + ds_system_errmsg()); + } + len = GetFileSize(sfd, NULL); + if( (MapHandle = CreateFileMapping(sfd, NULL, PAGE_READONLY, + 0, 0, NULL)) == NULL) { + return make_error("Cannot create file mapping of %s (%s)", sfile, + ds_system_errmsg()); + } + if (!(fpBase = fp = MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0))) { + return make_error("Cannot map file %s (%s)", sfile, ds_system_errmsg()); + } + if( (dfd = CreateFile(dfile, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) { + return make_error("Cannot open destination file %s for writing (%s)", + dfile, ds_system_errmsg()); + } + while ( len) { + if(!WriteFile(dfd, fp, len, &BytesWritten, NULL)) { + return ("Cannot write new file %s (%s)", dfile, ds_system_errmsg()); + } + len -= BytesWritten; + fp += BytesWritten; + } + CloseHandle(sfd); + UnmapViewOfFile(fpBase); + CloseHandle(MapHandle); + FlushFileBuffers(dfd); + CloseHandle(dfd); + /* BERT! */ + return NULL; +} +#endif + +static int +file_is_type_x(const char *dirname, const char *filename, PRFileType x) +{ + struct PRFileInfo inf; + int status = 0; + int size = strlen(dirname) + strlen(filename) + 2; /* 1 for slash + 1 for null */ + char *fullpath = calloc(sizeof(char), size); + + sprintf(fullpath, "%s/%s", dirname, filename); + if (PR_SUCCESS == PR_GetFileInfo(fullpath, &inf) && + inf.type == x) + status = 1; + + free(fullpath); + + return status; +} + +/* return true if the given path and file corresponds to a directory */ +static int +is_a_dir(const char *dirname, const char *filename) +{ + return file_is_type_x(dirname, filename, PR_FILE_DIRECTORY); +} + +/* return true if the given path and file corresponds to a regular file */ +static int +is_a_file(const char *dirname, const char *filename) +{ + return file_is_type_x(dirname, filename, PR_FILE_FILE); +} + +static char * +ds_copy_group_files_using_mode(char *src_dir, char *dest_dir, + char *filter, int use_mode) +{ + char *t = 0; + PRDir *ds = 0; + PRDirEntry *d = 0; + char src_file[PATH_SIZE], dest_file[PATH_SIZE], fullname[PATH_SIZE]; + + if(!(ds = PR_OpenDir(src_dir))) { + return make_error("Can't read directory %s (%s)", src_dir, ds_system_errmsg()); + } + while( (d = PR_ReadDir(ds, 0)) ) { + if(d->name[0] != '.') { + if(!filter || strstr(d->name, filter)) { + sprintf(fullname, "%s/%s", src_dir, d->name); + if(PR_SUCCESS != PR_Access(fullname, PR_ACCESS_EXISTS)) + continue; + sprintf(src_file, "%s%c%s", src_dir, FILE_PATHSEP, d->name); + sprintf(dest_file, "%s%c%s", dest_dir, FILE_PATHSEP, d->name); + if(is_a_dir(src_dir, d->name)) { + char *sub_src_dir = strdup(src_file); + char *sub_dest_dir = strdup(dest_file); + if( (t = create_instance_mkdir_p(sub_dest_dir, NEWDIR_MODE)) ) + return(t); + if( (t = ds_copy_group_files_using_mode(sub_src_dir, sub_dest_dir, filter, use_mode)) ) + return t; + free(sub_src_dir); + free(sub_dest_dir); + } + else { + if( (t = create_instance_copy(src_file, dest_file, use_mode)) ) + return t; + } + } + } + } + PR_CloseDir(ds); + return(NULL); +} + +static char * +ds_copy_group_files(char *src_dir, char *dest_dir, char *filter) +{ + return ds_copy_group_files_using_mode(src_dir, dest_dir, filter, + NEWFILE_MODE); +} + +static char * +ds_copy_group_bins(char *src_dir, char *dest_dir, char *filter, + int use_mode) +{ + return ds_copy_group_files_using_mode(src_dir, dest_dir, filter, + NEWSCRIPT_MODE); +} + +/* this macro was copied from libldap/tmplout.c */ +#define HREF_CHAR_ACCEPTABLE( c ) (( c >= '-' && c <= '9' ) || \ + ( c >= '@' && c <= 'Z' ) || \ + ( c == '_' ) || \ + ( c >= 'a' && c <= 'z' )) + +/* this function is based on libldap/tmplout.c:strcat_escaped */ +void fputs_escaped(char *s, FILE *fp) +{ + char *hexdig = "0123456789ABCDEF"; + register unsigned char c; + for ( ; c = *(unsigned char*)s; ++s ) { + if ( HREF_CHAR_ACCEPTABLE( c )) { + putc( c, fp ); + } else { + fprintf( fp, "%%%c%c", hexdig[ (c >> 4) & 0x0F ], hexdig[ c & 0x0F ] ); + } + } +} + +/* ------------- Create config files for Directory Server -------------- */ + +char *ds_cre_subdirs(char *sroot, server_config_s *cf, char *cs_path, + struct passwd* pw) +{ + char subdir[PATH_SIZE], *t = NULL; + + /* create subdir <a_server>/db */ + sprintf(subdir, "%s%cdb", cs_path, FILE_PATHSEP); + if( (t = create_instance_mkdir_p(subdir, NEWDIR_MODE)) ) + return(t); + chownfile (pw, subdir); + + /* create subdir <a_server>/ldif */ + sprintf(subdir, "%s%cldif", cs_path, FILE_PATHSEP); + if( (t = create_instance_mkdir_p(subdir, NEWDIR_MODE)) ) + return(t); + chownfile (pw, subdir); + + /* create subdir <a_server>/dsml */ + sprintf(subdir, "%s%cdsml", cs_path, FILE_PATHSEP); + if( (t = create_instance_mkdir_p(subdir, NEWDIR_MODE)) ) + return(t); + chownfile (pw, subdir); + + /* create subdir <a_server>/bak */ + sprintf(subdir, "%s%cbak", cs_path, FILE_PATHSEP); + if( (t = create_instance_mkdir_p(subdir, NEWDIR_MODE)) ) + return(t); + chownfile (pw, subdir); + + /* Create slapd-nickname/confbak directory */ + sprintf(subdir, "%s%cconfbak", cs_path, FILE_PATHSEP); + if( (t=create_instance_mkdir_p(subdir, NEWDIR_MODE)) ) + return(t); + chownfile (pw, subdir); + + /* create subdir <server_root>/dsgw/context */ + sprintf(subdir, "%s%cclients", sroot, FILE_PATHSEP); + if (is_a_dir(subdir, "dsgw")) { /* only create dsgw stuff if we are installing it */ + sprintf(subdir, "%s%cclients%cdsgw%ccontext", sroot, FILE_PATHSEP,FILE_PATHSEP,FILE_PATHSEP); + if( (t = create_instance_mkdir_p(subdir, NEWDIR_MODE)) ) + return(t); + } + + /* create subdir <server_root>/bin/slapd/authck */ + sprintf(subdir, "%s%cbin%cslapd%cauthck", sroot, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP); + if( (t = create_instance_mkdir_p(subdir, NEWDIR_MODE)) ) + return(t); +#if defined( SOLARIS ) + /* + * Solaris 9+ specific installation + */ + if (iDSISolaris) + logUninstallInfo(sroot, PRODUCT_NAME, PRODUCT_NAME, subdir); +#endif /* SOLARIS */ + + return (t); +} + +#define CREATE_LDIF2DB() \ + gen_perl_script_auto(mysroot, mycs_path, "ldif2db.pl", cf) + +#define CREATE_DB2INDEX() \ + gen_perl_script_auto(mysroot, mycs_path, "db2index.pl", cf) + +#define CREATE_DB2LDIF() \ + gen_perl_script_auto(mysroot, mycs_path, "db2ldif.pl", cf) + +#define CREATE_DB2BAK() \ + gen_perl_script_auto(mysroot, mycs_path, "db2bak.pl", cf) + +#define CREATE_BAK2DB() \ + gen_perl_script_auto(mysroot, mycs_path, "bak2db.pl", cf) + +#define CREATE_VERIFYDB() \ + gen_perl_script_auto(mysroot, mycs_path, "verify-db.pl", cf) + +#define CREATE_REPL_MONITOR_CGI() \ + gen_perl_script_auto(mysroot, cgics_path, "repl-monitor-cgi.pl", cf) + +#define CREATE_ACCOUNT_INACT(_commandName) \ + gen_perl_script_auto(mysroot, cs_path, _commandName, cf) + +#define CREATE_DSML() \ + gen_perl_script_auto(mysroot, mycs_path, "dsml-activate.pl", cf) + +#define CREATE_MIGRATETO5() \ + gen_perl_script_auto_for_migration(mysroot, mycs_path, "migrateTo5", cf) + +#define CREATE_MIGRATE50TO51() \ + gen_perl_script_auto_for_migration(mysroot, mycs_path, "migrate50to51", cf) + +#define CREATE_MIGRATEINSTANCE5() \ + gen_perl_script_auto_for_migration(mysroot, mycs_path, "migrateInstance5", cf) + +#define CREATE_MIGRATE5TO6() \ + gen_perl_script_auto_for_migration(mysroot, mycs_path, "migrate5to6", cf) + +#define CREATE_MIGRATEINSTANCE6() \ + gen_perl_script_auto_for_migration(mysroot, mycs_path, "migrateInstance6", cf) + +#define CREATE_MIGRATETO6() \ + gen_perl_script_auto_for_migration(mysroot, mycs_path, "migrateTo6", cf) + +#define CREATE_MIGRATE5TO7() \ + gen_perl_script_auto_for_migration(mysroot, mycs_path, "migrate5to7", cf) + +#define CREATE_MIGRATE6TO7() \ + gen_perl_script_auto_for_migration(mysroot, mycs_path, "migrate6to7", cf) + +#define CREATE_MIGRATEINSTANCE7() \ + gen_perl_script_auto_for_migration(mysroot, mycs_path, "migrateInstance7", cf) + +#define CREATE_MIGRATETO7() \ + gen_perl_script_auto_for_migration(mysroot, mycs_path, "migrateTo7", cf) + +#define CREATE_NEWPWPOLICY() \ + gen_perl_script_auto(mysroot, mycs_path, "ns-newpwpolicy.pl", cf) + +#ifdef XP_UNIX +char *ds_gen_scripts(char *sroot, server_config_s *cf, char *cs_path) +{ + char *t = NULL; + char server[PATH_SIZE], admin[PATH_SIZE], tools[PATH_SIZE]; + char cgics_path[PATH_SIZE]; + char *cl_scripts[7] = {"dsstop", "dsstart", "dsrestart", "dsrestore", "dsbackup", "dsimport", "dsexport"}; + char *cl_javafiles[7] = {"DSStop", "DSStart", "DSRestart", "DSRestore", "DSBackup", "DSImport", "DSExport"}; + int cls = 0; /*Index into commandline script names and java names - RJP*/ + char *mysroot, *mycs_path; + +#if defined( SOLARIS ) + /* + * Solaris 9+ specific installation + */ + char fn[PATH_SIZE]; +#endif /* SOLARIS */ + + mysroot = sroot; + mycs_path = cs_path; + + sprintf(server, "%s/bin/"PRODUCT_NAME"/server", sroot); + sprintf(admin, "%s/bin/"PRODUCT_NAME"/admin/bin", sroot); + sprintf(tools, "%s/shared/bin", sroot); + sprintf(cgics_path, "%s%cbin%cadmin%cadmin%cbin", sroot, + FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP); + + t = gen_script(cs_path, "monitor", + "if [ \"x$1\" != \"x\" ];\nthen MDN=\"$1\";\nelse MDN=\"cn=monitor\";\n fi\n" + + "cd %s\nPATH=%s:$PATH;export PATH\n" + "ldapsearch -p %s -b \"$MDN\" -s base \"objectClass=*\"\n", + tools, tools, cf->servport); + if(t) return t; + + t = gen_script(cs_path, "saveconfig", + "cd %s\n" + "echo saving configuration ...\n" + "conf_ldif=%s/confbak/`date +%%Y_%%m_%%d_%%H%%M%%S`.ldif\n" + "./ns-slapd db2ldif -N -D %s " + "-s \"%s\" -a $conf_ldif -n NetscapeRoot 2>&1\n" + "if [ \"$?\" -ge 1 ] \nthen\n" + " echo Error occurred while saving configuration\n" + " exit 1\n" + "fi\n" + "exit 0\n", + server, cs_path, cs_path, cf->netscaperoot); + if(t) return t; + + t = gen_script(cs_path, "restoreconfig", + "cd %s\n" + "conf_ldif=`ls -1t %s/confbak/*.ldif | head -1`\n" + "if [ -z \"$conf_ldif\" ]\n" + "then\n" + " echo No configuration to restore in %s/confbak ; exit 1\n" + "fi\n" + "echo Restoring $conf_ldif\n" + "./ns-slapd ldif2db -D %s" + " -i $conf_ldif -n NetscapeRoot 2>&1\n" + "exit $?\n", + server, cs_path, cs_path, cs_path); + if(t) return t; + + t = gen_script(cs_path, "ldif2db", + "cd %s\n" + "if [ $# -lt 4 ]\nthen\n" + "\techo \"Usage: ldif2db -n backend_instance | {-s includesuffix}* [{-x excludesuffix}*]\"\n" + "\techo \" {-i ldiffile}* [-O]\"\n" + "\techo \"Note: either \\\"-n backend_instance\\\" or \\\"-s includesuffix\\\" and \\\"-i ldiffile\\\" are required.\"\n" + "\texit 1\n" + "fi\n\n" + "echo importing data ...\n" + "./ns-slapd ldif2db -D %s \"$@\" 2>&1\n" + "exit $?\n", + server, cs_path); + if(t) return t; + +#if defined(UPGRADEDB) + t = gen_script(cs_path, "upgradedb", + "cd %s\n" + "if [ \"$#\" -eq 1 ]\nthen\n" + "\tbak_dir=$1\nelse\n" + "\tbak_dir=%s/bak/upgradedb_`date +%%Y_%%m_%%d_%%H_%%M_%%S`\nfi\n\n" + "echo upgrade index files ...\n" + "./ns-slapd upgradedb -D %s -a $bak_dir\n", + server, cs_path, cs_path); + if(t) return t; +#endif + + /* new code for dsml import */ + t = gen_script(cs_path, "dsml2db", + "cd %s\n" + "if [ $# -lt 4 ]\nthen\n" + "\techo \"Usage: dsml2db -n backend_instance | {-s includesuffix}* [{-x excludesuffix}*]\"\n" + "\techo \" {-i dsmlfile}\"\n" + "\techo \"Note: either \\\"-n backend_instance\\\" or \\\"-s includesuffix\\\" and \\\"-i dsmlfile\\\" are required.\"\n" + "\texit 1\n" + "fi\n\n" + "set_dsml=0\n" + "dsml_file=\"mydummy\"\n" + "space=\" \"\n" + "i=0\n" + "for arg in \"$@\"\ndo\n" + "\tif [ \"$arg\" = '-i' ];\n\tthen\n" + "\t\tset_dsml=1\n" + "\telif [ $set_dsml -eq 1 ];\n\tthen\n" + "\t\tdsml_file=$arg\n" + "\t\tset_dsml=2\n" + "\telse\n" + "\t\teval a$i=\\\"$arg\\\"\n" + "\t\ti=`expr $i + 1`\n" + "\tfi\n" + "done\n" + "max=$i; i=0;\n" + "shift $#\n" + "while [ $i -lt $max ]; do\n" + "\teval arg=\\$a$i\n" + "\tset -- \"$@\" \"$arg\"\n" + "\ti=`expr $i + 1`\n" + "done\n" + "\tif [ $dsml_file = \"mydummy\" ]\n\tthen\n\t" + "echo \"Need a DSML file as input\"" + "\n\t\t exit 1" + "\n\tfi\n" + "\tif [ -f $dsml_file ] && [ -r $dsml_file ]\n\tthen\n" + "\t\t%s/bin/base/jre/bin/java -Dverify=true -classpath %s/java/jars/crimson.jar:%s/java/ldapjdk.jar:%s/java/jars/xmltools.jar com.netscape.xmltools.DSML2LDIF $dsml_file\n" + "\t\tif [ $? = 0 ]; then\n" + "\t\techo importing data ...\n" + "\t\t%s/bin/base/jre/bin/java -classpath %s/java/jars/crimson.jar:%s/java/ldapjdk.jar:%s/java/jars/xmltools.jar com.netscape.xmltools.DSML2LDIF $dsml_file | ./ns-slapd ldif2db -D %s \"$@\" -i -\n" + "\t\texit $?\n" + "\t\tfi\n" + "\telse\n" + "\t\techo \"File $dsml_file invalid. Absolute path is required.\"\n\t\texit 1\n" + "\tfi\n", + server,sroot,sroot,sroot,sroot,sroot,sroot,sroot,sroot,cs_path); + if(t) return t; + + t = gen_script(cs_path, "ldif2ldap", + "cd %s\n" + "./ldapmodify -a -p %s -D \"$1\" -w \"$2\" -f $3\n", + tools, cf->servport); + if(t) return t; + + t = CREATE_LDIF2DB(); + if(t) return t; + + t = CREATE_DB2INDEX(); + if(t) return t; +/* + t = CREATE_MIGRATETO5(); + if(t) return t; + + t = CREATE_MIGRATE50TO51(); + if(t) return t; + + t = CREATE_MIGRATEINSTANCE5(); + if(t) return t; + + t = CREATE_MIGRATE5TO6(); + if(t) return t; + + t = CREATE_MIGRATEINSTANCE6(); + if(t) return t; + + t = CREATE_MIGRATETO6(); + if(t) return t; +*/ + + t = CREATE_MIGRATE5TO7(); + if(t) return t; + + t = CREATE_MIGRATE6TO7(); + if(t) return t; + + t = CREATE_MIGRATEINSTANCE7(); + if(t) return t; + + t = CREATE_MIGRATETO7(); + if(t) return t; + + t = gen_script(cs_path, "getpwenc", + "cd %s\n" + "PATH=%s:$PATH;export PATH\n" + "if [ $# -lt 2 ]\n" + "then\n" + "\techo \"Usage: getpwenc scheme passwd\"\n" + "\texit 1\n" + "fi\n\n" + "pwdhash -D %s -H -s \"$@\"\n", + server, server, cs_path); + if(t) return t; + + t = gen_script(cs_path, "db2ldif", + "cd %s\n" + "if [ \"$#\" -lt 2 ];\nthen\n" + "\techo \"Usage: db2ldif {-n backend_instance}* | {-s includesuffix}*\"\n" + "\techo \" [{-x excludesuffix}*] [-a outputfile]\"\n" + "\techo \" [-N] [-r] [-C] [-u] [-U] [-m] [-M] [-1]\"\n" + "\techo \"Note: either \\\"-n backend_instance\\\" or \\\"-s includesuffix\\\" is required.\"\n" + "\texit 1\n" + "fi\n\n" + "set_ldif=0\n" + "ldif_file=\"mydummy\"\n" + "for arg in \"$@\"\ndo\n" + "\tif [ \"$arg\" = '-a' ];\n\tthen\n" + "\t\tset_ldif=1\n" + "\telif [ $set_ldif -eq 1 ];\n\tthen\n" + "\t\tldif_file=$arg\n" + "\t\tset_ldif=2\n" + "\tfi\n" + "done\n" + "if [ $ldif_file = \"mydummy\" ]\nthen\n" + "\tldif_file=%s/ldif/`date +%%Y_%%m_%%d_%%H%%M%%S`.ldif\nfi\n" + "if [ $set_ldif -eq 2 ]\nthen\n" + "./ns-slapd db2ldif -D %s \"$@\"\nelse\n" + "./ns-slapd db2ldif -D %s -a $ldif_file \"$@\"\nfi\n", + server, cs_path, cs_path, cs_path); + if(t) return t; + + /* new code for dsml export */ + t = gen_script(cs_path, "db2dsml", + "cd %s\n" + "if [ \"$#\" -lt 2 ];\nthen\n" + "\techo \"Usage: db2dsml {-n backend_instance} | {-s includesuffix}*\"\n" + "\techo \" [{-x excludesuffix}*] [-a outputfile]\"\n" + "\techo \" [-u]\"\n" + "\techo \"Note: either \\\"-n backend_instance\\\" or \\\"-s includesuffix\\\" is required.\"\n" + "\texit 1\n" + "fi\n\n" + "set_dsml=0\n" + "dsml_file=\"mydummy\"\n" + "arg_list=\"\"\n" + "space=\" \"\n" + "for arg in \"$@\"\ndo\n" + "\tif [ \"$arg\" = '-a' ];\n\tthen\n" + "\t\tset_dsml=1\n" + "\telif [ $set_dsml -eq 1 ];\n\tthen\n" + "\t\tdsml_file=$arg\n" + "\t\tset_dsml=2\n" + "\telse\n" + "\t\targ_list=$arg_list$space$arg\n" + "\tfi\n" + "done\n" + "if [ $dsml_file = \"mydummy\" ]\nthen\n" + "\tdsml_file=%s/dsml/`date +%%Y_%%m_%%d_%%H%%M%%S`.dsml\n" + "\techo dsmlfile: $dsml_file\n" + "fi\n" + "%s/bin/base/jre/bin/java -Dverify=true -classpath %s/java/ldapjdk.jar:%s/java/jars/xmltools.jar com.netscape.xmltools.LDIF2DSML -s -o $dsml_file \n" + "if [ $? = 0 ]; then\n" + "\t./ns-slapd db2ldif -D %s \"$@\" -a - | %s/bin/base/jre/bin/java -classpath %s/java/ldapjdk.jar:%s/java/jars/xmltools.jar com.netscape.xmltools.LDIF2DSML -s -o $dsml_file \n" + "fi\n", + server, cs_path, sroot, sroot, sroot, cs_path, sroot, sroot, sroot); + if(t) return t; + + t = CREATE_DB2LDIF(); + if(t) return t; + +#if defined(UPGRADEDB) + t = gen_script(cs_path, "db2index", + "cd %s\n" + "if [ $# -eq 0 ]\n" + "then\n" + "\tbak_dir=%s/bak/reindex_`date +%%Y_%%m_%%d_%%H_%%M_%%S`\n" + "\t./ns-slapd upgradedb -D %s -f -a \"$bak_dir\"\n" + "elif [ $# -lt 4 ]\n" + "then\n" + "\techo \"Usage: db2index [-n backend_instance | {-s includesuffix}* -t attribute[:indextypes[:matchingrules]] -T vlvattribute]\"\n" + "\texit 1\n" + "else\n" + "\t./ns-slapd db2index -D %s \"$@\"\n" + "fi\n\n", + server, cs_path, cs_path, cs_path); + if(t) return t; +#endif + + t = gen_script(cs_path, "vlvindex", + "cd %s\n" + "if [ $# -lt 4 ]\n" + "then\n" + "\techo \"Usage: vlvindex -n backend_instance | {-s includesuffix}* -T attribute\"\n" + "\techo Note: either \\\"-n backend_instance\\\" or \\\"-s includesuffix\\\" are required.\n" + "\texit 1\n" + "fi\n\n" + "./ns-slapd db2index -D %s \"$@\"\n", + server, cs_path); + if(t) return t; + + t = gen_script(cs_path, "db2bak", + "cd %s\n" + "if [ \"$#\" -eq 1 ]\nthen\n" + "\tbak_dir=$1\nelse\n" + "\tbak_dir=%s/bak/`date +%%Y_%%m_%%d_%%H_%%M_%%S`\nfi\n\n" + "./ns-slapd db2archive -D %s -a $bak_dir\n", + server, cs_path, cs_path); + if(t) return t; + + t = CREATE_DB2BAK(); + if(t) return t; + + t = gen_script(cs_path, "bak2db", + "if [ \"$#\" -ne 1 ]\nthen\n" + " echo \"Usage: bak2db archivedir\"\n" + " exit 1\nfi\n\n" + "if [ 1 = `expr $1 : \"\\/\"` ]\nthen\n" + " archivedir=$1\n" + "else\n" + " # relative\n" + " cwd=`pwd`\n" + " archivedir=`echo $cwd/$1`\nfi\n\n" + "cd %s\n" + "./ns-slapd archive2db -D %s -a $archivedir\n", + server, cs_path); + if(t) return t; + + t = CREATE_BAK2DB(); + if(t) return t; + + t = CREATE_VERIFYDB(); + if(t) return t; + + t = CREATE_REPL_MONITOR_CGI(); + if(t) return t; + + t = CREATE_ACCOUNT_INACT("ns-inactivate.pl"); + if(t) return t; + + t = CREATE_ACCOUNT_INACT("ns-activate.pl"); + if(t) return t; + + t = CREATE_ACCOUNT_INACT("ns-accountstatus.pl"); + if(t) return t; + + t = CREATE_DSML(); + if(t) return t; + + t = CREATE_NEWPWPOLICY(); + if(t) return t; + + t = gen_script(cs_path, "suffix2instance", + "cd %s\n" + "if [ $# -lt 2 ]\n" + "then\n" + "\techo Usage: suffix2instance {-s includesuffix}*\n" + "\texit 1\n" + "fi\n\n" + "./ns-slapd suffix2instance -D %s \"$@\" 2>&1\n", + server, cs_path); + if(t) return t; + + /*Generate the java commandline tools in bin/slapd/server*/ + for (cls = 0; cls < 7; cls++) { + t = gen_script(server, cl_scripts[cls], + "cd %s\n\n" + "lang=${LANG:=en}\n" + "while [ $# -ge 1 ]\n" + "do\n" + " if [ $1 = '-l' ]\n" + " then\n" + " shift\n" + " lang=$1\n" + " else\n" + " arg=\"$arg $1\"\n" + " fi\n" + " shift\n" + "done\n" + "./bin/base/jre/bin/jre -classpath ./bin/base/jre/lib:" + "./bin/base/jre/lib/rt.jar:./bin/base/jre/lib/i18n.jar:" + "./java/base.jar:./java/jars/ds40.jar:./java/jars/ds40_${lang}.jar:" + "./java/swingall.jar:./java/ssl.zip:" + "./java/ldapjdk.jar:./java/mcc40.jar:./java/mcc40_${lang}.jar:" + "./java/nmclf40.jar:./java/nmclf40_${lang}.jar" + " com.netscape.admin.dirserv.cmdln.%s $arg\n", + sroot, cl_javafiles[cls]); + if(t) return t; +#if defined( SOLARIS ) + /* + * Solaris 9+ specific installation + */ + if (iDSISolaris) + { + sprintf(fn, "%s/%s", server, cl_scripts[cls]); + logUninstallInfo(sroot, PRODUCT_NAME, PRODUCT_NAME, fn); + } +#endif /* SOLARIS */ + + } + + + + return (t); +} +#else +char *ds_gen_scripts(char *sroot, server_config_s *cf, char *cs_path) +{ + char *t = NULL; + char server[PATH_SIZE], admin[PATH_SIZE], tools[PATH_SIZE]; + char cgics_path[PATH_SIZE]; + char *cl_scripts[7] = {"dsstop.bat", "dsstart.bat", "dsrestart.bat", "dsrestore.bat", "dsbackup.bat", "dsimport.bat", "dsexport.bat"}; + char *cl_javafiles[7] = {"DSStop", "DSStart", "DSRestart", "DSRestore", "DSBackup", "DSImport", "DSExport"}; + int cls = 0; /*Index into commandline script names and java names - RJP*/ + char *mysroot, *mycs_path; + + { + char *p, *q; + int n; + + for (n = 0, p = sroot; p = strchr(p, '/'); n++, p++) ; + for (p = sroot; p = strchr(p, '\\'); n++, p++) ; + mysroot = (char *)malloc(strlen(sroot) + n + 1); + for (p = sroot, q = mysroot; *p; p++, q++) { + if ('/' == *p || '\\' == *p) { + *q++ = '\\'; + *q = '\\'; + } else + *q = *p; + } + *q = '\0'; + + for (n = 0, p = cs_path; p = strchr(p, '/'); n++, p++) ; + for (p = cs_path; p = strchr(p, '\\'); n++, p++) ; + mycs_path = (char *)malloc(strlen(cs_path) + n + 1); + for (p = cs_path, q = mycs_path; *p; p++, q++) { + if ('/' == *p || '\\' == *p) { + *q++ = '\\'; + *q = '\\'; + } else + *q = *p; + } + *q = '\0'; + } + + sprintf(server, "%s/bin/"PRODUCT_NAME"/server", sroot); + sprintf(admin, "%s/bin/"PRODUCT_NAME"/admin/bin", sroot); + sprintf(tools, "%s/shared/bin", sroot); + sprintf(cgics_path, "%s/bin/admin/admin/bin", sroot); + + ds_unixtodospath( cs_path ); + ds_unixtodospath( server ); + ds_unixtodospath( admin ); + ds_unixtodospath( sroot ); + ds_unixtodospath( tools ); + ds_unixtodospath( cgics_path ); + + t = gen_script(cs_path, "monitor.bat", + "@echo off\n" + "setlocal\n" + "set rc=0\n" + "if %%1.==. goto noparam\n" + "\"%s\\ldapsearch\" -p %s -b %%1 " + "-s base \"objectClass=*\"\n" + "set rc=%%errorlevel%%\n" + "goto proceed\n" + ":noparam\n" + "\"%s\\ldapsearch\" -p %s -b \"cn=monitor\" " + "-s base \"objectClass=*\"\n" + "set rc=%%errorlevel%%\n" + ":proceed\n" + "if defined MKSARGS exit %%rc%%\n" + "exit /b %%rc%%\n", + tools, cf->servport, tools, cf->servport); + if(t) return t; + + t = gen_script(cs_path, "saveconfig.bat", + "@echo off\n" + "setlocal\n" + "set rc=0\n" + "PATH=\"%s\";%%PATH%%\n" + "namegen\n" + "call bstart\n" + "set config_ldif=%s\\confbak\\%%DATESTR%%.ldif\n" + "call bend\n" + "del bend.bat\n" + "slapd db2ldif -s \"%s\" -a \"%%config_ldif%%\" -N" + " -D \"%s\" -n NetscapeRoot 2>&1\n" + "set rc=%%errorlevel%%\n" + "if %%rc%%==0 goto done\n" + "echo Error occurred while saving configuration\n" + ":done\n" + "if defined MKSARGS exit %%rc%%\n" + "exit /b %%rc%%\n", + server, cs_path, cf->netscaperoot, cs_path); + if(t) return t; + + t = gen_script(cs_path, "restoreconfig.bat", + "@echo off\n" + "setlocal\n" + "set rc=0\n" + "PATH=\"%s\";%%PATH%%\n" + "set latestscript=%s\\latest_config.bat\n" + "if EXIST \"%%latestscript%%\" del \"%%latestscript%%\"\n" + "latest_file \"%s\\confbak\\*.ldif\" \"%%latestscript%%\"\n" + "if not EXIST \"%%latestscript%%\" goto noconfig\n" + "call \"%%latestscript%%\"\n" + "del \"%%latestscript%%\"\n" + "slapd ldif2db -D \"%s\" -i \"%%LATEST_FILE%%\"" + " -n NetscapeRoot 2>&1\n" + "set rc=%%errorlevel%%\n" + "if %%rc%%==0 goto done\n" + "echo Error occurred while saving configuration\n" + "goto done\n" + ":noconfig\n" + "set rc=0\n" /* no error */ + "echo No configuration to restore in %s\\confbak\n" + ":done\n" + "if defined MKSARGS exit %%rc%%\n" + "exit /b %%rc%%\n", + server, cs_path, cs_path, cs_path, cs_path); + if(t) return t; + + t = gen_script(cs_path, "ldif2db.bat", + "@if not \"%%echo%%\" == \"on\" echo off\n" + "setlocal\n" + "set rc=0\n" + "PATH=\"%s\";%%PATH%%\n\n" + "set noconfig=0\n" + "if [%%2] == [] goto incorrect\n" + "if [%%3] == [] goto incorrect\n" + "if [%%4] == [] goto incorrect\n\n" + "set args=\n" + ":getargs\n" + "if [%%1] == [] goto import\n" + "set args=%%args%% %%1\n" + "shift\n" + "goto getargs\n\n" + ":incorrect\n" + ":usage\n" + "echo \"Usage: ldif2db -n backend_instance | {-s \"includesuffix\"}* " + "{-i ldif-file}* [-O] [{-x \"excludesuffix\"}*]\"\n" + "set rc=1\n" + "goto done\n\n" + ":import\n" + "echo importing data ...\n" + "slapd ldif2db -D \"%s\" %%args%% 2>&1\n\n" + "set rc=%%errorlevel%%\n" + ":done\n" + "if defined MKSARGS exit %%rc%%\n" + "exit /b %%rc%%\n", + server, cs_path); + if(t) return t; + + /* new code for dsml import */ + t = gen_script(cs_path, "dsml2db.bat", + "@if not \"%%echo%%\" == \"on\" echo off\n" + "setlocal\n" + "set rc=0\n" + "PATH=\"%s\";%%PATH%%\n\n" + "set noconfig=0\n" + "if [%%2] == [] goto incorrect\n" + "if [%%3] == [] goto incorrect\n" + "if [%%4] == [] goto incorrect\n\n" + "set args=\n" + "goto getargs\n" + ":setdsml\n" + "set dsmlfile=\n" + "set dsmlfile=%%2\n" + "shift\n" + "shift\n" + "goto getargs\n" + ":getargs\n" + "if [%%1] == [] goto import\n" + "if [%%1] == [-i] goto setdsml\n" + "set args=%%args%% %%1\n" + "shift\n" + "goto getargs\n\n" + ":incorrect\n" + ":usage\n" + "echo \"Usage: dsml2db -n backend_instance | {-s \"includesuffix\"}* " + "{-i dsml-file} [{-x \"excludesuffix\"}*]\"\n" + "set rc=1\n" + "goto done\n\n" + ":import\n" + "%s\\bin\\base\\jre\\bin\\java -Dverify=true -classpath \".;%s\\java\\ldapjdk.jar;%s\\java\\jars\\crimson.jar;%s\\java\\jars\\xmltools.jar\" com.netscape.xmltools.DSML2LDIF %%dsmlfile%%\n" + "set rc=%%errorlevel%%\n" + "if %%rc%%==0 goto realimport else goto done\n" + ":realimport\n" + "echo importing data ...\n" + "%s\\bin\\base\\jre\\bin\\java -classpath \".;%s\\java\\ldapjdk.jar;%s\\java\\jars\\crimson.jar;%s\\java\\jars\\xmltools.jar\" com.netscape.xmltools.DSML2LDIF %%dsmlfile%% | slapd ldif2db -D \"%s\" -i - %%args%% 2>&1\n\n" + "set rc=%%errorlevel%%\n" + ":done\n" + "if defined MKSARGS exit %%rc%%\n" + "exit /b %%rc%%\n", + server, sroot, sroot, sroot, sroot, sroot, sroot, sroot, sroot, cs_path); + if(t) return t; + + t = gen_script(cs_path, "ldif2ldap.bat", + "@echo off\n" + "\"%s\\ldapmodify\" -a -p %s -D %%1 -w %%2 -f %%3\n", + tools, cf->servport); + if(t) return t; + + t = CREATE_LDIF2DB(); + if(t) return t; + + t = CREATE_DB2INDEX(); + if(t) return t; + +/* + t = CREATE_MIGRATETO5(); + if(t) return t; + + t = CREATE_MIGRATE50TO51(); + if(t) return t; + + t = CREATE_MIGRATEINSTANCE5(); + if(t) return t; + + t = CREATE_MIGRATETO6(); + if(t) return t; + + t = CREATE_MIGRATE5TO6(); + if(t) return t; + + t = CREATE_MIGRATEINSTANCE6(); + if(t) return t; +*/ + t = CREATE_MIGRATE5TO7(); + if(t) return t; + + t = CREATE_MIGRATE6TO7(); + if(t) return t; + + t = CREATE_MIGRATEINSTANCE7(); + if(t) return t; + + t = CREATE_MIGRATETO7(); + if(t) return t; + + t = gen_script(cs_path, "getpwenc.bat", + "@echo off\n" + "\"%s\\pwdhash\" -D \"%s\" -H -s %%1 %%2\n", + server, cs_path); + if(t) return t; + + t = gen_script(cs_path, "db2ldif.bat", + "@if not \"%%echo%%\" == \"on\" echo off\n\n" + "setlocal\n" + "set rc=0\n" + "PATH=\"%s\";%%PATH%%\n\n" + "if [%%2] == [] goto err\n\n" + "set arg=\n" + "set ldif_file=\n\n" + ":again\n" + "if \"%%1\" == \"\" goto next\n" + "if \"%%1\" == \"-n\" goto doubletag\n" + "if \"%%1\" == \"-s\" goto doubletag\n" + "if \"%%1\" == \"-x\" goto doubletag\n" + "if \"%%1\" == \"-a\" goto setldif\n" + "if \"%%1\" == \"-N\" goto singletag\n" + "if \"%%1\" == \"-r\" goto singletag\n" + "if \"%%1\" == \"-C\" goto singletag\n" + "if \"%%1\" == \"-u\" goto singletag\n" + "if \"%%1\" == \"-m\" goto singletag\n" + "if \"%%1\" == \"-o\" goto singletag\n" + "if \"%%1\" == \"-U\" goto singletag\n" + "if \"%%1\" == \"-M\" goto singletag\n" + "if \"%%1\" == \"-E\" goto singletag\n" + "goto next\n\n" + ":doubletag\n" + "set arg=%%1 %%2 %%arg%%\n" + "shift\n" + "shift\n" + "goto again\n\n" + ":singletag\n" + "set arg=%%1 %%arg%%\n" + "shift\n" + "goto again\n\n" + ":setldif\n" + "set ldif_file=%%2\n" + "shift\n" + "shift\n" + "goto again\n\n" + ":next\n" + "if not \"%%ldif_file%%\" == \"\" goto givenldif\n\n" + "namegen\n" + "call bstart\n" + "set ldif_file=\"%s\\ldif\\%%DATESTR%%.ldif\"\n" + "call bend\n" + "del bend.bat\n\n" + ":givenldif\n" + "\"%s\\slapd\" db2ldif -D \"%s\" -a %%ldif_file%% %%arg%%\n" + "set rc=%%errorlevel%%\n" + "goto done\n\n" + ":err\n" + "echo \"Usage: db2ldif -n backend_instance | " + "{-s \"includesuffix\"}* [{-x \"excludesuffix\"}*] [-N] [-r] [-C] " + "[-u] [-U] [-m] [-M] [-1] [-a outputfile]\"\n\n" + "set rc=1\n" + ":done\n" + "if defined MKSARGS exit %%rc%%\n" + "exit /b %%rc%%\n", + server, cs_path, server, cs_path); + if(t) return t; + + t = CREATE_DB2LDIF(); + if(t) return t; + + /* new code for dsml export */ + t = gen_script(cs_path, "db2dsml.bat", + "@if not \"%%echo%%\" == \"on\" echo off\n\n" + "setlocal\n" + "set rc=0\n" + "PATH=\"%s\";%%PATH%%\n\n" + "if [%%2] == [] goto err\n\n" + "set arg=\n" + "set dsml_file=\n\n" + ":again\n" + "if \"%%1\" == \"\" goto next\n" + "if \"%%1\" == \"-n\" goto doubletag\n" + "if \"%%1\" == \"-s\" goto doubletag\n" + "if \"%%1\" == \"-x\" goto doubletag\n" + "if \"%%1\" == \"-a\" goto setdsml\n" + "if \"%%1\" == \"-N\" goto singletag\n" + "if \"%%1\" == \"-r\" goto singletag\n" + "if \"%%1\" == \"-C\" goto singletag\n" + "if \"%%1\" == \"-u\" goto singletag\n" + "if \"%%1\" == \"-m\" goto singletag\n" + "if \"%%1\" == \"-o\" goto singletag\n" + "if \"%%1\" == \"-U\" goto singletag\n" + "if \"%%1\" == \"-M\" goto singletag\n" + "goto next\n\n" + ":doubletag\n" + "set arg=%%1 %%2 %%arg%%\n" + "shift\n" + "shift\n" + "goto again\n\n" + ":singletag\n" + "set arg=%%1 %%arg%%\n" + "shift\n" + "goto again\n\n" + ":setdsml\n" + "set dsml_file=%%2\n" + "shift\n" + "shift\n" + "goto again\n\n" + ":next\n" + "if not \"%%dsml_file%%\" == \"\" goto givendsml\n\n" + "namegen\n" + "call bstart\n" + "set dsml_file=\"%s\\dsml\\%%DATESTR%%.dsml\"\n" + "echo dsmlfile: %%dsml_file%%\n" + "call bend\n" + "del bend.bat\n\n" + ":givendsml\n" + "%s\\bin\\base\\jre\\bin\\java -Dverify=true -classpath \".;%s\\java\\ldapjdk.jar;%s\\java\\jars\\xmltools.jar\" com.netscape.xmltools.LDIF2DSML -s -o %%dsml_file%%\n" + "set rc=%%errorlevel%%\n" + "if %%rc%%==0 goto realimport else goto done\n\n" + ":realimport\n" + "\"%s\\slapd\" db2ldif -D \"%s\" -a - -1 %%arg%% | %s\\bin\\base\\jre\\bin\\java -classpath \".;%s\\java\\ldapjdk.jar;%s\\java\\jars\\xmltools.jar\" com.netscape.xmltools.LDIF2DSML -s -o %%dsml_file%%\n" + "set rc=%%errorlevel%%\n" + "goto done\n\n" + ":err\n" + "echo \"Usage: db2dsml -n backend_instance | " + "{-s \"includesuffix\"}* [{-x \"excludesuffix\"}*]" + "[-u] [-a outputfile]\"\n\n" + "set rc=1\n" + ":done\n" + "if defined MKSARGS exit %%rc%%\n" + "exit /b %%rc%%\n", + server, cs_path, sroot, sroot, sroot, server, cs_path, sroot, sroot, sroot); + if(t) return t; + + t = gen_script(cs_path, "db2bak.bat", + "@echo off\n" + "setlocal\n" + "set rc=0\n" + "PATH=\"%s\";%%PATH%%\n" + "if %%1.==. goto nobak\n" + "set bakdir=%%1\n" + "goto backup\n" + ":nobak\n" + "namegen\n" + "call bstart\n" + "set bakdir=\"%s\\bak\\%%DATESTR%%\"\n" + "call bend\n" + "del bend.bat\n" + ":backup\n" + "\"%s\\slapd\" db2archive -D \"%s\" -a %%bakdir%% " + "%%2 %%3 %%4 %%5 %%6 %%7 %%8\n" + "set rc=%%errorlevel%%\n" + ":done\n" + "if defined MKSARGS exit %%rc%%\n" + "exit /b %%rc%%\n", + server, cs_path, server, cs_path); + if(t) return t; + + t = CREATE_DB2BAK(); + if(t) return t; + +#if defined(UPGRADEDB) + t = gen_script(cs_path, "db2index.bat", + "@echo off\n" + "setlocal\n" + "set rc=0\n" + "PATH=\"%s\";%%PATH%%\n" + "if %%1.==. goto indexall\n\n" + "if %%2.==. goto err\n" + "if %%3.==. goto err\n\n" + "set bakdir=%%1\n" + "goto backup\n\n" + ":indexall\n" + "namegen\n" + "call bstart\n" + "set bakdir=\"%s\\bak\\%%DATESTR%%\"\n" + "call bend\n" + "del bend.bat\n" + "\"%s\\slapd\" upgradedb -D \"%s\" -f -a %%bakdir%%\n" + "set rc=%%errorlevel%%\n" + "goto done\n\n" + ":backup\n" + "\"%s\\slapd\" db2index -D \"%s\" " + "%%1 %%2 %%3 %%4 %%5 %%6 %%7 %%8\n" + "set rc=%%errorlevel%%\n" + "goto done\n\n" + ":err\n" + "echo \"Usage: db2index [-n backend_instance | {-s instancesuffix}* -t attribute[:indextypes[:matchingrules]] -T vlvattribute]\"\n\n" + "set rc=1\n" + ":done\n" + "if defined MKSARGS exit %%rc%%\n" + "exit /b %%rc%%\n", + server, cs_path, server, cs_path, server, cs_path); + if(t) return t; +#endif + + t = gen_script(cs_path, "vlvindex.bat", + "@echo off\n" + "setlocal\n" + "set rc=0\n" + "if [%%2] == [] goto usage\n" + "if [%%3] == [] goto usage\n" + "if [%%4] == [] goto usage\n\n" + "\"%s\\slapd\" db2index -D \"%s\" \"%%@\"\n" + "set rc=%%errorlevel%%\n" + "goto done\n\n" + ":usage\n" + "echo \"Usage: vlvindex -n backend_instance | {-s includesuffix}* {-T attribute}\"\n\n" + "set rc=1\n" + ":done\n" + "if defined MKSARGS exit %%rc%%\n" + "exit /b %%rc%%\n", + server, cs_path); + if(t) return t; + + t = gen_script(cs_path, "bak2db.bat", + "@echo off\n" + "setlocal\n\n" + "set rc=0\n" + "if [%%1] == [] goto usage\n\n" + "\"%s\\slapd\" archive2db -D \"%s\" -a %%1\n" + "set rc=%%errorlevel%%\n" + "goto done\n\n" + ":usage\n" + "echo \"Usage: bak2db -a archivedir\"\n\n" + "set rc=1\n" + ":done\n" + "if defined MKSARGS exit %%rc%%\n" + "exit /b %%rc%%\n", + server, cs_path); + if(t) return t; + +#if defined(UPGRADEDB) + t = gen_script(cs_path, "upgradedb.bat", + "@echo off\n" + "setlocal\n" + "set rc=0\n" + "PATH=\"%s\";%%PATH%%\n" + "if %%1.==. goto nobak\n" + "set bakdir=%%1\n" + "goto backup\n" + ":nobak\n" + "namegen\n" + "call bstart\n" + "set bakdir=\"%s\\bak\\upgradedb_%%DATESTR%%\"\n" + "call bend\n" + "del bend.bat\n" + ":backup\n" + "\"%s\\slapd\" upgradedb -D \"%s\" -a %%bakdir%% " + "%%2 %%3 %%4 %%5 %%6 %%7 %%8\n" + "set rc=%%errorlevel%%\n" + ":done\n" + "if defined MKSARGS exit %%rc%%\n" + "exit /b %%rc%%\n", + server, cs_path, server, cs_path); + if(t) return t; +#endif + + t = CREATE_BAK2DB(); + if(t) return t; + + t = CREATE_VERIFYDB(); + if(t) return t; + + t = CREATE_REPL_MONITOR_CGI(); + if(t) return t; + + t = gen_script(cs_path, "suffix2instance.bat", + "@if not \"%%echo%%\" == \"on\" echo off\n\n" + "setlocal\n" + "set rc=0\n" + "PATH=\"%s\";%%PATH%%\n\n" + "if [%%2] == [] goto err\n\n" + "set arg=\n\n" + ":again\n" + "if \"%%1\" == \"\" goto next\n" + "if \"%%1\" == \"-s\" goto doubletag\n" + "shift\n" + "goto again\n\n" + ":doubletag\n" + "set arg=%%1 %%2 %%arg%%\n" + "shift\n" + "shift\n" + "goto again\n\n" + ":next\n" + "\"%s\\slapd\" suffix2instance -D \"%s\" %%arg%%\n" + "set rc=%%errorlevel%%\n" + "goto done\n\n" + ":err\n" + "echo Usage: suffix2instance {-s \"suffix\"}*\n\n" + "set rc=1\n" + ":done\n" + "if defined MKSARGS exit %%rc%%\n" + "exit /b %%rc%%\n", + server, server, cs_path); + if(t) return t; + + t = CREATE_ACCOUNT_INACT("ns-inactivate.pl"); + if(t) return t; + + t = CREATE_ACCOUNT_INACT("ns-activate.pl"); + if(t) return t; + + t = CREATE_ACCOUNT_INACT("ns-accountstatus.pl"); + if(t) return t; + + t = CREATE_DSML(); + if(t) return t; + + t = gen_script(cs_path, "dsml-activate.bat", + "@echo off\n" + "setlocal\n" + "PATH=%s\\bin\\slapd\\admin\\bin;%%PATH%%\n" + "perl \"%s\\dsml-activate.pl\" %%*\n" + "set rc=%%errorlevel%%\n" + "if defined MKSARGS exit %%rc%%\n" + "exit /b %%rc%%\n", + sroot, cs_path); + if(t) return t; + + + + t = CREATE_NEWPWPOLICY(); + if(t) return t; + + t = gen_script(cs_path, "ns-newpwpolicy.cmd", + "@echo off\n" + "setlocal\n" + "PATH=%s\\bin\\slapd\\admin\\bin;%%PATH%%\n" + "perl \"%s\\ns-newpwpolicy.pl\" %%*\n" + "set rc=%%errorlevel%%\n" + "if defined MKSARGS exit %%rc%%\n" + "exit /b %%rc%%\n", + sroot, cs_path); + if(t) return t; + + free(mysroot); + free(mycs_path); + + /*Generate the java commandline tools in bin/slapd/server*/ + for (cls = 0; cls < 7; cls++) { + t = gen_script(server, cl_scripts[cls], + "@echo off\npushd \"%s\"\n\n" + "setlocal\n" + "set LANG=en\n" + "set arg=\n" + "set rc=0\n" + ":getarg\n" + "if %%1.==. goto start\n" + "if %%1==-l goto getlang\n" + "set arg=%%arg%% %%1\n" + "shift\n" + "goto getarg\n" + ":getlang\n" + "shift\n" + "set LANG=%%1\n" + "shift\n" + "goto getarg\n" + ":start\n" + ".\\bin\\base\\jre\\bin\\jre -classpath " + ".;.\\java;.\\bin\\base\\jre\\lib;" + ".\\bin\\base\\jre\\lib\\rt.jar;.\\bin\\base\\jre\\lib\\i18n.jar;" + ".\\java\\base.jar;.\\java\\jars\\ds40.jar;.\\java\\jars\\ds40_%%LANG%%.jar;" + ".\\java\\swingall.jar;.\\java\\ssl.zip;" + ".\\java\\ldapjdk.jar;.\\java\\mcc40.jar;.\\java\\mcc40_%%LANG%%.jar;" + ".\\java\\nmclf40.jar;.\\java\\nmclf40_%%LANG%%.jar " + "com.netscape.admin.dirserv.cmdln.%s %%arg%%\n" + "set rc=%%errorlevel%%\n" + "popd\n" + "if defined MKSARGS exit %%rc%%\n" + "exit /b %%rc%%\n", + sroot, cl_javafiles[cls]); + if(t) return t; + } + + + + return (t); +} +#endif + + +void +suffix_gen_conf(FILE* f, char * suffix, char *be_name) +{ + int l; + char* belowdn; + + fprintf(f, "dn: cn=%s,cn=ldbm database,cn=plugins,cn=config\n", be_name); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "objectclass: nsBackendInstance\n"); + fprintf(f, "nsslapd-cachesize: -1\n"); + fprintf(f, "nsslapd-cachememsize: 10485760\n"); + fprintf(f, "nsslapd-suffix: %s\n", suffix); + fprintf(f, "cn: %s\n", be_name); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=monitor,cn=%s,cn=ldbm database,cn=plugins,cn=config\n", be_name); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: monitor\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=\"%s\",cn=mapping tree,cn=config\n", suffix); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "objectclass: nsMappingTree\n"); + fprintf(f, "cn: \"%s\"\n", suffix); + fprintf(f, "nsslapd-state: backend\n"); + fprintf(f, "nsslapd-backend: %s\n", be_name); + fprintf(f, "\n"); + + /* Parent entry for attribute encryption config entries */ + + fprintf(f, "dn: cn=encrypted attributes,cn=%s,cn=ldbm database,cn=plugins,cn=config\n", be_name); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: encrypted attributes\n"); + fprintf(f, "\n"); + + /* Parent entry for attribute encryption keys */ + + fprintf(f, "dn: cn=encrypted attribute keys,cn=%s,cn=ldbm database,cn=plugins,cn=config\n", be_name); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: encrypted attributes keys\n"); + fprintf(f, "\n"); + + /* Indexes for the ldbm instance */ + + fprintf(f, "dn: cn=index,cn=%s,cn=ldbm database,cn=plugins,cn=config\n", be_name); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: index\n"); + fprintf(f, "\n"); + + l = strlen("cn=index,cn=") + strlen(be_name) + strlen(",cn=ldbm database,cn=plugins,cn=config"); + belowdn = (char *)malloc(l + 1); + sprintf(belowdn, "cn=index,cn=%s,cn=ldbm database,cn=plugins,cn=config", be_name); + ds_gen_index(f, belowdn); + + /* done with ldbm entries */ +} + +#define MKSYNTAX(_name,_fn) do { \ + fprintf(f, "dn: cn=%s,cn=plugins,cn=config\n", (_name)); \ + fprintf(f, "objectclass: top\n"); \ + fprintf(f, "objectclass: nsSlapdPlugin\n"); \ + fprintf(f, "objectclass: extensibleObject\n"); \ + fprintf(f, "cn: %s\n",(_name)); \ + fprintf(f, "nsslapd-pluginpath: %s/lib/syntax-plugin%s\n", sroot, shared_lib); \ + fprintf(f, "nsslapd-plugininitfunc: %s\n", (_fn)); \ + fprintf(f, "nsslapd-plugintype: syntax\n"); \ + fprintf(f, "nsslapd-pluginenabled: on\n"); \ + fprintf(f, "\n"); \ + } while (0) + +char *ds_gen_confs(char *sroot, server_config_s *cf, + char *cs_path) +{ + char *pServerName = NULL; + char *schemaFile = NULL; + char* t = NULL; + char src[PATH_SIZE], dest[PATH_SIZE]; + char fn[PATH_SIZE], line[1024]; + FILE *f = 0, *f2 = 0, *srcf = 0; + int rootdse = 0; + char *shared_lib; + + sprintf(fn, "%s%cconfig%cdse.ldif", cs_path, FILE_PATHSEP, FILE_PATHSEP); + if(!(f = fopen(fn, "w"))) + return make_error("Can't write to %s (%s)", fn, ds_system_errmsg()); + +#if defined( XP_WIN32 ) + shared_lib = ".dll"; +#else +#ifdef HPUX + shared_lib = ".sl"; +#else +#ifdef AIX +#if OSVERSION >= 4200 + shared_lib = ".so"; +#else + shared_lib = "_shr.a"; +#endif +#else + shared_lib = ".so"; +#endif +#endif +#endif + + fprintf(f, "dn: cn=config\n"); + fprintf(f, "cn: config\n"); + fprintf(f, "objectclass:top\n"); + fprintf(f, "objectclass:extensibleObject\n"); + fprintf(f, "objectclass:nsslapdConfig\n"); + fprintf(f, "nsslapd-accesslog-logging-enabled: on\n"); + fprintf(f, "nsslapd-accesslog-maxlogsperdir: 10\n"); + fprintf(f, "nsslapd-accesslog-mode: 600\n"); + fprintf(f, "nsslapd-accesslog-maxlogsize: 100\n"); + fprintf(f, "nsslapd-accesslog-logrotationtime: 1\n"); + fprintf(f, "nsslapd-accesslog-logrotationtimeunit: day\n"); + fprintf(f, "nsslapd-accesslog-logrotationsync-enabled: off\n"); + fprintf(f, "nsslapd-accesslog-logrotationsynchour: 0\n"); + fprintf(f, "nsslapd-accesslog-logrotationsyncmin: 0\n"); + fprintf(f, "nsslapd-accesslog: %s/logs/access\n", cs_path); + fprintf(f, "nsslapd-enquote-sup-oc: off\n"); + fprintf(f, "nsslapd-localhost: %s\n", cf->servname); + fprintf(f, "nsslapd-schemacheck: %s\n", + (cf->disable_schema_checking && !strcmp(cf->disable_schema_checking, "1")) ? "off" : "on"); + fprintf(f, "nsslapd-rewrite-rfc1274: off\n"); + fprintf(f, "nsslapd-return-exact-case: on\n"); + fprintf(f, "nsslapd-ssl-check-hostname: on\n"); + fprintf(f, "nsslapd-port: %s\n", cf->servport); +#if !defined( XP_WIN32 ) + if (cf->servuser && *(cf->servuser)) { + fprintf(f, "nsslapd-localuser: %s\n", cf->servuser); + } +#endif + fprintf(f, "nsslapd-errorlog-logging-enabled: on\n"); + fprintf(f, "nsslapd-errorlog-mode: 600\n"); + fprintf(f, "nsslapd-errorlog-maxlogsperdir: 2\n"); + fprintf(f, "nsslapd-errorlog-maxlogsize: 100\n"); + fprintf(f, "nsslapd-errorlog-logrotationtime: 1\n"); + fprintf(f, "nsslapd-errorlog-logrotationtimeunit: week\n"); + fprintf(f, "nsslapd-errorlog-logrotationsync-enabled: off\n"); + fprintf(f, "nsslapd-errorlog-logrotationsynchour: 0\n"); + fprintf(f, "nsslapd-errorlog-logrotationsyncmin: 0\n"); + fprintf(f, "nsslapd-errorlog: %s/logs/errors\n", cs_path); + if (cf->loglevel) + fprintf(f, "nsslapd-errorlog-level: %s\n", cf->loglevel); + fprintf(f, "nsslapd-auditlog: %s/logs/audit\n", cs_path); + fprintf(f, "nsslapd-auditlog-mode: 600\n"); + fprintf(f, "nsslapd-auditlog-maxlogsize: 100\n"); + fprintf(f, "nsslapd-auditlog-logrotationtime: 1\n"); + fprintf(f, "nsslapd-auditlog-logrotationtimeunit: day\n"); + fprintf(f, "nsslapd-rootdn: %s\n", cf->rootdn); +#if !defined(_WIN32) && !defined(AIX) + { + unsigned int maxdescriptors = FD_SETSIZE; + struct rlimit rl; + if (getrlimit(RLIMIT_NOFILE, &rl) == 0) + maxdescriptors = (unsigned int)rl.rlim_max; + fprintf(f, "nsslapd-maxdescriptors: %d\n", maxdescriptors); + } +#endif + fprintf(f, "nsslapd-max-filter-nest-level: 40\n" ); + fprintf(f, "nsslapd-rootpw: %s\n", cf->roothashedpw); + if (getenv("DEBUG_SINGLE_THREADED")) + fprintf(f, "nsslapd-threadnumber: 1\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=plugins, cn=config\nobjectclass: top\nobjectclass: nsContainer\ncn: plugins\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=Password Storage Schemes,cn=plugins, cn=config\n"); + fprintf(f, "objectclass: top\nobjectclass: nsContainer\ncn: Password Storage Schemes\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=SSHA,cn=Password Storage Schemes,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "cn: SSHA\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/pwdstorage-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: ssha_pwd_storage_scheme_init\n"); + fprintf(f, "nsslapd-plugintype: pwdstoragescheme\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=SHA,cn=Password Storage Schemes,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "cn: SHA\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/pwdstorage-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: sha_pwd_storage_scheme_init\n"); + fprintf(f, "nsslapd-plugintype: pwdstoragescheme\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=CRYPT,cn=Password Storage Schemes,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "cn: CRYPT\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/pwdstorage-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: crypt_pwd_storage_scheme_init\n"); + fprintf(f, "nsslapd-plugintype: pwdstoragescheme\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=CLEAR,cn=Password Storage Schemes,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "cn: CLEAR\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/pwdstorage-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: clear_pwd_storage_scheme_init\n"); + fprintf(f, "nsslapd-plugintype: pwdstoragescheme\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=NS-MTA-MD5,cn=Password Storage Schemes,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "cn: NS-MTA-MD5\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/pwdstorage-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: ns_mta_md5_pwd_storage_scheme_init\n"); + fprintf(f, "nsslapd-plugintype: pwdstoragescheme\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=DES,cn=Password Storage Schemes,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: DES\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/des-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: des_init\n"); + fprintf(f, "nsslapd-plugintype: reverpwdstoragescheme\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "nsslapd-pluginarg0: nsmultiplexorcredentials\n"); + fprintf(f, "nsslapd-pluginarg1: nsds5ReplicaCredentials\n"); + fprintf(f, "nsslapd-pluginid: des-storage-scheme\n"); + fprintf(f, "\n"); + + MKSYNTAX("Case Ignore String Syntax","cis_init"); + MKSYNTAX("Case Exact String Syntax","ces_init"); + MKSYNTAX("Space Insensitive String Syntax","sicis_init"); + MKSYNTAX("Binary Syntax","bin_init"); + MKSYNTAX("Octet String Syntax","octetstring_init"); + MKSYNTAX("Boolean Syntax","boolean_init"); + MKSYNTAX("Generalized Time Syntax","time_init"); + MKSYNTAX("Telephone Syntax","tel_init"); + MKSYNTAX("Integer Syntax","int_init"); + MKSYNTAX("Distinguished Name Syntax","dn_init"); + MKSYNTAX("OID Syntax","oid_init"); + MKSYNTAX("URI Syntax","uri_init"); + MKSYNTAX("JPEG Syntax","jpeg_init"); + MKSYNTAX("Country String Syntax","country_init"); + MKSYNTAX("Postal Address Syntax","postal_init"); + + fprintf(f, "dn: cn=State Change Plugin,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: State Change Plugin\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/statechange-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: statechange_init\n"); + fprintf(f, "nsslapd-plugintype: postoperation\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=Roles Plugin,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: Roles Plugin\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/roles-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: roles_init\n"); + fprintf(f, "nsslapd-plugintype: postoperation\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "nsslapd-plugin-depends-on-type: database\n"); + fprintf(f, "nsslapd-plugin-depends-on-named: State Change Plugin\n"); + fprintf(f, "nsslapd-plugin-depends-on-named: Views\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=ACL Plugin,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: ACL Plugin\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/acl-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: acl_init\n"); + fprintf(f, "nsslapd-plugintype: accesscontrol\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "nsslapd-plugin-depends-on-type: database\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=ACL preoperation,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: ACL preoperation\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/acl-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: acl_preopInit\n"); + fprintf(f, "nsslapd-plugintype: preoperation\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "nsslapd-plugin-depends-on-type: database\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=Legacy Replication Plugin,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: Legacy Replication Plugin\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/replication-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: replication_legacy_plugin_init\n"); + fprintf(f, "nsslapd-plugintype: object\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "nsslapd-plugin-depends-on-type: database\n"); + fprintf(f, "nsslapd-plugin-depends-on-named: Multimaster Replication Plugin\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=Multimaster Replication Plugin,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: Multimaster Replication Plugin\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/replication-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: replication_multimaster_plugin_init\n"); + fprintf(f, "nsslapd-plugintype: object\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "nsslapd-plugin-depends-on-named: ldbm database\n"); + fprintf(f, "nsslapd-plugin-depends-on-named: DES\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=Retro Changelog Plugin,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: Retro Changelog Plugin\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/retrocl-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: retrocl_plugin_init\n"); + fprintf(f, "nsslapd-plugintype: object\n"); + fprintf(f, "nsslapd-pluginenabled: off\n"); + fprintf(f, "nsslapd-plugin-depends-on-type: database\n"); + fprintf(f, "\n"); + + + /* cos needs to be placed before other same type'ed plugins (postoperation) */ + fprintf(f, "dn: cn=Class of Service,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: Class of Service\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/cos-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: cos_init\n"); + fprintf(f, "nsslapd-plugintype: postoperation\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "nsslapd-plugin-depends-on-type: database\n"); + fprintf(f, "nsslapd-plugin-depends-on-named: State Change Plugin\n"); + fprintf(f, "nsslapd-plugin-depends-on-named: Views\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=Views,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: Views\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/views-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: views_init\n"); + fprintf(f, "nsslapd-plugintype: object\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "nsslapd-plugin-depends-on-type: database\n"); + fprintf(f, "nsslapd-plugin-depends-on-named: State Change Plugin\n"); + fprintf(f, "\n"); + + /* + * LP: Turn referential integrity plugin OFF by default + * defect 518862 + */ + fprintf(f, "dn: cn=referential integrity postoperation,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: referential integrity postoperation\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/referint-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: referint_postop_init\n"); + fprintf(f, "nsslapd-plugintype: postoperation\n"); + fprintf(f, "nsslapd-pluginenabled: off\n"); + fprintf(f, "nsslapd-pluginArg0: %d\n", REFERINT_DELAY); + fprintf(f, "nsslapd-pluginArg1: %s/logs/referint\n", cs_path); + fprintf(f, "nsslapd-pluginArg2: %d\n", REFERINT_LOG_CHANGES); + fprintf(f, "nsslapd-pluginArg3: member\n"); + fprintf(f, "nsslapd-pluginArg4: uniquemember\n"); + fprintf(f, "nsslapd-pluginArg5: owner\n"); + fprintf(f, "nsslapd-pluginArg6: seeAlso\n"); + fprintf(f, "nsslapd-plugin-depends-on-type: database\n"); + fprintf(f, "\n"); +/* + NT synch is dead as of 5.0 + + fprintf(f, "dn: cn=ntSynchService preoperation,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: ntSynchService preoperation\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/ntsynch-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: libntsynch_plugin_preop_init\n"); + fprintf(f, "nsslapd-plugintype: preoperation\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=ntSynchService postoperation,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: ntSynchService postoperation\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/ntsynch-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: libntsynch_plugin_postop_init\n"); + fprintf(f, "nsslapd-plugintype: postoperation\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "\n"); +*/ + if (!cf->use_existing_user_ds) { + t = cf->suffix; + } else { + t = cf->netscaperoot; + } + + /* + * LP: Turn attribute uniqueness plugin OFF by default + * defect 518862 + */ + fprintf(f, "dn: cn=attribute uniqueness,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: attribute uniqueness\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/attr-unique-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: NSUniqueAttr_Init\n"); + fprintf(f, "nsslapd-plugintype: preoperation\n"); + fprintf(f, "nsslapd-pluginenabled: off\n"); + fprintf(f, "nsslapd-pluginarg0: uid\n"); + fprintf(f, "nsslapd-pluginarg1: %s\n", t); + fprintf(f, "nsslapd-plugin-depends-on-type: database\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=7-bit check,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: 7-bit check\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/attr-unique-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: NS7bitAttr_Init\n"); + fprintf(f, "nsslapd-plugintype: preoperation\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "nsslapd-pluginarg0: uid\n"); + fprintf(f, "nsslapd-pluginarg1: mail\n"); + fprintf(f, "nsslapd-pluginarg2: userpassword\n"); + fprintf(f, "nsslapd-pluginarg3: ,\n"); + fprintf(f, "nsslapd-pluginarg4: %s\n", t); + fprintf(f, "nsslapd-plugin-depends-on-type: database\n"); + fprintf(f, "\n"); + + t = 0; + + fprintf(f, "dn: cn=Internationalization Plugin,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: Internationalization Plugin\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/liblcoll%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: orderingRule_init\n"); + fprintf(f, "nsslapd-plugintype: matchingRule\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "nsslapd-pluginarg0: %s/config/slapd-collations.conf\n", cs_path); + fprintf(f, "\n"); + + /* The HTTP client plugin */ + fprintf(f, "dn: cn=HTTP Client,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: HTTP Client\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/http-client-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: http_client_init\n"); + fprintf(f, "nsslapd-plugintype: preoperation\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "nsslapd-plugin-depends-on-type: database\n"); + fprintf(f, "\n"); + + /* The IM presence plugin root */ + fprintf(f, "dn: cn=Presence,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: Presence\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/presence-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: presence_init\n"); + fprintf(f, "nsslapd-plugintype: preoperation\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "nsslapd-plugin-depends-on-type: database\n"); + fprintf(f, "nsslapd-plugin-depends-on-named: HTTP Client\n"); + fprintf(f, "\n"); + + /* The AIM presence plugin */ + fprintf(f, "dn: cn=AIM Presence,cn=Presence,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: AIM Presence\n"); + fprintf(f, "nsim-id: nsAIMid\n"); + fprintf(f, "nsim-urltext: http://big.oscar.aol.com/$nsaimid?on_url=http://online&off_url=http://offline\n"); + fprintf(f, "nsim-urlgraphic: http://big.oscar.aol.com/$nsaimid?on_url=http://online&off_url=http://offline\n"); + fprintf(f, "nsim-onvaluemaptext: http://online\n"); + fprintf(f, "nsim-offvaluemaptext: http://offline\n"); + fprintf(f, "nsim-urltextreturntype: TEXT\n"); + fprintf(f, "nsim-urlgraphicreturntype: TEXT\n"); + fprintf(f, "nsim-requestmethod: REDIRECT\n"); + fprintf(f, "nsim-statustext: nsAIMStatusText\n"); + fprintf(f, "nsim-statusgraphic: nsAIMStatusGraphic\n"); + fprintf(f, "\n"); + + /* The ICQ presence plugin */ + fprintf(f, "dn: cn=ICQ Presence,cn=Presence,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: ICQ Presence\n"); + fprintf(f, "nsim-id: nsICQid\n"); + fprintf(f, "nsim-urltext: http://online.mirabilis.com/scripts/online.dll?icq=$nsicqid&img=5\n"); + fprintf(f, "nsim-urlgraphic: http://online.mirabilis.com/scripts/online.dll?icq=$nsicqid&img=5\n"); + fprintf(f, "nsim-onvaluemaptext: /lib/image/0,,4367,00.gif\n"); + fprintf(f, "nsim-offvaluemaptext: /lib/image/0,,4349,00.gif\n"); + fprintf(f, "nsim-urltextreturntype: TEXT\n"); + fprintf(f, "nsim-urlgraphicreturntype: TEXT\n"); + fprintf(f, "nsim-requestmethod: REDIRECT\n"); + fprintf(f, "nsim-statustext: nsICQStatusText\n"); + fprintf(f, "nsim-statusgraphic: nsICQStatusGraphic\n"); + fprintf(f, "\n"); + + /* The Yahoo presence plugin */ + fprintf(f, "dn: cn=Yahoo Presence,cn=Presence,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: Yahoo Presence\n"); + fprintf(f, "nsim-id: nsYIMid\n"); + fprintf(f, "nsim-urltext: http://opi.yahoo.com/online?u=$nsyimid&m=t\n"); + fprintf(f, "nsim-urlgraphic: http://opi.yahoo.com/online?u=$nsyimid&m=g&t=0\n"); + fprintf(f, "nsim-onvaluemaptext: $nsyimid is ONLINE\n"); + fprintf(f, "nsim-offvaluemaptext: $nsyimid is NOT ONLINE\n"); + fprintf(f, "nsim-urltextreturntype: TEXT\n"); + fprintf(f, "nsim-urlgraphicreturntype: BINARY\n"); + fprintf(f, "nsim-requestmethod: GET\n"); + fprintf(f, "nsim-statustext: nsYIMStatusText\n"); + fprintf(f, "nsim-statusgraphic: nsYIMStatusGraphic\n"); + fprintf(f, "\n"); + + /* enable pass thru authentication */ + if (cf->use_existing_config_ds || cf->use_existing_user_ds) + { + LDAPURLDesc *desc = 0; + char *url = cf->use_existing_config_ds ? cf->config_ldap_url : + cf->user_ldap_url; + if (url && !ldap_url_parse(url, &desc) && desc) + { + char *suffix = desc->lud_dn; + char *service = !strncmp(url, "ldaps:", strlen("ldaps:")) ? + "ldaps" : "ldap"; + if (cf->use_existing_config_ds) + { + suffix = cf->netscaperoot; + } + + suffix = ds_URL_encode(suffix); + fprintf(f, "dn: cn=Pass Through Authentication,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: Pass Through Authentication\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/passthru-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: passthruauth_init\n"); + fprintf(f, "nsslapd-plugintype: preoperation\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "nsslapd-pluginarg0: %s://%s:%d/%s\n", service, desc->lud_host, desc->lud_port, + suffix); + fprintf(f, "nsslapd-plugin-depends-on-type: database\n"); + fprintf(f, "\n"); + free(suffix); + ldap_free_urldesc(desc); + } + } + + fprintf(f, "dn: cn=ldbm database,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: ldbm database\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/libback-ldbm%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: ldbm_back_init\n"); + fprintf(f, "nsslapd-plugintype: database\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "nsslapd-plugin-depends-on-type: Syntax\n"); + fprintf(f, "nsslapd-plugin-depends-on-type: matchingRule\n"); + fprintf(f, "\n"); + + if (strlen(cf->suffix) == 0){ + rootdse = 1; + } + + /* Entries for the ldbm plugin */ + fprintf(f, "dn: cn=config,cn=ldbm database,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: config\n"); + fprintf(f, "nsslapd-lookthroughlimit: 5000\n"); + fprintf(f, "nsslapd-mode: 600\n"); + fprintf(f, "nsslapd-directory: %s/db\n", cs_path); + fprintf(f, "nsslapd-dbcachesize: 10485760\n"); + /* will be default from 6.2 or 6.11... */ + if (getenv("USE_OLD_IDL_SWITCH")) { + fprintf(f, "nsslapd-idl-switch: old\n"); + } + fprintf(f, "\n"); + + /* Placeholder for the default user-defined ldbm indexes */ + fprintf(f, "dn: cn=default indexes, cn=config,cn=ldbm database,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: default indexes\n"); + fprintf(f, "\n"); + + /* default user-defined ldbm indexes */ + ds_gen_index(f, "cn=default indexes, cn=config,cn=ldbm database,cn=plugins,cn=config"); + + + + + fprintf(f, "dn: cn=monitor, cn=ldbm database, cn=plugins, cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: monitor\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=database, cn=monitor, cn=ldbm database, cn=plugins, cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: database\n"); + fprintf(f, "\n"); + + /* Entries for the chaining backend plugin */ + fprintf(f, "dn: cn=chaining database,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsSlapdPlugin\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: chaining database\n"); + fprintf(f, "nsslapd-pluginpath: %s/lib/chainingdb-plugin%s\n", sroot, shared_lib); + fprintf(f, "nsslapd-plugininitfunc: chaining_back_init\n"); + fprintf(f, "nsslapd-plugintype: database\n"); + fprintf(f, "nsslapd-pluginenabled: on\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=config,cn=chaining database,cn=plugins,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: config\n"); + fprintf(f, "nsTransmittedControls: 2.16.840.1.113730.3.4.2\n"); + fprintf(f, "nsTransmittedControls: 2.16.840.1.113730.3.4.9\n"); + fprintf(f, "nsTransmittedControls: 1.2.840.113556.1.4.473\n"); + fprintf(f, "nsTransmittedControls: 1.3.6.1.4.1.1466.29539.12\n"); + fprintf(f, "nsPossibleChainingComponents: cn=resource limits,cn=components,cn=config\n"); + fprintf(f, "nsPossibleChainingComponents: cn=certificate-based authentication,cn=components,cn=config\n"); + fprintf(f, "nsPossibleChainingComponents: cn=ACL Plugin,cn=plugins,cn=config\n"); + fprintf(f, "nsPossibleChainingComponents: cn=old plugin,cn=plugins,cn=config\n"); + fprintf(f, "nsPossibleChainingComponents: cn=referential integrity postoperation,cn=plugins,cn=config\n"); + fprintf(f, "nsPossibleChainingComponents: cn=attribute uniqueness,cn=plugins,cn=config\n"); + fprintf(f, "\n"); + + free(t); + t = NULL; + + /* suffix for the mapping tree */ + fprintf(f, "dn: cn=mapping tree,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: mapping tree\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=tasks,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: tasks\n"); + fprintf(f, "\n"); + + /* Entries for the ldbm instances and mapping tree */ + if ( cf->netscaperoot && !cf->use_existing_config_ds) + { + suffix_gen_conf(f, cf->netscaperoot, "NetscapeRoot"); + } + + if (!cf->use_existing_user_ds) + { + suffix_gen_conf(f, cf->suffix, "userRoot"); + } + + if ( cf->samplesuffix && cf->suffix && PL_strcasecmp(cf->samplesuffix, cf->suffix)) + { + suffix_gen_conf(f, cf->samplesuffix, "sampleRoot"); + } + + if ( cf->testconfig && cf->suffix && PL_strcasecmp(cf->testconfig, cf->suffix)) + { + suffix_gen_conf(f, cf->testconfig, "testRoot"); + } + + + /* tasks */ + fprintf(f, "dn: cn=import,cn=tasks,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: import\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=export,cn=tasks,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: export\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=backup,cn=tasks,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: backup\n"); + fprintf(f, "\n"); + + fprintf(f, "dn: cn=restore,cn=tasks,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: restore\n"); + fprintf(f, "\n"); + +#if defined(UPGRADEDB) + fprintf(f, "dn: cn=upgradedb,cn=tasks,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: upgradedb\n"); + fprintf(f, "\n"); +#endif + /* END of tasks */ + + + fprintf(f, "dn: cn=replication,cn=config\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: extensibleObject\n"); + fprintf(f, "cn: replication\n"); + fprintf(f, "\n"); + + if( cf->replicationdn && *(cf->replicationdn) ) + { + fprintf(f, "dn: cn=replication4,cn=replication,cn=config\n"); + fprintf(f, "cn: replication4\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsConsumer4Config\n"); + fprintf(f, "nsslapd-updatedn: %s\n", cf->replicationdn); + fprintf(f, "nsslapd-updatepw: %s\n", cf->replicationhashedpw); + fprintf(f, "\n"); + } + + if(cf->changelogdir && *(cf->changelogdir) ) + { + fprintf(f, "dn: cn=changelog4,cn=config\n"); + fprintf(f, "cn: changelog4\n"); + fprintf(f, "objectclass: top\n"); + fprintf(f, "objectclass: nsChangelog4Config\n"); + fprintf(f, "nsslapd-changelogdir: %s\n", cf->changelogdir); + fprintf(f, "nsslapd-changelogsuffix: %s\n", cf->changelogsuffix); + fprintf(f, "nsslapd-changelogmaxage: 2d\n"); + fprintf(f, "\n"); + + /* create the changelog directory */ + if( (t = create_instance_mkdir_p(cf->changelogdir, NEWDIR_MODE)) ) + return(t); + } + + fclose (f); + + sprintf(src, "%s%cconfig%cdse.ldif", cs_path, FILE_PATHSEP, FILE_PATHSEP); + sprintf(fn, "%s%cconfig%cdse_original.ldif", cs_path, FILE_PATHSEP, FILE_PATHSEP); + create_instance_copy(src, fn, 0600); + + /* + * generate slapd-collations.conf + */ + sprintf(src, "%s%cbin%c"PRODUCT_NAME"%cinstall%cconfig%c%s-collations.conf", + sroot, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, + FILE_PATHSEP, PRODUCT_NAME); + sprintf(dest, "%s%cconfig%c%s-collations.conf", cs_path, FILE_PATHSEP, + FILE_PATHSEP, PRODUCT_NAME); + if (!(srcf = fopen(src, "r"))) { + return make_error("Can't read from %s (%s)", src, ds_system_errmsg()); + } + if (!(f = fopen(dest, "w"))) { + return make_error("Can't write to %s (%s)", dest, ds_system_errmsg()); + } + while (fgets(line, sizeof(line), srcf)) { + if ((line[0] != '\0') && (fputs(line, f) == EOF)) { + make_error("Error writing to file %s from copy of %s (%s)", + dest, src, ds_system_errmsg()); + } + } + if (!feof(srcf)) { + make_error("Error reading from file %s (%s)", src, ds_system_errmsg()); + } + fclose(srcf); + fclose(f); + + sprintf(src, "%s/bin/slapd/install/schema", sroot); + sprintf(dest, "%s/config/schema", cs_path); + if (t = ds_copy_group_files(src, dest, 0)) + return t; + + sprintf(src, "%s/bin/slapd/install/presence", sroot); + sprintf(dest, "%s/config/presence", cs_path); + if (t = ds_copy_group_files(src, dest, 0)) + return t; + + /* Generate the orgchart configuration */ + sprintf(src, "%s/clients", sroot); + if (is_a_dir(src, "orgchart")) { + if (t = ds_gen_orgchart_conf(sroot, cs_path, cf)) { + return t; + } + } + + /* Generate dsgw.conf */ + sprintf(src, "%s/clients", sroot); + if (is_a_dir(src, "dsgw")) { + if (t = ds_gen_gw_conf(sroot, cs_path, cf, GW_CONF)) { + return t; + } + + /* Generate pb.conf */ + if (t = ds_gen_gw_conf(sroot, cs_path, cf, PB_CONF)) { + return t; + } + } + + return NULL; /* Everything worked fine */ +} + +/* + * Function: ds_gen_gw_conf + * + * Returns: pointer to error message, or NULL if all went well + * + * Description: This generates the gateway configuration files + * for the regular gateway stuff and for the phonebook. + * + * Author: RJP + * + */ +static char * +ds_gen_gw_conf(char *sroot, char *cs_path, server_config_s *cf, int conf_type) +{ + char dest[PATH_SIZE]; + char src[PATH_SIZE]; + char line[1024]; + FILE *f = NULL; + FILE *srcf = NULL; + char *t = NULL; + const char *ctxt; + + if (conf_type == GW_CONF) { + ctxt = "dsgw"; + } else { + ctxt = "pb"; + } + /* + * generate .../dsgw/context/[dsgw|pb].conf by creating the file, placing + * install-specific config. file lines at the start of file, and then + * copying the rest from NS-HOME/dsgw/config/dsgw.tmpl + */ + + sprintf(dest, "%s%cclients%cdsgw%ccontext%c%s.conf", sroot, FILE_PATHSEP,FILE_PATHSEP, + FILE_PATHSEP, FILE_PATHSEP, ctxt); + + + /* If the config file already exists, just return success */ + if (create_instance_exists(dest)) { + return(NULL); + } + + /* Attempt to open that bad boy */ + if(!(f = fopen(dest, "w"))) { + return make_error("Can't write to %s (%s)", dest, ds_system_errmsg()); + } + + /* Write out the appropriate values */ + fprintf(f, "# Used by Netscape Directory Server Gateway\n"); + fprintf(f, "baseurl\t\"ldap://%s:%s/", cf->servname, cf->servport); + fputs_escaped(cf->suffix, f); + fputs("\"\n\n",f); + if (cf->rootdn && *(cf->rootdn)) { + t = ds_enquote_config_value(DS_ROOTDN, cf->rootdn); + fprintf(f, "dirmgr\t%s\n\n", t ); + if (t != cf->rootdn) free(t); + } + + t = ds_enquote_config_value(DS_SUFFIX, cf->suffix); + fprintf(f, "location-suffix\t%s\n\n", t); + if (t != cf->suffix) free(t); + + + fprintf(f, "securitypath\t\"%s%calias%c%s-cert.db\"\n\n", sroot, FILE_PATHSEP, FILE_PATHSEP, ctxt ); + + fprintf(f, "# The url base to the orgchart application.\n#No link from the DSGW to the orgchart will appear in the UI if this configuration line is commented out.\n"); + fprintf(f, "url-orgchart-base\thttp://%s:%s/clients/orgchart/bin/org?context=%s&data=\n\n", cf->servname, cf->adminport ? cf->adminport : "80", ctxt); + + /* copy in template */ + if (conf_type == GW_CONF) { + sprintf(src, "%s%cclients%cdsgw%cconfig%cdsgw.tmpl", + sroot, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP); + } else if (conf_type == PB_CONF) { + sprintf(src, "%s%cclients%cdsgw%cpbconfig%cpb.tmpl", + sroot, FILE_PATHSEP,FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP); + } else { + /*This should never, ever happen if this function is called correctly*/ + fclose(f); + return make_error("Unknown gateway config file requested"); + } + + + /* Try to open the dsgw.conf template file (dsgw.tmpl) */ + if(!(srcf = fopen(src, "r"))) { + fclose(f); + return make_error("Can't read %s (%s)", src, ds_system_errmsg()); + } + + while(fgets(line, sizeof(line), srcf)) { + fputs(line, f); + } + + fclose(srcf); + fclose(f); + + /* Generate default.conf */ + if (conf_type == GW_CONF) { + struct passwd* pw = NULL; + char defaultconf[PATH_SIZE]; + +#if !defined( XP_WIN32 ) + /* find the server's UID and GID */ + if (cf->servuser && *(cf->servuser)) { + if ((pw = getpwnam (cf->servuser)) == NULL) { + return make_error("Could not find UID and GID of user '%s'.", cf->servuser); + } else if (pw->pw_name == NULL) { + pw->pw_name = cf->servuser; + } + } +#endif + + sprintf(defaultconf, "%s%cclients%cdsgw%ccontext%cdefault.conf", sroot, + FILE_PATHSEP,FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP); + + create_instance_copy(dest, defaultconf, NEWFILE_MODE); + chownfile (pw, defaultconf); + } + unlink(src); + + return NULL; +} + + +/* + * Function: ds_gen_orgchart_conf + * + * Returns: pointer to error message, or NULL if all went well + * + * Description: This generates the orgchart configuration file + * + * Author: RJP + * + */ +static char * +ds_gen_orgchart_conf(char *sroot, char *cs_path, server_config_s *cf) +{ + char dest[PATH_SIZE]; + char src[PATH_SIZE]; + char line[1024]; + FILE *f = NULL; + FILE *srcf = NULL; + char *t = NULL; + + /* + * generate .../clients/orgchart/config.txt by creating the file, placing + * install-specific config. file lines at the start of file, and then + * copying the rest from NS-HOME/clients/orgchart/config.tmpl + */ + sprintf(dest, "%s%cclients%corgchart%cconfig.txt", sroot, FILE_PATHSEP, + FILE_PATHSEP, FILE_PATHSEP ); + sprintf(src, "%s%cclients%corgchart%cconfig.tmpl", sroot, FILE_PATHSEP, + FILE_PATHSEP, FILE_PATHSEP); + + /* If the config file already exists, just return success */ + if (create_instance_exists(dest)) { + return(NULL); + } + + /* Attempt to open that bad boy */ + if(!(f = fopen(dest, "w"))) { + return make_error("Cannot write to %s (%s)", dest, ds_system_errmsg()); + } + + /* Write out the appropriate values */ + fprintf(f, "#############\n#\n#\n"); + fprintf(f, "# Configuration file for Netscape Directory Server Org Chart\n"); + fprintf(f, "# ----------------------------------------------------------\n#\n#\n"); + fprintf(f, "#############\n\n\n#\n"); + fprintf(f, "# Blank lines in this file, as well as lines that\n"); + fprintf(f, "# start with at least one \"#\" character, are both ignored.\n"); + fprintf(f, "#\n#\n"); + fprintf(f, "# Name/Value pairs below are (and need to be) separated with\n"); + fprintf(f, "# one or more tabs (or spaces)\n"); + fprintf(f, "#\n"); + + fprintf(f, "ldap-host\t%s\n", cf->servname); + fprintf(f, "ldap-port\t%s\n", cf->servport); + fprintf(f, "ldap-search-base\t%s\n\n", cf->suffix); + + fprintf(f, "#\n# If you would like to have the phonebook icon visible, you must\n"); + fprintf(f, "# supply the partial phonebook URL below, which will have each\n"); + fprintf(f, "# given user's DN attribute value concatenated to the end.\n"); + fprintf(f, "#\n# For example, you could specify below something close to:\n"); + fprintf(f, "#\n# url-phonebook-base http://hostname.domain.com/dsgw/bin/dosearch?context=default&hp=localhost&dn=\n#\n\n"); + fprintf(f, "url-phonebook-base\thttp://%s:%s/clients/dsgw/bin/dosearch?context=pb&hp=%s:%s&dn=\n\n",cf->servname, cf->adminport ? cf->adminport : "80", cf->servname, cf->servport); + + /*fputs_escaped(cf->suffix, f);*/ + /*fprintf(f, "\n\n");*/ + /* + *t = ds_enquote_config_value(DS_SUFFIX, cf->suffix); + *fprintf(f, "location-suffix\t%s\n\n", t); + *if (t != cf->suffix) free(t); + */ + + /*if (cf->rootdn && *(cf->rootdn)) { + *t = ds_enquote_config_value(DS_ROOTDN, cf->rootdn); + *fprintf(f, "dirmgr\t%s\n\n", t ); + *if (t != cf->rootdn) free(t); + }*/ + + /* Try to open the config.txt template file (config.tmpl) */ + if(!(srcf = fopen(src, "r"))) { + fclose(f); + return make_error("Can't read %s (%s)", src, ds_system_errmsg()); + } + + while(fgets(line, sizeof(line), srcf)) { + fputs(line, f); + } + + fclose(srcf); + fclose(f); + + unlink(src); + return NULL; +} + +/* + * Function: gen_presence_init + * + * Description: Creates a script to initialize images for use in the IM + * Presence plugin. + */ +#define PRESENCE_LDIF "init_presence_images.ldif" +static char *gen_presence_init_script(char *sroot, server_config_s *cf, + char *cs_path) +{ + char fn[PATH_SIZE]; + char dir[PATH_SIZE]; + FILE *f; + + sprintf(dir, "%s%cconfig%cpresence", + cs_path, FILE_PATHSEP, FILE_PATHSEP); + sprintf(fn, "%s%c%s", + dir, FILE_PATHSEP, PRESENCE_LDIF); + + if(!(f = fopen(fn, "w"))) + return make_error("Could not write to %s (%s).", fn, ds_system_errmsg()); + + fprintf( f, + "dn:cn=ICQ Presence,cn=Presence,cn=plugins,cn=config\n" + "changeType:modify\n" + "replace:nsim-onvaluemapgraphic\n" + "nsim-onvaluemapgraphic: %s%cicq-online.gif\n" + "\n" + "dn:cn=ICQ Presence,cn=Presence,cn=plugins,cn=config\n" + "changeType:modify\n" + "replace:nsim-offvaluemapgraphic\n" + "nsim-offvaluemapgraphic: %s%cicq-offline.gif\n" + "\n" + "dn:cn=ICQ Presence,cn=Presence,cn=plugins,cn=config\n" + "changeType:modify\n" + "replace:nsim-disabledvaluemapgraphic\n" + "nsim-disabledvaluemapgraphic: %s%cicq-disabled.gif\n" + "\n" + "dn:cn=AIM Presence,cn=Presence,cn=plugins,cn=config\n" + "changeType:modify\n" + "replace:nsim-onvaluemapgraphic\n" + "nsim-onvaluemapgraphic: %s%caim-online.gif\n" + "\n" + "dn:cn=AIM Presence,cn=Presence,cn=plugins,cn=config\n" + "changeType:modify\n" + "replace:nsim-offvaluemapgraphic\n" + "nsim-offvaluemapgraphic: %s%caim-offline.gif\n" + "\n" + "dn:cn=AIM Presence,cn=Presence,cn=plugins,cn=config\n" + "changeType:modify\n" + "replace:nsim-disabledvaluemapgraphic\n" + "nsim-disabledvaluemapgraphic: %s%caim-offline.gif\n" + "\n" + "dn:cn=Yahoo Presence,cn=Presence,cn=plugins,cn=config\n" + "changeType:modify\n" + "replace:nsim-offvaluemapgraphic\n" + "nsim-offvaluemapgraphic: %s%cyahoo-offline.gif\n" + "\n" + "dn:cn=Yahoo Presence,cn=Presence,cn=plugins,cn=config\n" + "changeType:modify\n" + "replace:nsim-onvaluemapgraphic\n" + "nsim-onvaluemapgraphic: %s%cyahoo-online.gif\n" + "\n" + "dn:cn=Yahoo Presence,cn=Presence,cn=plugins,cn=config\n" + "changeType:modify\n" + "replace:nsim-disabledvaluemapgraphic\n" + "nsim-disabledvaluemapgraphic: %s%cyahoo-offline.gif\n", + dir, FILE_PATHSEP, + dir, FILE_PATHSEP, + dir, FILE_PATHSEP, + dir, FILE_PATHSEP, + dir, FILE_PATHSEP, + dir, FILE_PATHSEP, + dir, FILE_PATHSEP, + dir, FILE_PATHSEP, + dir, FILE_PATHSEP + ); + fclose(f); + return NULL; +} + +/* + * Function init_presence + * + * Description: Runs ldapmodify to initialize the images used by the + * IM presence plugin + */ +static int init_presence(char *sroot, server_config_s *cf, char *cs_path) +{ + char cmd[PATH_SIZE]; + char tools[PATH_SIZE]; + char precmd[PATH_SIZE]; + + precmd[0] = 0; + sprintf(tools, "%s%cshared%cbin", sroot, FILE_PATHSEP, FILE_PATHSEP); + +#ifdef XP_UNIX + sprintf(precmd, "cd %s;", tools); +#endif + + sprintf(cmd, "%s%s%cldapmodify -q -p %d -b -D \"%s\" -w \"%s\" " + "-f %s%s%cconfig%cpresence%c%s%s", + precmd, + tools, FILE_PATHSEP, + atoi(cf->servport), + cf->rootdn, + cf->rootpw, + ENQUOTE, cs_path, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, + PRESENCE_LDIF, ENQUOTE); + return ds_exec_and_report( cmd ); +} + +/* + * Function: ds_gen_index + * + * Description: This generates the default index list. + * This function is passed the parent entry below which the nsIndex + * entries must be created. This allows to use it when creating: + * - the default index list (ie belowdn = cn=default indexes,cn=config...) + * - the userRoot backend (ie belowdn = cn=index,cn=userRoot...) + * + */ +static void +ds_gen_index(FILE* f, char* belowdn) +{ +#define MKINDEX(_name, _inst, _sys, _type1, _type2, _type3) do { \ + fprintf(f, "dn: cn=%s,%s\n", (_name), (_inst)); \ + fprintf(f, "objectclass: top\n"); \ + fprintf(f, "objectclass: nsIndex\n"); \ + fprintf(f, "cn: %s\n", (_name)); \ + fprintf(f, "nssystemindex: %s\n", (_sys) ? "true" : "false"); \ + if (_type1) \ + fprintf(f, "nsindextype: %s\n", (_type1)); \ + if (_type2) \ + fprintf(f, "nsindextype: %s\n", (_type2)); \ + if (_type3) \ + fprintf(f, "nsindextype: %s\n", (_type3)); \ + fprintf(f, "\n"); \ +} while (0) + + MKINDEX("aci", belowdn, 1, "pres", NULL, NULL); + MKINDEX("cn", belowdn, 0, "pres", "eq", "sub"); + MKINDEX("entrydn", belowdn, 1, "eq", NULL, NULL); + MKINDEX("givenName", belowdn, 0, "pres", "eq", "sub"); + MKINDEX("mail", belowdn, 0, "pres", "eq", "sub"); + MKINDEX("mailAlternateAddress", belowdn, 0, "eq", NULL, NULL); + MKINDEX("mailHost", belowdn, 0, "eq", NULL, NULL); + MKINDEX("member", belowdn, 0, "eq", NULL, NULL); + MKINDEX("nsCalXItemId", belowdn, 0, "pres", "eq", "sub"); + MKINDEX("nsLIProfileName", belowdn, 0, "eq", NULL, NULL); + MKINDEX("nsUniqueId", belowdn, 1, "eq", NULL, NULL); + MKINDEX("nswcalCALID", belowdn, 0, "eq", NULL, NULL); + MKINDEX("numsubordinates", belowdn, 1, "pres", NULL, NULL); + MKINDEX("objectclass", belowdn, 1, "eq", NULL, NULL); + MKINDEX("owner", belowdn, 0, "eq", NULL, NULL); + MKINDEX("parentid", belowdn, 1, "eq", NULL, NULL); + MKINDEX("pipstatus", belowdn, 0, "eq", NULL, NULL); + MKINDEX("pipuid", belowdn, 0, "pres", NULL, NULL); + MKINDEX("seeAlso", belowdn, 0, "eq", NULL, NULL); + MKINDEX("sn", belowdn, 0, "pres", "eq", "sub"); + MKINDEX("telephoneNumber", belowdn, 0, "pres", "eq", "sub"); + MKINDEX("uid", belowdn, 0, "eq", NULL, NULL); + MKINDEX("uniquemember", belowdn, 0, "eq", NULL, NULL); +} + + + +static char *install_ds(char *sroot, server_config_s *cf, char *param_name) +{ + SLAPD_CONFIG slapd_conf; + QUERY_VARS query_vars; + char *t, src[PATH_SIZE], dest[PATH_SIZE], big_line[PATH_SIZE]; + char cs_path[PATH_SIZE]; + struct passwd* pw = NULL; + int isrunning; + int status = 0; +#ifdef XP_WIN32 + WSADATA wsadata; +#endif + +#if !defined( XP_WIN32 ) + /* find the server's UID and GID */ + if (cf->servuser && *(cf->servuser)) { + if ((pw = getpwnam (cf->servuser)) == NULL) { + strcpy(param_name, "servuser"); + return make_error("Could not find UID and GID of user '%s'.", + cf->servuser); + } else if (pw->pw_name == NULL) { + pw->pw_name = cf->servuser; + } + } +#endif + + sprintf(cs_path, "%s%c"PRODUCT_NAME"-%s", sroot, FILE_PATHSEP, cf->servid); + + /* create all <a_server>/<subdirs> */ + if ( (t = ds_cre_subdirs(sroot, cf, cs_path, pw)) ) + return(t); + + /* Generate all scripts */ + if ( (t = ds_gen_scripts(sroot, cf, cs_path)) ) + return(t); + +#if defined( XP_WIN32 ) + ds_dostounixpath( sroot ); + ds_dostounixpath( cs_path ); +#endif + + /* Generate all conf files */ + if ( (t = ds_gen_confs(sroot, cf, cs_path)) ) + return(t); + + sprintf(src, "%s%cbin%c"PRODUCT_NAME"%cinstall%cldif%cExample.ldif", sroot, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, + FILE_PATHSEP); + sprintf(dest, "%s%cldif%cExample.ldif", cs_path, FILE_PATHSEP, FILE_PATHSEP); + create_instance_copy(src, dest, NEWFILE_MODE); + chownfile (pw, dest); + + sprintf(src, "%s%cbin%c"PRODUCT_NAME"%cinstall%cldif%cExample-roles.ldif", sroot, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, + FILE_PATHSEP); + sprintf(dest, "%s%cldif%cExample-roles.ldif", cs_path, FILE_PATHSEP, FILE_PATHSEP); + create_instance_copy(src, dest, NEWFILE_MODE); + chownfile (pw, dest); + + sprintf(src, "%s%cbin%c"PRODUCT_NAME"%cinstall%cldif%cExample-views.ldif", sroot, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, + FILE_PATHSEP); + sprintf(dest, "%s%cldif%cExample-views.ldif", cs_path, FILE_PATHSEP, FILE_PATHSEP); + create_instance_copy(src, dest, NEWFILE_MODE); + chownfile (pw, dest); + + sprintf(src, "%s%cbin%c"PRODUCT_NAME"%cinstall%cldif%cEuropean.ldif", sroot, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, + FILE_PATHSEP); + sprintf(dest, "%s%cldif%cEuropean.ldif", cs_path, FILE_PATHSEP, FILE_PATHSEP); + create_instance_copy(src, dest, NEWFILE_MODE); + chownfile (pw, dest); + + /* new code for dsml sample files */ + sprintf(src, "%s%cbin%c"PRODUCT_NAME"%cinstall%cdsml%cExample.dsml", sroot, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, + FILE_PATHSEP); + sprintf(dest, "%s%cdsml%cExample.dsml", cs_path, FILE_PATHSEP, FILE_PATHSEP); + create_instance_copy(src, dest, NEWFILE_MODE); + chownfile (pw, dest); + + sprintf(src, "%s%cbin%c"PRODUCT_NAME"%cinstall%cdsml%cExample-roles.dsml", sroot, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, + FILE_PATHSEP); + sprintf(dest, "%s%cdsml%cExample-roles.dsml", cs_path, FILE_PATHSEP, FILE_PATHSEP); + create_instance_copy(src, dest, NEWFILE_MODE); + chownfile (pw, dest); + + sprintf(src, "%s%cbin%c"PRODUCT_NAME"%cinstall%cdsml%cEuropean.dsml", sroot, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP, + FILE_PATHSEP); + sprintf(dest, "%s%cdsml%cEuropean.dsml", cs_path, FILE_PATHSEP, FILE_PATHSEP); + create_instance_copy(src, dest, NEWFILE_MODE); + chownfile (pw, dest); + + /* + If the user has specified an LDIF file to use to initialize the database, + load it now + */ + if (cf->install_ldif_file && !access(cf->install_ldif_file, 0)) + { + char msg[2*PATH_SIZE] = {0}; + int status = ds_ldif2db_backend_subtree(cf->install_ldif_file, NULL, cf->suffix); + if (status) + sprintf(msg, "The file %s could not be loaded", + cf->install_ldif_file); + else + sprintf(msg, "The file %s was successfully loaded", + cf->install_ldif_file); + ds_show_message(msg); + free(cf->install_ldif_file); + cf->install_ldif_file = NULL; + } + + /* + All of the config files have been written, and the server should + be ready to go. Start the server if the user specified to start + it or if we are configuring the server to serve as the repository + for SuiteSpot (Mission Control) information + Only attempt to start the server if the port is not in use + */ + if(needToStartServer(cf) && + !(t = create_instance_checkport(cf->bindaddr, cf->servport))) + { + sprintf(big_line,"SERVER_NAMES=slapd-%s",cf->servid); + putenv(big_line); + + isrunning = ds_get_updown_status(); + + if (isrunning != DS_SERVER_UP) + { + int start_status = 0; + int verbose = 1; + char instance_dir[PATH_SIZE], errorlog[PATH_SIZE]; + + if (getenv("USE_DEBUGGER")) + verbose = 0; + /* slapd-nickname directory */ + sprintf(instance_dir, "%s%c"PRODUCT_NAME"-%s", sroot, FILE_PATHSEP, + cf->servid); + /* error log file */ + sprintf(errorlog, "%s%clogs%cerrors", instance_dir, FILE_PATHSEP, + FILE_PATHSEP); + start_status = ds_bring_up_server_install(verbose, instance_dir, errorlog); + + if (start_status != DS_SERVER_UP) + { + /* + If we were going to configure the server for SuiteSpot (Mission + Control), the server must be running. Therefore, it is a very + bad thing, and we want to exit with a non zero exit code so the + caller will know something went wrong. + Otherwise, if the user just wanted to start the server for some + reason, just exit with a zero and the messages printed will + let the user know the server wasn't started. + */ + char *msg; + if (start_status == DS_SERVER_PORT_IN_USE) + msg = "The server could not be started because the port is in use."; + else if (start_status == DS_SERVER_MAX_SEMAPHORES) + msg = "No more servers may be installed on this system.\nPlease refer to documentation for information about how to\nincrease the number of installed servers per system."; + else if (start_status == DS_SERVER_CORRUPTED_DB) + msg = "The server could not be started because the database is corrupted."; + else if (start_status == DS_SERVER_NO_RESOURCES) + msg = "The server could not be started because the operating system is out of resources (e.g. CPU memory)."; + else if (start_status == DS_SERVER_COULD_NOT_START) + msg = "The server could not be started due to invalid command syntax or operating system resource limits."; + else + msg = "The server could not be started."; + + if( cf->cfg_sspt && !strcmp(cf->cfg_sspt, "1") ) + { + ds_report_error(DS_SYSTEM_ERROR, "server", msg); + return msg; + } + else + { + ds_show_message(msg); + return 0; + } + } + else + { + ds_show_message("Your new directory server has been started."); + } + } + + /* write ldap.conf */ + write_ldap_info( sroot, cf ); + +#ifdef XP_UNIX + ds_become_localuser_name (cf->servuser); +#endif +#ifdef XP_WIN32 + if( errno = WSAStartup(0x0101, &wsadata ) != 0 ) + { + char szTmp[512]; + /*replaced errno > -1 && errno < sys_nerr ? sys_errlist[errno] : + "unknown" with strerror(errno)*/ + sprintf(szTmp, "Error: Windows Sockets initialization failed errno %d (%s)<br>\n", errno, + strerror(errno), 0 ); + + fprintf (stdout, szTmp); + return 0; + } +#endif /* XP_WIN32 */ + + memset( &query_vars, 0, sizeof(query_vars) ); + if (!cf->use_existing_user_ds) + query_vars.suffix = myStrdup( cf->suffix ); + query_vars.ssAdmID = myStrdup( cf->cfg_sspt_uid ); + query_vars.ssAdmPW1 = myStrdup( cf->cfg_sspt_uidpw ); + query_vars.ssAdmPW2 = myStrdup( cf->cfg_sspt_uidpw ); + query_vars.rootDN = myStrdup( cf->rootdn ); + query_vars.rootPW = myStrdup( cf->rootpw ); + query_vars.admin_domain = + myStrdup( cf->admin_domain ); + query_vars.netscaperoot = myStrdup( cf->netscaperoot ); + query_vars.testconfig = myStrdup( cf->testconfig ); + query_vars.consumerDN = myStrdup(cf->consumerdn); + query_vars.consumerPW = myStrdup(cf->consumerhashedpw); + if (cf->cfg_sspt && !strcmp(cf->cfg_sspt, "1")) + query_vars.cfg_sspt = 1; + else + query_vars.cfg_sspt = 0; + + if (cf->suitespot3x_uid) + query_vars.config_admin_uid = myStrdup(cf->suitespot3x_uid); + else + query_vars.config_admin_uid = myStrdup(cf->cfg_sspt_uid); + + memset(&slapd_conf, 0, sizeof(SLAPD_CONFIG)); + if (sroot) + strcpy(slapd_conf.slapd_server_root, sroot); + if (cf->servport) + slapd_conf.port = atoi(cf->servport); + if (cf->servname) + strcpy(slapd_conf.host, cf->servname); + + status = config_suitespot(&slapd_conf, &query_vars); + if (status == -1) /* invalid or null arguments or configuration */ + return "Invalid arguments for server configuration."; + } + else if (t) /* just notify the user about the port conflict */ + { + ds_show_message(t); + } + + /* Create script for initializing IM Presence images */ + if ((NULL == t) && (0 == status)) + { + if ( (t = gen_presence_init_script(sroot, cf, cs_path)) ) + return(t); + /* Initialize IM Presence images */ + status = init_presence(sroot, cf, cs_path); + if (status) + return make_error ("ds_exec_and_report() failed (%d).", status); + } + + if (status) + return make_error ("Could not configure server (%d).", status); + + return(NULL); +} + +/* write_ldap_info() : writes ldap.conf */ + +static int +write_ldap_info( char *slapd_server_root, server_config_s *cf) +{ + FILE* fp; + int ret = 0; + + char* fmt = "%s/shared/config/ldap.conf"; + char* infoFileName; + + if (!slapd_server_root) { + return -1; + } + + infoFileName = (char*)malloc(strlen(fmt) + strlen(slapd_server_root) + 1); + sprintf(infoFileName, fmt, slapd_server_root); + + if ((fp = fopen(infoFileName, "w")) == NULL) + { + ret = -1; + } + else + { + fprintf(fp, "url\tldap://%s:%d/", + cf->servname, atoi(cf->servport)); + + if (cf->suffix) + fprintf(fp, "%s", cf->suffix); + + fprintf(fp, "\n"); + + if (cf->cfg_sspt_uid) { + fprintf(fp, "admnm\t%s\n", cf->cfg_sspt_uid); + } + + fclose(fp); + } +#if defined( SOLARIS ) + /* + * Solaris 9+ specific installation + */ + if (iDSISolaris) + logUninstallInfo(slapd_server_root, PRODUCT_NAME, PRODUCT_NAME, infoFileName); + +#endif /* SOLARIS */ + free(infoFileName); + + return ret; +} + diff --git a/ldap/admin/src/create_instance.h b/ldap/admin/src/create_instance.h new file mode 100644 index 00000000..d1f7c5c3 --- /dev/null +++ b/ldap/admin/src/create_instance.h @@ -0,0 +1,112 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * create_instance.h: create an instance of a directory server + * + * Rob McCool + */ + + +#ifndef _create_instance_h +#define _create_instance_h + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + + +#ifdef XP_UNIX +#define PRODUCT_NAME "slapd" + +#define PRODUCT_BIN "ns-slapd" + +#endif + +typedef struct { + char *sroot; + + char *servname; + char *bindaddr; + char *servport; + char *suitespot3x_uid; + char *cfg_sspt; + char *cfg_sspt_uid; + char *cfg_sspt_uidpw; + char *secserv; + char *secservport; + char *ntsynch; + char *ntsynchssl; + char *ntsynchport; + char *rootdn; + char *rootpw; + char *roothashedpw; + char *replicationdn; + char *replicationpw; + char *replicationhashedpw; + char *consumerdn; + char *consumerpw; + char *consumerhashedpw; + char *changelogdir; + char *changelogsuffix; + char *suffix; + char *loglevel; + char *netscaperoot; + char *samplesuffix; + char *testconfig; + char *servid; +#ifdef XP_UNIX + char *servuser; + char *numprocs; +#endif + char *minthreads; + char *maxthreads; + int upgradingServer; + + char * start_server; + + char * admin_domain; + char * config_ldap_url; + char * user_ldap_url; + int use_existing_user_ds; + int use_existing_config_ds; + char * disable_schema_checking; + char * install_ldif_file; + char *adminport; +} server_config_s; + + +#ifdef NS_UNSECURE +#define DEFAULT_ID "unsecure" +#else +#define DEFAULT_ID "secure" +#endif + +/* + Initialize a server config structure with default values, using sroot + as the server root, and hn as the machine's full host name. + */ +void set_defaults(char *sroot, char *hn, server_config_s *conf); + +/* + Create a server using the given configuration structure. This affects + files and directories in the structure's server root. space for param_name + should be allocated by the caller e.g. char param_name[ENOUGH_ROOM]. + If there was a problem with one of the parameters passed in for instance + creation e.g. servport is out of range, the param_name parameter will be + filled in with "servport" and the error message returned will contain + additional detail + */ +char *create_server(server_config_s *cf, char *param_name); + +/* from script-gen.c */ +int generate_script(const char *inpath, const char *outpath, int mode, + const char *table[][2]); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/ldap/admin/src/ds_bak2db.c b/ldap/admin/src/ds_bak2db.c new file mode 100644 index 00000000..d4ce49e4 --- /dev/null +++ b/ldap/admin/src/ds_bak2db.c @@ -0,0 +1,71 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * Restores a database. + * + * Anil Bhavnani + * Removed all HTML output for DS 4.0: Rob Weltman + */ + +#include <stdio.h> +#include <stdlib.h> +#include "libadminutil/admutil.h" +#include "dsalib.h" +#include "init_ds_env.h" +#include <string.h> + +int main(int argc, char *argv[]) +{ + int isrunning; + char *filename = NULL; + int status; + + fprintf(stdout, "Content-type: text/html\n\n"); + + if ( init_ds_env() ) + return 1; + + /* + * Get value of the "filename" variable. + */ + filename = ds_get_cgi_var("filename"); + if ( (NULL == filename) || (strlen(filename) < 1) ) { + fprintf(stdout, "Environment variable filename not defined.\n"); + rpt_err( DS_UNDEFINED_VARIABLE, "filename", NULL, NULL ); + return 1; + } + + /* Check if server is up */ + isrunning = ds_get_updown_status(); + + /* Stop it, if so */ + if (isrunning != DS_SERVER_DOWN) { + status = ds_bring_down_server(); + if(status != DS_SERVER_DOWN) { + rpt_err( DS_SERVER_MUST_BE_DOWN, filename, NULL, NULL ); + return 1; + } + } + + ds_send_status("restoring database ..."); + status = ds_bak2db(filename); + + if ( !status ) { + rpt_success("Success! The database has been restored."); + status = 0; + } else { + rpt_err( status, filename, NULL, NULL ); + status = 1; + } + + /* Restart the server if we brought it down */ + if (isrunning != DS_SERVER_DOWN) { + if(ds_bring_up_server(1) != DS_SERVER_UP) { + ds_send_status( "An error occurred during startup" ); + } + } + return status; +} diff --git a/ldap/admin/src/ds_db2bak.c b/ldap/admin/src/ds_db2bak.c new file mode 100644 index 00000000..bca6bce5 --- /dev/null +++ b/ldap/admin/src/ds_db2bak.c @@ -0,0 +1,77 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * Backs up the database. + * + * Anil Bhavnani + * Removed all HTML output for DS 4.0: Rob Weltman + */ + +#include <stdio.h> +#include <stdlib.h> +#include "libadminutil/admutil.h" +#include "dsalib.h" +#include "init_ds_env.h" +#include <string.h> +#ifdef XP_UNIX +#include <unistd.h> +#endif + +int main(int argc, char *argv[]) +{ + char *filename = NULL; + int status; + + fprintf(stdout, "Content-type: text/html\n\n"); + + if ( init_ds_env() ) + return 1; + + /* + * Get value of the "filename" variable. + */ + filename = ds_get_cgi_var("filename"); + if ( (NULL == filename) || (strlen(filename) < 1) ) { + rpt_err( DS_UNDEFINED_VARIABLE, "filename", NULL, NULL ); + return 1; + } + + ds_become_localuser (ds_get_config (DS_REAL_CONFIG)); + +#define NEWDIR_MODE 0755 + /* Attempt to detect up front if file cannot be written */ + status = -1; + /* Attempt to create the backup directory */ + if ( 0 == ds_mkdir_p(filename, NEWDIR_MODE) ) { + char foo[256]; + FILE *f; + /* Now attempt to create a file there (the directory might + already have existed */ + sprintf( foo, "%s%c%s", filename, FILE_PATHSEP, "foo" ); + f = fopen(foo, "w"); + if ( NULL != f ) { + status = 0; + fclose( f ); + unlink( foo ); + } + } + if ( status ) { + rpt_err( DS_CANNOT_CREATE_FILE, filename, NULL, NULL ); + return 1; + } + + ds_send_status("backing up database ..."); + + status = ds_db2bak( filename ); /* prints errors as needed */ + + if ( !status ) { + rpt_success("Success! The database has been backed up."); + return 0; + } else { + rpt_err( status, filename, NULL, NULL ); + return 1; + } +} diff --git a/ldap/admin/src/ds_db2ldif.c b/ldap/admin/src/ds_db2ldif.c new file mode 100644 index 00000000..42c755a4 --- /dev/null +++ b/ldap/admin/src/ds_db2ldif.c @@ -0,0 +1,78 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * Converts the database into an ldif file. + * + * Anil Bhavnani + * Removed all HTML output for DS 4.0: Rob Weltman + */ + +#include <stdio.h> +#include <stdlib.h> +#include "libadminutil/admutil.h" +#include "dsalib.h" +#include "init_ds_env.h" +#include <string.h> +#ifdef XP_UNIX +#include <unistd.h> +#endif + +int main(int argc, char *argv[]) +{ + char *filename = NULL; + char *subtree = NULL; + int status; + FILE *f; + + fprintf(stdout, "Content-type: text/html\n\n"); + + if ( init_ds_env() ) + return 1; + + /* + * Get value of the "filename" variable. + */ + filename = ds_get_cgi_var("filename"); + if ( (NULL == filename) || (strlen(filename) < 1) ) { + rpt_err( DS_UNDEFINED_VARIABLE, "filename", NULL, NULL ); + return 1; + } + + ds_become_localuser (ds_get_config (DS_REAL_CONFIG)); + + /* Attempt to detect up front if file cannot be written */ + f = fopen(filename, "w"); + if ( NULL != f ) { + fclose( f ); + unlink( filename ); + } else { + rpt_err( DS_CANNOT_CREATE_FILE, filename, NULL, NULL ); + return 1; + } + + /* + * Get value of the "subtree" variable. + */ + subtree = ds_get_cgi_var("subtree"); + + ds_send_status("creating LDIF file ..."); + + if ( (subtree != NULL) && (*subtree != 0) ) { + char *escaped = ds_escape_for_shell( subtree ); + status = ds_db2ldif_subtree(filename, escaped); + free( escaped ); + } else { + status = ds_db2ldif(filename); /* prints errors as needed */ + } + + if ( !status ) { + rpt_success("Success! The database has been exported."); + return 0; + } else { + rpt_err( status, filename, NULL, NULL ); + return 1; + } +} diff --git a/ldap/admin/src/ds_ldif2db.c b/ldap/admin/src/ds_ldif2db.c new file mode 100644 index 00000000..f98c47da --- /dev/null +++ b/ldap/admin/src/ds_ldif2db.c @@ -0,0 +1,103 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * ds_ldif2db.c: Converts an ldif file into a database. + * + * Anil Bhavnani + * Removed all HTML output for DS 4.0: Rob Weltman + */ + +#include <stdio.h> +#include <stdlib.h> +#include "libadminutil/admutil.h" +#include "dsalib.h" +#include "init_ds_env.h" +#include <string.h> + +int main(int argc, char *argv[]) +{ + int isrunning; + char *filename = NULL; + char *saveconfig = NULL; + int preserve; + int status; + + setbuf(stdout, 0); +#ifdef DEBUG_CGI + freopen("\\tmp\\stderr.out", "w", stderr); +#else + dup2(fileno(stdout), fileno(stderr)); +#endif /* DEBUG_CGI */ + fprintf(stdout, "Content-type: text/html\n\n"); + + if ( init_ds_env() ) + return 1; + + /* + * Get value of the "filename" variable. + */ + filename = ds_get_cgi_var("filename"); + if ( (NULL == filename) || (strlen(filename) < 1) ) { + rpt_err( DS_UNDEFINED_VARIABLE, "filename", NULL, NULL ); + return 1; + } + +#ifdef DEBUG_CGI + fprintf(stderr, "filename=%s\n", filename); +#endif /* DEBUG_CGI */ + + /* + * Get value of the "saveconfig" variable. + */ + saveconfig = ds_get_cgi_var("saveconfig"); + preserve = ( (saveconfig == NULL) || !(strcmp(saveconfig,"true")) ); + +#ifdef DEBUG_CGI + fprintf(stderr, "preserve=%d\n", preserve); +#endif /* DEBUG_CGI */ + + /* Check if server is up */ + isrunning = ds_get_updown_status(); + +#ifdef DEBUG_CGI + fprintf(stderr, "isrunning=%d\n", isrunning); +#endif /* DEBUG_CGI */ + + /* Stop it, if so */ + if (isrunning != DS_SERVER_DOWN) { + status = ds_bring_down_server(); +#ifdef DEBUG_CGI + fprintf(stderr, "status=%d\n", status); +#endif /* DEBUG_CGI */ + if(status != DS_SERVER_DOWN) { + rpt_err( DS_SERVER_MUST_BE_DOWN, filename, NULL, NULL ); + return 1; + } + } + + ds_send_status("creating database ..."); + if ( preserve ) + status = ds_ldif2db_preserve(filename); /* prints errors as needed */ + else + status = ds_ldif2db(filename); /* prints errors as needed */ + + if ( !status ) { + rpt_success("Success! The database has been imported."); + status = 0; + } else { + rpt_err( status, filename, NULL, NULL ); + status = 1; + } + + /* Restart the server if we brought it down */ + if (isrunning != DS_SERVER_DOWN) { + int retval; + if((retval=ds_bring_up_server(1)) != DS_SERVER_UP) { + ds_send_status( "An error occurred during startup" ); + } + } + return status; +} diff --git a/ldap/admin/src/ds_listdb.c b/ldap/admin/src/ds_listdb.c new file mode 100644 index 00000000..5d0c06ad --- /dev/null +++ b/ldap/admin/src/ds_listdb.c @@ -0,0 +1,37 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * List the database backup directories. + * No HTML - this is for DS 4.0. + * + * Rob Weltman + */ + +#include <stdio.h> +#include <stdlib.h> +#include "dsalib.h" + +int main(int argc, char *argv[], char *envp[]) +{ + char **bak_dirs; + + ds_become_localuser (ds_get_config (DS_REAL_CONFIG)); + + /* Tell the receiver we are about to start sending data */ + fprintf(stdout, "\n"); + bak_dirs = ds_get_bak_dirs(); + if ( bak_dirs != NULL ) /* no error */ { + char **cur_file = bak_dirs; + while ( *cur_file != NULL ) { + fprintf(stdout, "%s\n", *cur_file); + cur_file++; + } + } + + ds_become_original(); + + return 0; +} diff --git a/ldap/admin/src/ds_remove.c b/ldap/admin/src/ds_remove.c new file mode 100644 index 00000000..c9fa8020 --- /dev/null +++ b/ldap/admin/src/ds_remove.c @@ -0,0 +1,234 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * Remove the server + * + * Prasanta Behera + */ +#ifdef XP_WIN32 +#include <windows.h> +#include <io.h> +#include "regparms.h" +extern BOOL DeleteServer(LPCSTR pszServiceId); +#endif + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "libadminutil/admutil.h" +#ifdef XP_UNIX +#include <sys/errno.h> +#include <dirent.h> +#include <sys/types.h> +#include <fcntl.h> +#include <sys/ipc.h> +#include <sys/sem.h> +#else +#endif /* WIN32? */ +#include <sys/stat.h> + +#include "dsalib.h" +#include "init_ds_env.h" +#include "ds_remove_uninst.h" + + +#include "nspr.h" + +/* this will be set to 1 if we need to retry the + rm -rf of the instance directory again */ +static int try_rm_rf_again = 0; + +static int +rm_rf_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); + } + + /* ignore "file or directory already removed" errors */ + if (errcode != PR_FILE_NOT_FOUND_ERROR) { + msg = PR_smprintf("%s %s: error code %d (%s)", op, path, errcode, errtext); + ds_send_error(msg, 0); + PR_smprintf_free(msg); + } + + /* On Windows and HPUX, if the file/directory to remove is opened by another + application, it cannot be removed and will generate a busy error + This usually happens when we attempt to stop slapd then remove the + instance directory, but for some reason the process still has some + open files + In this case, we need to wait for some period of time then attempt to + remove the instance directory again + */ + if (errcode == PR_FILE_IS_BUSY_ERROR) { + try_rm_rf_again = 1; + return 0; /* just abort the operation */ + } + +#ifdef XP_WIN32 + /* on windows, err 145 means dir not empty + 145 The directory is not empty. ERROR_DIR_NOT_EMPTY + If there was a busy file, it wasn't able to be + removed, so when we go to remove the directory, it + won't be empty + */ + if (errcode == ERROR_DIR_NOT_EMPTY) { + if (try_rm_rf_again) { + return 0; /* don't continue */ + } + } +#else /* unix */ + if (errcode == EEXIST) { /* not empty */ + if (try_rm_rf_again) { + return 0; /* don't continue */ + } + } +#endif + + return 1; /* just continue */ +} + +int main(int argc, char *argv[]) +{ + int status = -1; + char *servername; + char *installroot; + int isRunning; +#ifndef __LP64__ +#ifdef hpux + _main(); +#endif +#endif + +#ifdef XP_WIN32 + if ( getenv("DEBUG_DSINST") ) + DebugBreak(); +#endif + + /* case 1: being called as program -f inffile */ + if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'f') + { + FILE *infFile = fopen(argv[2], "r"); + if (!infFile) + { + ds_report_error (DS_INCORRECT_USAGE, argv[2], + "This file could not be opened. A valid file must be given."); + status = 1; + + return status; + } + else + fclose(infFile); + + ds_uninst_set_cgi_env(argv[2]); + } else if (getenv("REQUEST_METHOD")) { /* case 2: called as a CGI */ + fprintf(stdout, "Content-type: text/html\n\n"); + fflush(stdout); + } else { /* case 3: run from the command line */ + /* when being run from the command line, we require many command line arguments */ + /* we need to do 2 or three things: + 1 - stop the server and remove the server instance directory + 2 - remove the server's information from the config ds + 3 - On Windows, remove the registry information + We require the instance name as an argument. We also need the following: + For 1, we need the server root + For 2, we need the config ds host, port, admin domain, admin dn, admin password + For 3, just the instance name + + There are two other arguments that are optional. -force will ignore errors and just keep + going. On Windows, -allreg will clean up all known registry information for all instances + of DS on this machine + */ + } + + + if ( init_ds_env() ) { + return 1; + } + + /* + * Get the server pathto delete. + * serevrpath = /export/serevrs/dirserv/slapd-talac + */ + if (!(servername = ds_get_cgi_var("InstanceName"))) + servername = ds_get_server_name(); + + /* Check again if the serevr is down or not */ + if((isRunning = ds_get_updown_status()) == DS_SERVER_UP) { + if ((status = ds_bring_down_server()) != DS_SERVER_DOWN) { + char buf[1024]; + sprintf(buf, "Could not stop server: error %d", status); + ds_report_error (DS_GENERAL_FAILURE, servername, buf); + return 1; + } + } + + if (servername) { + char line[1024]; + int busy_retries = 3; /* if busy, retry this many times */ + installroot = ds_get_install_root(); + /* We may get busy errors if files are in use when we try + to remove them, so if that happens, sleep for 30 seconds + and try again */ + status = ds_rm_rf(installroot, rm_rf_err_func, NULL); + while (status && try_rm_rf_again && busy_retries) { + sprintf(line, "Some files or directories in %s are still in use. Will sleep for 30 seconds and try again.", + installroot); + ds_show_message(line); + PR_Sleep(PR_SecondsToInterval(30)); + try_rm_rf_again = 0; + --busy_retries; + status = ds_rm_rf(installroot, rm_rf_err_func, NULL); + } + if (status) { + sprintf(line, "Could not remove %s. Please check log messages and try again.", + installroot); + ds_send_error(line, 0); + } + } +#ifdef XP_WIN32 + if (servername) { + status += ds_remove_reg_key(HKEY_LOCAL_MACHINE, "%s\\%s\\%s\\%s", KEY_SOFTWARE_NETSCAPE, + DS_NAME_SHORT, DS_VERSION, servername); + + /* also try to remove version key in case this is the last instance */ + status += ds_remove_reg_key(HKEY_LOCAL_MACHINE, "%s\\%s\\%s", KEY_SOFTWARE_NETSCAPE, + DS_NAME_SHORT, DS_VERSION); + + /* also try to remove product key in case this is the last instance */ + status += ds_remove_reg_key(HKEY_LOCAL_MACHINE, "%s\\%s", KEY_SOFTWARE_NETSCAPE, + DS_NAME_SHORT); + + /* also need to remove service */ + if (!DeleteServer(servername)) { + status += 1; + } + + /* Remove Event Log Key */ + status += ds_remove_reg_key(HKEY_LOCAL_MACHINE, "%s\\%s\\%s", KEY_SERVICES, KEY_EVENTLOG_APP, servername); + } +#endif + + if (status == 0) { + char buf[1024]; + sprintf(buf, "Server %s was successfully removed", servername); + ds_show_message(buf); + rpt_success(""); + } else { + char buf[1024]; + sprintf(buf, "Could not remove server %s", servername); + ds_send_error(buf, 0); + } + + return status; +} diff --git a/ldap/admin/src/ds_remove_uninst.cpp b/ldap/admin/src/ds_remove_uninst.cpp new file mode 100644 index 00000000..d38de4fa --- /dev/null +++ b/ldap/admin/src/ds_remove_uninst.cpp @@ -0,0 +1,317 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +// ds_remove_uninst.cpp +// +// ds_remove routines that use c++ calls in adminsdk +// +#include <iostream.h> +#include <fstream.h> +#include <stdio.h> /* printf, file I/O */ +#include <string.h> /* strlen */ +#include <ctype.h> +#ifdef XP_UNIX +#include <strings.h> +#include <pwd.h> +#include <grp.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#endif +#include <stdlib.h> /* memset, rand stuff */ +#include <sys/types.h> +#include <errno.h> +#include <stdarg.h> +#include <time.h> + +#include "ds_remove_uninst.h" + +#ifdef __cplusplus +extern "C" { +#endif +#include "dsalib.h" +#ifdef __cplusplus +} + +#include "prprf.h" + +#endif +#ifdef XP_UNIX +#include "ux-util.h" +#endif +#include "ldapu.h" +#include "install_keywords.h" +#include "global.h" +#include "setupapi.h" + +#define MAX_STR_SIZE 512 + +static InstallLog *installLog = NULL; + +static void +dsLogMessage(const char *level, const char *which, + const char *format, ...) +{ + char bigbuf[BIG_BUF*4]; + va_list ap; + va_start(ap, format); + PR_vsnprintf(bigbuf, BIG_BUF*4, format, ap); + va_end(ap); +#ifdef _WIN32 // always output to stdout (for CGIs), and always log + // if a log is available + fprintf(stdout, "%s %s %s\n", level, which, bigbuf); + fflush(stdout); + if (installLog) + installLog->logMessage(level, which, bigbuf); +#else // not Windows + if (installLog) + installLog->logMessage(level, which, bigbuf); + else + fprintf(stdout, "%s %s %s\n", level, which, bigbuf); + fflush(stdout); +#endif + + return; +} + +// replace \ in path with \\ for LDAP search filters +static char * +escapePath(const char *path) +{ + char *s = 0; + if (path) { + s = new char [(strlen(path)+1)*2]; // worst case + char *p = s; + const char *pp = path; + for (; *pp; ++pp, ++p) { + if (*pp == '\\') { + *p++ = *pp; + } + *p = *pp; + } + *p = 0; + } + + return s; +} + +static LdapErrorCode +localRemoveISIE(LdapEntry &isieEntry) +{ + /* stevross: for now explicitly delete ISIE because it's not getting + removed by removeSIE for some reason */ + LdapError err = isieEntry.dropAll(isieEntry.entryDN()); + if (err.errorCode()) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "Error: could not remove ISIE entry %s: error = %d", + (const char *)isieEntry.entryDN(), (int)err.errorCode()); + } + + // OK to remove, recursively go up the tree and remove all + char *dn = new char [strlen(isieEntry.entryDN()) + 10]; + char **explodedDN = ldap_explode_dn(isieEntry.entryDN(), 0); + int i = 0; + + while (1) + { + dn[0] = 0; + char **s = &explodedDN[i]; + while (*s != NULL) + { + strcat(dn, *s); + strcat(dn, LDAP_PATHSEP); + s++; + } + + if (*s == NULL) + { + dn[strlen(dn)-strlen(LDAP_PATHSEP)] = 0; + } + + if (strcasecmp(dn, DEFAULT_ROOT_DN) == 0) + { + break; + } + + err = isieEntry.retrieve(OBJECT_CLASS_FILTER, LDAP_SCOPE_ONELEVEL, dn); + + if (err == NOT_FOUND) + { + isieEntry.drop(dn); + ++i; + } + else + { + break; + } + } + + delete [] dn; + ldap_value_free(explodedDN); + + return OKAY; +} + +////////////////////////////////////////////////////////////////////////////// +// removeInstanceLDAPEntries +// +// +// remove sie, isie of this instance +// +// +// +// + +int removeInstanceLDAPEntries(const char *pszLdapHost, + const char *pszPort, + const char *pszLdapSuffix, + const char *pszUser, + const char *pszPw, + const char *pszInstanceName, + const char *pszInstanceHost, + const char *pszServerRoot) +{ + LDAP *ld = NULL; + char szSearchBase[] = "o=NetscapeRoot"; + + /* open LDAP connection */ + LdapError ldapError = 0; + NSString newURL = NSString("ldap://") + pszLdapHost + ":" + + pszPort + "/" + pszLdapSuffix; + Ldap ldap(ldapError, newURL, pszUser, pszPw, 0, 0); + if (ldapError.errorCode()) + { + return 1; + } + + /* get SIE entry */ + char *sroot = escapePath(pszServerRoot); + LdapEntry sieEntry(&ldap); + NSString sieFilter = NSString("(&(serverhostname=") + pszInstanceHost + + ")(cn=" + pszInstanceName + ")(serverroot=" + + sroot + "))"; + ldapError = sieEntry.retrieve(sieFilter, LDAP_SCOPE_SUBTREE, szSearchBase); + if (ldapError.errorCode()) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "Error: could not find the SIE entry using filter %s: error = %d", + (const char *)sieFilter, (int)ldapError.errorCode()); + delete [] sroot; + return 1; + } + + /* get ISIE entry */ + LdapEntry isieEntry(&ldap); + NSString isieFilter = + NSString("(&(objectclass=nsApplication)(uniquemember=") + + sieEntry.entryDN() + ")(nsinstalledlocation=" + + sroot + "))"; + ldapError = isieEntry.retrieve(isieFilter, LDAP_SCOPE_SUBTREE, szSearchBase); + if (ldapError.errorCode()) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "Error: could not find the ISIE entry using filter %s: error = %d", + (const char *)isieFilter, (int)ldapError.errorCode()); + delete [] sroot; + return 1; + } + + /* delete the SIE and ISIE entry */ + LdapErrorCode code = removeSIE(&ldap, sieEntry.entryDN(), False); + if (code) + { + dsLogMessage(SETUP_LOG_FATAL, "Slapd", + "Error: could not remove SIE entry %s: error = %d", + (const char *)sieEntry.entryDN(), (int)code); + return code; + } + + code = localRemoveISIE(isieEntry); + + delete [] sroot; + return code; +} + + +int ds_uninst_set_cgi_env(char *pszInfoFileName) +{ + InstallInfo *uninstallInfo = NULL; + InstallInfo *instanceInfo = NULL; + static char szQueryString[512] = {0}; + static char szScriptName[512] = {0}; + static char szNetsiteRoot[512] = {0}; + const char *serverID = 0; + const char *tmp; + + uninstallInfo = new InstallInfo(pszInfoFileName); + + if (!uninstallInfo) + return 1; + + instanceInfo = uninstallInfo->getSection("uninstall"); + if (!instanceInfo) + instanceInfo = uninstallInfo; + + putenv("REQUEST_METHOD=GET"); + if (instanceInfo->get(SLAPD_KEY_SERVER_IDENTIFIER)) + serverID = instanceInfo->get(SLAPD_KEY_SERVER_IDENTIFIER); + else if (ds_get_server_name()) + serverID = ds_get_server_name(); + + if (serverID) + sprintf(szQueryString, "QUERY_STRING=InstanceName=%s", + serverID); + + putenv(szQueryString); + + if (instanceInfo->get(SLAPD_KEY_SERVER_ROOT)) + sprintf(szNetsiteRoot, "NETSITE_ROOT=%s", + instanceInfo->get(SLAPD_KEY_SERVER_ROOT)); + putenv(szNetsiteRoot); + + if (serverID) + sprintf(szScriptName, "SCRIPT_NAME=/%s/Tasks/Operation/Remove", + serverID); + putenv(szScriptName); + + // remove SIE entry + const char *host = instanceInfo->get(SLAPD_KEY_K_LDAP_HOST); + char port[20] = {0}; + if (instanceInfo->get(SLAPD_KEY_K_LDAP_PORT)) + strcpy(port, instanceInfo->get(SLAPD_KEY_K_LDAP_PORT)); + const char *suffix = instanceInfo->get(SLAPD_KEY_SUFFIX); + const char *ldapurl = instanceInfo->get(SLAPD_KEY_K_LDAP_URL); + LDAPURLDesc *desc = 0; + if (ldapurl && !ldap_url_parse((char *)ldapurl, &desc) && desc) { + if (!host) + host = desc->lud_host; + if (port[0] == 0) + sprintf(port, "%d", desc->lud_port); + if (!suffix) + suffix = desc->lud_dn; + } + + // get and set the log file + if (tmp = instanceInfo->get(SLAPD_INSTALL_LOG_FILE_NAME)) + { + static char s_logfile[PATH_MAX+32]; + PR_snprintf(s_logfile, PATH_MAX+32, "DEBUG_LOGFILE=%s", tmp); + putenv(s_logfile); + installLog = new InstallLog(tmp); + } + + removeInstanceLDAPEntries(host, port, suffix, + instanceInfo->get(SLAPD_KEY_SERVER_ADMIN_ID), + instanceInfo->get(SLAPD_KEY_SERVER_ADMIN_PWD), + serverID, + instanceInfo->get(SLAPD_KEY_FULL_MACHINE_NAME), + instanceInfo->get(SLAPD_KEY_SERVER_ROOT)); + + if (desc) + ldap_free_urldesc(desc); + return 0; +} diff --git a/ldap/admin/src/ds_remove_uninst.h b/ldap/admin/src/ds_remove_uninst.h new file mode 100644 index 00000000..15c28c59 --- /dev/null +++ b/ldap/admin/src/ds_remove_uninst.h @@ -0,0 +1,23 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* ds_remove_uninst.h */ + + +#ifndef _DS_REMOVE_UNINST_H_ +#define _DS_REMOVE_UNINST_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + +int ds_uninst_set_cgi_env(char *pszInfoFileName); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ldap/admin/src/ds_rmdb.c b/ldap/admin/src/ds_rmdb.c new file mode 100644 index 00000000..08a1bb7c --- /dev/null +++ b/ldap/admin/src/ds_rmdb.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 **/ +/* + * Delete backed-up database files. + * + * Anil Bhavnani + * Removed all HTML output for DS 4.0: Rob Weltman + */ + +#include <stdio.h> +#include <stdlib.h> +#include "libadminutil/admutil.h" +#include "dsalib.h" +#include "portable.h" +#include "init_ds_env.h" +#include <string.h> +#ifdef XP_UNIX +#include <unistd.h> +#endif + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +int main(int argc, char *argv[], char *envp[]) +{ + char *del_file = NULL; + char **bak_files; + int file_count = 0; + int err = 0; + + fprintf(stdout, "Content-type: text/html\n\n"); + + if ( init_ds_env() ) + return 1; + + ds_become_localuser (ds_get_config (DS_REAL_CONFIG)); + + /* + * Get value of the "deletefile" variable. + */ + del_file = ds_get_cgi_var("deletefile"); + if ( (NULL == del_file) || (strlen(del_file) < 1) ) { + rpt_err( DS_UNDEFINED_VARIABLE, "deletefile", NULL, NULL ); + return 1; + } + + bak_files = ds_get_file_list( del_file ); + if ( bak_files == NULL ) { + rpt_err( DS_NO_SUCH_FILE, del_file, NULL, NULL ); + return 1; + } else { + int j; + char buf[ MAXPATHLEN ]; + for ( j = 0; bak_files[ j ] != NULL; j++ ) { + sprintf( buf, "%s/%s", del_file, bak_files[ j ]); + if ( unlink(buf) != 0 ) { + rpt_err( DS_CANNOT_DELETE_FILE, buf, NULL, NULL ); + return 1; + } + } + if ( rmdir( del_file ) < 0 ) { + rpt_err( DS_CANNOT_DELETE_FILE, del_file, NULL, NULL ); + return 1; + } + } + rpt_success("Success! Deleted directory."); + + return 0; +} diff --git a/ldap/admin/src/ds_snmpctrl.c b/ldap/admin/src/ds_snmpctrl.c new file mode 100644 index 00000000..e2a40b6d --- /dev/null +++ b/ldap/admin/src/ds_snmpctrl.c @@ -0,0 +1,308 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * snmpctrl.c - start/stop/restart LDAP-based SNMP subagent + * + * Steve Ross -- 08/12/97 + * + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "libadminutil/admutil.h" +#include "dsalib.h" +#include "init_ds_env.h" + +#if !defined(_WIN32) +#include <signal.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <unistd.h> +#include <stdlib.h> +#else +#include <windows.h> +#endif + +#define SUBAGT_PATH "bin/slapd/server" +#define SUBAGT_NAME "ns-ldapagt" + +#define START 1 +#define STOP 2 +#define RESTART 3 + +#define NSLDAPAGT_PID "NSLDAPAGT.LK" + +#ifdef __cplusplus +extern "C" { +#endif +int nsldapagt_is_running(void); +int nsldapagt_shutdown(void); +int nsldapagt_start(void); +int nsldapagt_restart(void); +#ifdef __cplusplus +} +#endif + +int main(int argc, char *argv[]) +{ + char *action_type = NULL; + int haderror=0; + int status = 1; + + fprintf(stdout, "Content-type: text/html\n\n"); + + if ( init_ds_env() ) + return 1; + + action_type = ds_a_get_cgi_var("ACTION", "Missing Command", + "Need to specify Start, Stop, or Restart"); + if (!action_type) + return 1; + + if (!strcmp(action_type, "START")) { + status = nsldapagt_start(); + } else if (!strcmp(action_type, "STOP")) { + status = nsldapagt_shutdown(); + } else if (!strcmp(action_type, "RESTART")) { + status = nsldapagt_restart(); + } else { + status = DS_UNKNOWN_SNMP_COMMAND; + } + + if ( !status ) { + rpt_success("Success!"); + return 0; + } else { + rpt_err( status, action_type, NULL, NULL ); + return 1; + } +} + +#if !defined(_WIN32) +int +get_nsldapagt_pid(pid_t *pid) +{ + char *SLAPD_ROOT; + char path[PATH_MAX]; + FILE *fp; + + *pid = -1; + + SLAPD_ROOT = ds_get_install_root(); + sprintf(path, "%s/logs/%s", SLAPD_ROOT, NSLDAPAGT_PID); + if (!ds_file_exists(path)) { + return(-1); + } + + if ((fp = fopen(path, "r")) != (FILE *) NULL) { + if ((fscanf(fp, "%d\n", (int *) pid)) != -1) { + (void) fclose(fp); + return(0); + } + } + + (void) fclose(fp); + return(-1); +} +#endif + +#if defined(_WIN32) +BOOL isServiceRunning(LPCTSTR szServiceId) +{ + BOOL bReturn = FALSE; + DWORD dwError = 0; + SC_HANDLE schService = NULL; + SC_HANDLE schSCManager = NULL; + SERVICE_STATUS lpss; + + if((schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) + { + if((schService = OpenService(schSCManager, + szServiceId, + SERVICE_ALL_ACCESS))) + { + + bReturn = ControlService(schService, SERVICE_CONTROL_INTERROGATE , &lpss); + + if(SERVICE_RUNNING == lpss.dwCurrentState) + { + bReturn = TRUE; + } + + CloseServiceHandle(schService); + } + dwError = GetLastError(); + CloseServiceHandle(schSCManager); + } + return(bReturn); +} +#endif + +/* + * This routine returns: + * 0 if nsldapagt is NOT running + * 1 if nsldapagt is actually running + */ +int +nsldapagt_is_running() +{ + +#if defined(_WIN32) + if (FALSE == isServiceRunning("SNMP") ) + { + return(0); + } +#else + pid_t pid; + + if (get_nsldapagt_pid(&pid) != 0) { + return(0); + } + + if (kill(pid, 0) == -1) { + return(0); + } +#endif + return(1); +} + +#if !defined(_WIN32) +/* + * This routine returns: + * 0 if magt is NOT running + * 1 if magt is actually running + * + * The run state is determined whether one can successfully bind to the + * smux port. + * + * this is for UNIX only + */ +int +smux_master_is_running() +{ + struct servent *pse; + struct protoent *ppe; + struct sockaddr_in sin; + int s; + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + + if (pse = getservbyname("smux", "tcp")) { + sin.sin_port = ntohs(pse->s_port); + } else { + sin.sin_port = 199; + } + + if ((ppe = getprotobyname("tcp")) == 0) { + return(0); + } + + if ((s = socket(AF_INET, SOCK_STREAM, ppe->p_proto)) < 0) { + return(0); + } + + /* bind expects port number to be in network order + we should do this for all platforms, not just OSF. */ + sin.sin_port = htons(sin.sin_port); + if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + close(s); + return(1); + } else { + } + + close(s); + return(0); +} +#endif + +int +nsldapagt_start() +{ + if (nsldapagt_is_running()) { + return(0); + } + +#if defined(_WIN32) +/* NT version -- just try to start the SNMP service */ +/* Bug 612322: redirecting the output to null device */ + system("net start SNMP > nul"); + +#else + + /* + * Check if smux master agent is running before firing off the subagent! + */ + if (!smux_master_is_running()) { + return(-1); + } else { + char *NETSITE_ROOT = getenv("NETSITE_ROOT"); + char *SLAPD_ROOT = ds_get_install_root(); + char command[1024]; + + sprintf(command, "cd %s/%s; ./%s -d %s", NETSITE_ROOT, SUBAGT_PATH, + SUBAGT_NAME, SLAPD_ROOT); + + (void) system(command); + sleep(2); + } +#endif + + if (!nsldapagt_is_running()) { + return(-1); + } + + return(0); +} + +int +nsldapagt_shutdown() +{ + if (!nsldapagt_is_running()) { + rpt_success("NOT_RUNNING"); + exit(0); + + } else { + int status = -1; + +#if defined(_WIN32) + /* NT version -- just try to stop the SNMP service */ + /* Bug 612322: redirecting the output to null device */ + status = system("net stop SNMP > nul"); + +#else + /* UNIX version */ + pid_t pid; + if (get_nsldapagt_pid(&pid) == 0) + { + if (kill(pid, SIGTERM) == 0) + { + sleep(2); + if (!nsldapagt_is_running()) + { + status = 0; + } + } + } +#endif + return(status); + } + return(0); +} + + +int +nsldapagt_restart() +{ + int status; + if ( (status = nsldapagt_shutdown()) != 0 ) + return status; + else + return nsldapagt_start(); +} + diff --git a/ldap/admin/src/ds_viewlog.pl b/ldap/admin/src/ds_viewlog.pl new file mode 100644 index 00000000..d5f171ef --- /dev/null +++ b/ldap/admin/src/ds_viewlog.pl @@ -0,0 +1,129 @@ +#!perl +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# view the last N lines of the given file + +BEGIN { + # make stdout unbuffered for friendly CGI output + $| = 1; + # print CGI header + print "Content-type: text/plain\n\n"; + # add the current directory to the beginning of the module + # search path (for our CGI.pm) + unshift @INC, '.'; + +} + +my $dbfh; # debugging file handler +sub debug { + # comment out the return line to enable debugging + return; + + if (!$dbfh) { + $dbfh = 'mylog.txt'; + open $dbfh, ">$dbfh" or die "Error: could not write $dbfh: $!"; + } + print $dbfh "@_\n"; +} + +sub sigDieHandler { + &debug(@_, "\n"); + print @_, "\n"; + &debug("NMC_STATUS: ", $!+0, "\n"); + print "NMC_STATUS: ", $!+0, "\n"; + exit $!; +} + +sub rpt_err { + my ($code, $value) = @_; + $! = $code; + die "Error: value $value is invalid: code $code"; +} + +$SIG{__DIE__} = 'sigDieHandler'; +my $DEF_SIZE = 25; + +# constants from dsalib.h +my $DS_UNKNOWN_ERROR = -1; +my $DS_NO_SERVER_ROOT = -10; +my $DS_CANNOT_EXEC = -11; +my $DS_CANNOT_OPEN_STAT_FILE = -12; +my $DS_NULL_PARAMETER = -13; +my $DS_SERVER_MUST_BE_DOWN = -14; +my $DS_CANNOT_OPEN_BACKUP_FILE = -15; +my $DS_NOT_A_DIRECTORY = -16; +my $DS_CANNOT_CREATE_DIRECTORY = -17; +my $DS_CANNOT_OPEN_LDIF_FILE = -18; +my $DS_IS_A_DIRECTORY = -19; +my $DS_CANNOT_CREATE_FILE = -20; +my $DS_UNDEFINED_VARIABLE = -21; +my $DS_NO_SUCH_FILE = -22; +my $DS_CANNOT_DELETE_FILE = -23; +my $DS_UNKNOWN_SNMP_COMMAND = -24; +my $DS_NON_NUMERIC_VALUE = -25; +my $DS_NO_LOGFILE_NAME = -26; +my $DS_CANNOT_OPEN_LOG_FILE = -27; +my $DS_HAS_TOBE_READONLY_MODE = -28; +my $DS_INVALID_LDIF_FILE = -29; + +# process the CGI input +use Cgi; + +my $num = $cgiVars{num}; +my $str = $cgiVars{str}; +my $logfile = $cgiVars{logfile}; + +&debug("ENV:"); +foreach $item (keys %ENV) { + &debug("ENV $item = $ENV{$item}"); +} +&debug("query string = ", $Cgi::QUERY_STRING); +&debug("content = ", $CONTENT); +&debug("cgiVars = ", %cgiVars); +&debug("num = $num str = $str logfile = $logfile"); + +if (! $num) { + $num = $DEF_SIZE; +} + +if (! ($num =~ /\d+/)) { + &rpt_err( $DS_NON_NUMERIC_VALUE, $num ); + return 1; +} + +if (! $logfile) { + &rpt_err( $DS_NO_LOGFILE_NAME, "no logfile"); +} + +if (! -f $logfile) { + &rpt_err( $DS_CANNOT_OPEN_LOG_FILE, $logfile); +} + +open(INP, $logfile) or &rpt_err( $DS_CANNOT_OPEN_LOG_FILE, $logfile); + +my $ii = 0; +my @buf = (); +while (<INP>) { + &debug("raw: $_"); + if (!$str || /$str/i) { + $ii++; + $buf[$ii%$num] = $_; + } +} +close INP; + +my @tail = (@buf[ ($ii%$num + 1) .. $#buf ], + @buf[ 0 .. $ii%$num ]); +&debug("tail size = ", scalar(@tail), " first line = $tail[0]"); +for (@tail) { + print if $_; # @tail may begin or end with undef + &debug($_) if $_; +} + +die "Finished"; diff --git a/ldap/admin/src/getConfigInfo b/ldap/admin/src/getConfigInfo new file mode 100644 index 00000000..5ba1d20d --- /dev/null +++ b/ldap/admin/src/getConfigInfo @@ -0,0 +1,134 @@ +#!perl +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# Get some configuration information from an instance + +BEGIN { + $| = 1; + # print CGI header + print "Content-type: text/plain\n\n"; + + $isNT = -d '\\'; + $PATHSEP = $isNT ? "\\" : "/"; + # get the server root directory + $sroot = $ENV{'NETSITE_ROOT'}; + @INC = ( '.', '../../../admin/admin/bin' ); + grep { s@/@\\@g } @INC if $isNT; +} + +sub sigDieHandler { + print @_, "\n"; + print "NMC_STATUS: ", $!+0, "\n"; + exit $!; +} + +$SIG{__DIE__} = 'sigDieHandler'; + +# process the CGI input +use Cgi; + +$oldSlapdConf = $cgiVars{'oldServerRoot'} . $PATHSEP . 'slapd-' . + $cgiVars{'oldServerName'} . $PATHSEP . 'config' . $PATHSEP . + 'slapd.conf'; + +$foundLocalUser = 0; + +open(OLDSLAPDCONF, $oldSlapdConf) or + die "Error: could not open old config file $oldSlapdConf: $!"; +while ($line = <OLDSLAPDCONF>) { + chop $line; + foreach $key (keys %cgiVars) { + $param = $cgiVars{$key}; + if ($line =~ /^$param\s+/i) { + ($value = $') =~ s/^[\"]//; + # remove leading " + $value =~ s/[\"]$//; + # remove trailing " + print $key, ':', $value, "\n"; + if (lc($param) eq 'localuser') { + $foundLocalUser = 1; + } + } + } + if ($line =~ /^directory\s+/i) { $dbdir = $';} + # the user may have given us a network mounted old home directory, but in the + # old instance's config files, the root directory referred to is usually + # a local directory. For example, suppose there is an automounter map for + # hosts which maps onto /h e.g. /h/oldhost would contain all directories + # exported via NFS. Similarly, for NT, you could do \\oldhost\c to look + # at the C: drive on the old host. Or the user may have network mounted + # the old server root some other way. Anyway, we need to determine what + # the old server root was local to the original host because that is what + # will be referred to it the old config files. So, we look at the errorlog + # directive in slapd.conf and use whatever comes before the slapd-oldname + elsif ($line =~ /\werrorlog\s+(.*)slapd-$cgiVars{'oldServerName'}/i) { + $realOldDir = $1; + } + elsif ($line =~ /^security\s+/i) { + if (lc($') eq 'on') { + $security = 1; + } + } + elsif ($line =~ /^encryption-alias\s+/i) { + $encryptionalias = $'; + } +} +close(OLDSLAPDCONF); + +if (! $realOldDir) { + $realOldDir = $cgiVars{'oldServerRoot'}; +} + +# if security is enabled, see if there is a cert and key db +if ($security && $encryptionalias) { + $secDir = $cgiVars{'oldServerRoot'} . $PATHSEP . 'alias'; + opendir(SECDIR, $secDir) or + die "Error: could not open alias dir $secDir : $!"; + foreach (readdir(SECDIR)) { + if (! /[.][.]?/) { + if (/^$encryptionalias/i) { + print 'needSecPwd:true', "\n"; + last; + } + } + } + closedir(SECDIR); +} + +# the dbdir is stored as a local dir, but we may need a network dir +($networkDbDir = $dbdir) =~ s/^$realOldDir/$cgiVars{'oldServerRoot'}/ig; + +if (! $isNT && $cgiVars{'oldlocaluser'} && ! $foundLocalUser) { + # get the local user by doing a stat of the db directory + $olduid = (stat($networkDbDir))[4]; + # convert the numeric uid to string name + setpwent; + while (@ent = getpwent) { + if ($ent[2] == $olduid) { + print 'oldlocaluser:', $ent[0], "\n"; + last; + } + } + endpwent; +} + +if (! $isNT && $cgiVars{'newlocaluser'}) { + open(SSUSERS, "$sroot${PATHSEP}shared${PATHSEP}config${PATHSEP}ssusers.conf") or + die "Error: could not open $sroot${PATHSEP}shared${PATHSEP}config${PATHSEP}ssusers.conf: $!"; + while (<SSUSERS>) { + chop; + if (/^SuiteSpotUser\s+/i) { + print 'newlocaluser:', $', "\n"; + } + } + close(SSUSERS); +} + +print "NMC_STATUS: 0\n"; +exit 0; diff --git a/ldap/admin/src/import2info b/ldap/admin/src/import2info new file mode 100755 index 00000000..5429d71d --- /dev/null +++ b/ldap/admin/src/import2info @@ -0,0 +1,58 @@ +#!perl +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# Get information to import a 1.x Directory server's info + +BEGIN { @INC = ( '../../../admin/admin/bin' , '.' ); } + +$| = 1; +use Cgi; + +$isNT = -d '\\'; +$cgiVars{'server'} =~ /-/; +$root = $ENV{'NETSITE_ROOT'}; +$oldDir = $cgiVars{'dir'}; +$oldDir =~ s/\\/\//g; +$oldHome = "$oldDir/$cgiVars{'server'}"; +$snmpfile = "$oldHome/config/snmp.conf"; + +$ds30 = 0; +if ( -e $snmpfile) { + open ( SRC, $snmpfile) | "Can't open $snmpfile: $!\n"; + while ( <SRC> ) { + if ($_=~/^Version/ ) { + $where = index ($_, "3.0"); + if ($where > -1 ) { + $ds30 =1; + } + } + } +} + +# QUERY_STRING still set from invocation + +print "Content-type: text/html\n\n"; +if ($ds30) { + print "<HTML><HEAD><TITLE>Import 3.0 Directory Server Info</TITLE></HEAD>\n"; + print "<BODY>\n"; + print "<H1><center>The server you are attempting to migrate is a 3.0 directory server. There is no need to migrate a 3.0 server to 3.1 server.</center></H1>\n"; + print "</BODY></HTML>\n"; +} else { + print "<HTML><HEAD><TITLE>Import 1.x Directory Server Info</TITLE></HEAD>\n"; + print "<BODY>\n"; + print "<H1>Import 1.x Directory Server Info</H1>\n"; + print '<FORM action="import" method="GET">', "\n"; + print "<INPUT type=hidden name=\"dir\" value=\"$cgiVars{'dir'}\">\n"; + print "<INPUT type=hidden name=\"server\" value=\"$cgiVars{'server'}\">\n"; + $cgiVars{'server'} =~ /-/; + print "Name: $`-<INPUT type=text name=\"name\" value=\"$'\"><P>\n"; + print "<P><INPUT type=submit value=\"Import\">\n"; + print "</FORM>\n</BODY></HTML>\n"; +} + diff --git a/ldap/admin/src/init_ds_env.c b/ldap/admin/src/init_ds_env.c new file mode 100644 index 00000000..554f1cec --- /dev/null +++ b/ldap/admin/src/init_ds_env.c @@ -0,0 +1,57 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * Set up environment for CGIs. + * + * Rob Weltman + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "libadminutil/admutil.h" +#include "libadminutil/distadm.h" +#include "init_ds_env.h" +#include "dsalib.h" + +int init_ds_env() +{ + char *m = getenv("REQUEST_METHOD"); + char *qs = NULL; + int proceed = 0; + int _ai = ADMUTIL_Init(); + + if ( m != NULL ) { + if( !strcmp(m, "GET") ) { + qs = GET_QUERY_STRING(); + if ( qs && *qs ) { + ds_get_begin(qs); + } + proceed = 1; + } else if(!strcmp(m, "POST")) { + if (ds_post_begin(stdin)) { + proceed = 0; + } else { + proceed = 1; + } + } + } + + if(!proceed) { + char msg[2000]; + sprintf(msg, "ErrorString: REQUEST_METHOD=%s," + "QUERY_STRING=%s\n", + (m == NULL) ? "<undefined>" : m, + (qs == NULL) ? "<undefined>" : qs); + rpt_err( GENERAL_FAILURE, + msg, + "", + "" ); + return 1; + } + + return 0; +} diff --git a/ldap/admin/src/init_ds_env.h b/ldap/admin/src/init_ds_env.h new file mode 100644 index 00000000..99dba832 --- /dev/null +++ b/ldap/admin/src/init_ds_env.h @@ -0,0 +1,11 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * Set up environment for CGIs. + * + * Rob Weltman + */ +extern int init_ds_env(); diff --git a/ldap/admin/src/install_keywords.h b/ldap/admin/src/install_keywords.h new file mode 100644 index 00000000..b855db30 --- /dev/null +++ b/ldap/admin/src/install_keywords.h @@ -0,0 +1,111 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/********************************************************************* +** +** +** NAME: +** install_keywords.h +** +** DESCRIPTION: +** Miscellaneous stuffs used by ux-update or ux-config +** +** NOTES: +** +** +*/ + +#ifndef _INSTALL_KEYWORDS_H_ +#define _INSTALL_KEYWORDS_H_ + +#include "global.h" + + +#ifdef XP_UNIX +#define SLAPD_KEY_FULL_MACHINE_NAME MACHINE_NAME +#else +#define SLAPD_KEY_FULL_MACHINE_NAME "FullMachineName" +#endif +#define SLAPD_KEY_SERVER_ROOT "ServerRoot" +#define SLAPD_KEY_SERVER_PORT "ServerPort" +#define SLAPD_KEY_SECURITY_ON "SecurityOn" +#define SLAPD_KEY_SECURE_SERVER_PORT "SecureServerPort" +#define SLAPD_KEY_SLAPD_CONFIG_FOR_MC "SlapdConfigForMC" + +#ifdef XP_UNIX +#define SLAPD_KEY_SERVER_ADMIN_ID MC_ADMIN_ID +#define SLAPD_KEY_SERVER_ADMIN_PWD MC_ADMIN_PWD +#else +#define SLAPD_KEY_SERVER_ADMIN_ID "ConfigDirectoryAdminID" +#define SLAPD_KEY_SERVER_ADMIN_PWD "ConfigDirectoryAdminPwd" +#endif + +#define SLAPD_KEY_SERVER_IDENTIFIER "ServerIdentifier" +#define SLAPD_KEY_SUITESPOT_USERID SS_USER_ID +#define SLAPD_KEY_SUFFIX "Suffix" +#define SLAPD_KEY_ROOTDN "RootDN" +#define SLAPD_KEY_ROOTDNPWD "RootDNPwd" +#define SLAPD_KEY_ADMIN_SERVER_PORT "Port" +#define SLAPD_KEY_OLD_SERVER_ROOT "OldServerRoot" + +#ifdef XP_UNIX +#define SLAPD_KEY_K_LDAP_URL CONFIG_LDAP_URL +#else +#define SLAPD_KEY_K_LDAP_URL "ConfigDirectoryLdapURL" +#endif + +#define SLAPD_KEY_K_LDAP_HOST CONFIG_DS_HOST +#define SLAPD_KEY_K_LDAP_PORT CONFIG_DS_PORT +#define SLAPD_KEY_BASE_SUFFIX CONFIG_DS_SUFFIX +#define SLAPD_KEY_ADMIN_SERVER_ID "ServerAdminID" +#define SLAPD_KEY_ADMIN_SERVER_PWD "ServerAdminPwd" +#define SLAPD_KEY_ADD_SAMPLE_ENTRIES "AddSampleEntries" +#define SLAPD_KEY_ADD_ORG_ENTRIES "AddOrgEntries" +#define SLAPD_KEY_INSTALL_LDIF_FILE "InstallLdifFile" +#define SLAPD_KEY_ORG_SIZE "OrgSize" +#define SLAPD_KEY_SETUP_CONSUMER "SetupConsumer" +#define SLAPD_KEY_CIR_HOST "CIRHost" +#define SLAPD_KEY_CIR_PORT "CIRPort" +#define SLAPD_KEY_CIR_SUFFIX "CIRSuffix" +#define SLAPD_KEY_CIR_BINDDN "CIRBindDN" +#define SLAPD_KEY_CIR_BINDDNPWD "CIRBindDNPwd" +#define SLAPD_KEY_CIR_SECURITY_ON "CIRSecurityOn" +#define SLAPD_KEY_CIR_INTERVAL "CIRInterval" +#define SLAPD_KEY_CIR_DAYS "CIRDays" +#define SLAPD_KEY_CIR_TIMES "CIRTimes" +#define SLAPD_KEY_SETUP_SUPPLIER "SetupSupplier" +#define SLAPD_KEY_REPLICATIONDN "ReplicationDN" +#define SLAPD_KEY_REPLICATIONPWD "ReplicationPwd" +#define SLAPD_KEY_CHANGELOGDIR "ChangeLogDir" +#define SLAPD_KEY_CHANGELOGSUFFIX "ChangeLogSuffix" +#define SLAPD_KEY_USE_REPLICATION "UseReplication" +#define SLAPD_KEY_CONSUMERDN "ConsumerDN" +#define SLAPD_KEY_CONSUMERPWD "ConsumerPwd" +#define SLAPD_KEY_SIR_HOST "SIRHost" +#define SLAPD_KEY_SIR_PORT "SIRPort" +#define SLAPD_KEY_SIR_SUFFIX "SIRSuffix" +#define SLAPD_KEY_SIR_BINDDN "SIRBindDN" +#define SLAPD_KEY_SIR_BINDDNPWD "SIRBindDNPwd" +#define SLAPD_KEY_SIR_SECURITY_ON "SIRSecurityOn" +#define SLAPD_KEY_SIR_DAYS "SIRDays" +#define SLAPD_KEY_SIR_TIMES "SIRTimes" +#define SLAPD_KEY_USE_EXISTING_MC "UseExistingMC" +#define SLAPD_KEY_ADMIN_DOMAIN "AdminDomain" +#define SLAPD_KEY_DISABLE_SCHEMA_CHECKING "DisableSchemaChecking" +#define SLAPD_KEY_USE_EXISTING_UG "UseExistingUG" +#define SLAPD_KEY_USER_GROUP_LDAP_URL "UserDirectoryLdapURL" +#define SLAPD_KEY_UG_HOST "UGHost" +#define SLAPD_KEY_UG_PORT "UGPort" +#define SLAPD_KEY_UG_SUFFIX "UGSuffix" +#define SLAPD_KEY_USER_GROUP_ADMIN_ID "UserDirectoryAdminID" +#define SLAPD_KEY_USER_GROUP_ADMIN_PWD "UserDirectoryAdminPwd" +#define SLAPD_KEY_CONFIG_ADMIN_DN "ConfigAdminDN" +/* This is used to pass the name of the log file used in the main setup + program to the ds_create or ds_remove (for uninstall) so that + they can all use the same log file +*/ +#define SLAPD_INSTALL_LOG_FILE_NAME "LogFileName" + +#endif // _INSTALL_KEYWORDS_H_ diff --git a/ldap/admin/src/instindex.cpp b/ldap/admin/src/instindex.cpp new file mode 100644 index 00000000..ecde4fad --- /dev/null +++ b/ldap/admin/src/instindex.cpp @@ -0,0 +1,423 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * index.c: Shows the first page you see on install + * + * Rob McCool + */ + +#include <nss.h> +#include <libadminutil/distadm.h> + +#include "create_instance.h" +#include "configure_instance.h" + +#include "dsalib.h" +#include "ldap.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef XP_WIN32 +#include "regparms.h" +#endif + +char *ds_salted_sha1_pw_enc(char* pwd); + + + +/* ----------- Create a new server from configuration variables ----------- */ + + +static int create_config(server_config_s *cf) +{ + char *t = NULL; + char error_param[BIG_LINE] = {0}; + + t = create_server(cf, error_param); + if(t) + { + char *msg; + if (error_param[0]) + { + msg = PR_smprintf("%s.error:could not create server %s - %s", + error_param, cf->servid, t); + } + else + { + msg = PR_smprintf("error:could not create server %s - %s", + cf->servid, t); + } + ds_show_message(msg); + PR_smprintf_free(msg); + } + else if (!t) + { + ds_show_message("Created new Directory Server"); + return 0; + } + + return 1; +} + + +/* ------ check passwords are same and satisfy minimum length policy------- */ +static int check_passwords(char *pw1, char *pw2) +{ + if (strcmp (pw1, pw2) != 0) { + ds_report_error (INCORRECT_USAGE, " different passwords", + "Enter the password again." + " The two passwords you entered are different."); + return 1; + } + + if ( ((int) strlen(pw1)) < 8 ) { + ds_report_error (INCORRECT_USAGE, " password too short", + "The password must be at least 8 characters long."); + return 1; + } + + return 0; +} + +/* ------ Parse the results of a form and create a server from them ------- */ + + +static int parse_form(server_config_s *cf) +{ + char *sroot=NULL, *servname=NULL; + char *rm = getenv("REQUEST_METHOD"); + char *qs = getenv("QUERY_STRING"); + char* cfg_sspt_uid_pw1; + char* cfg_sspt_uid_pw2; + int len = 0; + LDAPURLDesc *desc = 0; + char *temp = 0; + + cf->sroot = getenv("NETSITE_ROOT"); + + if (rm && qs && !strcmp(rm, "GET")) + { + ds_get_begin(qs); + } + else if (ds_post_begin(stdin)) + { + return 1; + } + + if (rm) + { + printf("Content-type: text/plain\n\n"); + } + /* else we are being called from server installation; no output */ + + if (!(cf->servname = ds_a_get_cgi_var("servname", "Server Name", + "Please give a hostname for your server."))) + { + return 1; + } + + cf->bindaddr = ds_a_get_cgi_var("bindaddr", NULL, NULL); + if (!(cf->servport = ds_a_get_cgi_var("servport", "Server Port", + "Please specify the TCP port number for this server."))) + { + return 1; + } + /* the suitespot 3x uid is the uid to use for setting up */ + /* a 4.x server to serve as a suitespot 3.x host */ + cf->suitespot3x_uid = ds_a_get_cgi_var("suitespot3x_uid", NULL, NULL); + cf->cfg_sspt = ds_a_get_cgi_var("cfg_sspt", NULL, NULL); + cf->cfg_sspt_uid = ds_a_get_cgi_var("cfg_sspt_uid", NULL, NULL); + if (cf->cfg_sspt_uid && *(cf->cfg_sspt_uid) && + !(cf->cfg_sspt_uidpw = ds_a_get_cgi_var("cfg_sspt_uid_pw", NULL, NULL))) + { + + if (!(cfg_sspt_uid_pw1 = ds_a_get_cgi_var("cfg_sspt_uid_pw1", "Password", + "Enter the password for the Mission Control Administrator's account."))) + { + return 1; + } + + if (!(cfg_sspt_uid_pw2 = ds_a_get_cgi_var("cfg_sspt_uid_pw2", "Password", + "Enter the password for the Mission Control Administrator account, " + "twice."))) + { + return 1; + } + + if (strcmp (cfg_sspt_uid_pw1, cfg_sspt_uid_pw2) != 0) + { + ds_report_error (INCORRECT_USAGE, " different passwords", + "Enter the Mission Control Administrator account password again." + " The two Mission Control Administrator account passwords " + "you entered are different."); + return 1; + } + if ( ((int) strlen(cfg_sspt_uid_pw1)) < 1 ) { + ds_report_error (INCORRECT_USAGE, " password too short", + "The password must be at least 1 character long."); + return 1; + } + cf->cfg_sspt_uidpw = cfg_sspt_uid_pw1; + } + + if (cf->cfg_sspt && *cf->cfg_sspt && !strcmp(cf->cfg_sspt, "1") && + !cf->cfg_sspt_uid) + { + ds_report_error (INCORRECT_USAGE, + " Userid not specified", + "A Userid for Mission Control Administrator must be specified."); + return 1; + } + cf->start_server = ds_a_get_cgi_var("start_server", NULL, NULL); + cf->secserv = ds_a_get_cgi_var("secserv", NULL, NULL); + if (cf->secserv && strcmp(cf->secserv, "off")) + cf->secservport = ds_a_get_cgi_var("secservport", NULL, NULL); + if (!(cf->servid = ds_a_get_cgi_var("servid", "Server Identifier", + "Please give your server a short identifier."))) + { + return 1; + } + +#ifdef XP_UNIX + cf->servuser = ds_a_get_cgi_var("servuser", NULL, NULL); +#endif + + /*cf->suffix = ds_a_get_cgi_var("suffix", "Subtree to store in this database",*/ + /*"Please specify the Subtree to store in this database");*/ + cf->suffix = NULL; + cf->suffix = dn_normalize_convert(ds_a_get_cgi_var("suffix", NULL, NULL)); + + if (cf->suffix == NULL) { + cf->suffix = ""; + } + + cf->rootdn = dn_normalize_convert(ds_a_get_cgi_var("rootdn", NULL, NULL)); + if (cf->rootdn && *(cf->rootdn)) { + if (!(cf->rootpw = ds_a_get_cgi_var("rootpw", NULL, NULL))) + { + char* pw1 = ds_a_get_cgi_var("rootpw1", "Password", + "Enter the password for the unrestricted user."); + char* pw2 = ds_a_get_cgi_var("rootpw2", "Password", + "Enter the password for the unrestricted user, twice."); + + if (!pw1 || !pw2 || check_passwords(pw1, pw2)) + { + return 1; + } + + cf->rootpw = pw1; + } + /* Encode the password in SSHA by default */ + cf->roothashedpw = (char *)ds_salted_sha1_pw_enc (cf->rootpw); + } + + cf->replicationdn = dn_normalize_convert(ds_a_get_cgi_var("replicationdn", NULL, NULL)); + if(cf->replicationdn && *(cf->replicationdn)) + { + if (!(cf->replicationpw = ds_a_get_cgi_var("replicationpw", NULL, NULL))) + { + char *replicationpw1 = ds_a_get_cgi_var("replicationpw1", "Password", + "Enter the password for the replication dn."); + char *replicationpw2 = ds_a_get_cgi_var("replicationpw2", "Password", + "Enter the password for the replication dn, twice."); + + if (!replicationpw1 || !replicationpw2 || check_passwords(replicationpw1, replicationpw2)) + { + return 1; + } + + cf->replicationpw = replicationpw1; + } + /* Encode the password in SSHA by default */ + cf->replicationhashedpw = (char *)ds_salted_sha1_pw_enc (cf->replicationpw); + } + + cf->consumerdn = dn_normalize_convert(ds_a_get_cgi_var("consumerdn", NULL, NULL)); + if(cf->consumerdn && *(cf->consumerdn)) + { + if (!(cf->consumerpw = ds_a_get_cgi_var("consumerpw", NULL, NULL))) + { + char *consumerpw1 = ds_a_get_cgi_var("consumerpw1", "Password", + "Enter the password for the consumer dn."); + char *consumerpw2 = ds_a_get_cgi_var("consumerpw2", "Password", + "Enter the password for the consumer dn, twice."); + + if (!consumerpw1 || !consumerpw2 || check_passwords(consumerpw1, consumerpw2)) + { + return 1; + } + + cf->consumerpw = consumerpw1; + } + /* Encode the password in SSHA by default */ + cf->consumerhashedpw = (char *)ds_salted_sha1_pw_enc (cf->consumerpw); + } + + cf->changelogdir = ds_a_get_cgi_var("changelogdir", NULL, NULL); + cf->changelogsuffix = dn_normalize_convert(ds_a_get_cgi_var("changelogsuffix", NULL, NULL)); + + cf->admin_domain = ds_a_get_cgi_var("admin_domain", NULL, NULL); + cf->use_existing_config_ds = 1; /* there must already be one */ + cf->use_existing_user_ds = 0; /* we are creating it */ + + temp = ds_a_get_cgi_var("ldap_url", NULL, NULL); + if (temp && !ldap_url_parse(temp, &desc) && desc) + { + char *suffix = dn_normalize_convert(strdup(cf->netscaperoot)); + /* the config ds connection may require SSL */ + int isSSL = !strncmp(temp, "ldaps:", strlen("ldaps:")); + len = strlen("ldap://") + 1 + strlen(desc->lud_host) + strlen(":") + + 6 + strlen("/") + strlen(suffix); + cf->config_ldap_url = (char *)calloc(len+1, 1); + sprintf(cf->config_ldap_url, "ldap%s://%s:%d/%s", + (isSSL ? "s" : ""), desc->lud_host, desc->lud_port, suffix); + ldap_free_urldesc(desc); + } + + /* if being called as a CGI, the user_ldap_url will be the directory + we're creating */ + len = strlen("ldap://") + strlen(cf->servname) + strlen(":") + + strlen(cf->servport) + strlen("/") + strlen(cf->suffix); + cf->user_ldap_url = (char *)calloc(len+1, 1); + /* this is the directory we're creating, and we cannot create an ssl + directory, so we don't have to worry about ldap vs ldaps here */ + + sprintf(cf->user_ldap_url, "ldap://%s:%s/%s", cf->servname, + cf->servport, cf->suffix); + + cf->samplesuffix = NULL; + + cf->disable_schema_checking = ds_a_get_cgi_var("disable_schema_checking", + NULL, NULL); + return 0; +} + + +/* --------------------------------- main --------------------------------- */ + +static void +printInfo(int argc, char *argv[], char *envp[], FILE* fp) +{ + int ii = 0; + if (!fp) + fp = stdout; + + fprintf(fp, "Program name = %s\n", argv[0]); + for (ii = 1; ii < argc; ++ii) + { + fprintf(fp, "argv[%d] = %s\n", ii, argv[ii]); + } + + for (ii = 0; envp[ii]; ++ii) + { + fprintf(fp, "%s\n", envp[ii]); + } + + fprintf(fp, "#####################################\n"); +} + +int main(int argc, char *argv[], char */*envp*/[]) +{ + char *rm = getenv("REQUEST_METHOD"); + int status = 0; + server_config_s cf; + char *infFileName = 0; + int reconfig = 0; + int ii = 0; + int cgi = 0; + int _ai = ADMUTIL_Init(); + + /* Initialize NSS to make ds_salted_sha1_pw_enc() happy */ + if (NSS_NoDB_Init(NULL) != SECSuccess) { + ds_report_error(DS_GENERAL_FAILURE, " initialization failure", + "Unable to initialize the NSS subcomponent."); + exit(1); + } + + /* make stdout unbuffered */ + setbuf(stdout, 0); + +#ifdef XP_WIN32 + if ( getenv("DEBUG_DSINST") ) + DebugBreak(); +#endif + + memset(&cf, 0, sizeof(cf)); + set_defaults(0, 0, &cf); + + /* scan cmd line arguments */ + for (ii = 0; ii < argc; ++ii) + { + if (!strcmp(argv[ii], "-f") && (ii + 1) < argc && + argv[ii+1]) + infFileName = argv[ii+1]; + else if (!strcmp(argv[ii], "-r")) + reconfig = 1; + } + + /* case 1: being called as program -f inffile */ + if (infFileName) + { + FILE *infFile = fopen(infFileName, "r"); + if (!infFile) + { + ds_report_error(INCORRECT_USAGE, infFileName, + "This file could not be opened. A valid file must be given."); + status = 1; + } + else + fclose(infFile); + + if (reconfig) + status = reconfigure_instance(argc, argv); + else + { + if (!status) + status = create_config_from_inf(&cf, argc, argv); + if (!status) + status = create_config(&cf); + if (!status) + status = configure_instance(); + } + } + /* case 2: being called as a CGI */ + else if (rm) + { + cgi = 1; + status = parse_form(&cf); + if (!status) + status = create_config(&cf); + if (!status) + status = configure_instance_with_config(&cf, 1, 0); + } + /* case 3: punt */ + else + { + ds_report_error ( + INCORRECT_USAGE, + "No request method specified", + "A REQUEST_METHOD must be specified (POST, GET) to run this CGI program."); + status = 1; + } + + if (cgi) + { + /* The line below is used by the console to detect + the end of the operation. See replyHandler() in + MigrateCreate.java */ + fprintf(stdout, "NMC_Status: %d\n", status); + /* In the past, we used to call rpt_success() or rpt_err() + according to status. However these functions are not designed + for our case: they print an HTTP header line "Content-type: text/html" */ + } + +#if defined( hpux ) + _exit(status); +#endif + return status; +} diff --git a/ldap/admin/src/java/com/netscape/xmltools/DSML2LDIF.java b/ldap/admin/src/java/com/netscape/xmltools/DSML2LDIF.java new file mode 100644 index 00000000..42eb02fb --- /dev/null +++ b/ldap/admin/src/java/com/netscape/xmltools/DSML2LDIF.java @@ -0,0 +1,234 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +package com.netscape.xmltools; + +import java.util.*; +import java.io.*; +import org.xml.sax.SAXException; +import netscape.ldap.*; +import netscape.ldap.util.*; + +/** + * Tool for converting DSML document to LDIF document + */ +public class DSML2LDIF { + + /** + * Default no argument constructor. + */ + public DSML2LDIF() { + } + + /** + * Parse the command line parameters and setup the options parameters + */ + static private GetOpt parseParameters( String[] args ) { + + GetOpt options = new GetOpt("H?so:", args); + + if (options.hasOption('H') || options.hasOption('?')) { + usage(); + System.exit(0); + } + + if (options.hasOption('v')) { + m_verbose = true; + } + + if (options.hasOption('o')) { + m_outfile = options.getOptionParam('o'); + if (m_outfile == null) { + System.err.println( "Missing argument for output filename" ); + usage(); + System.exit(0); + } + + try { + m_pw = null; + m_pw = new PrintWriter( new FileOutputStream(m_outfile), true ); + } catch (IOException e) { + System.err.println( "Can't open " + m_outfile ); + System.err.println( e.toString() ); + System.exit(1); + } + } + + Vector extras = options.getParameters(); + if (extras.size() == 1 ) { + m_infile = new String( (String)extras.get(0) ); + } else { + if ( options.hasOption('s') ) { + // Use standard input for input of dsml file + m_infile = null; + } else { + usage(); + System.exit(0); + } + + } + return options; + } + + + /** + * Print out usage of the tool + */ + static private void usage() { + System.err.println("Usage: java [-classpath CLASSPATH] DSML2LDIF infile.dsml -s [-o outfile.ldif]"); + System.err.println("options"); + System.err.println(" -s use standard input for input of dsml file" ); + System.err.println(" -o outfile filename for the output LDIF file" ); + System.err.println(" -H -? for usage" ); + // System.err.println(" -v for verbose mode" ); + } + + static void processEntry( LDAPEntry entry ) { + + long now = 0; + long later = 0; + long writeTime; + if ( m_doProfile ) { + now = System.currentTimeMillis(); + } + try { + if (entry != null) { + m_ldifWriter.printEntry( entry ); + // e = null; + } + if ( m_doProfile ) { + later = System.currentTimeMillis(); + writeTime = later - now; + m_lapWriteTime += writeTime; + now = later; + } + } catch (Exception e) { + ; + } + + if ( m_doProfile ) { + m_entryCount++; + if ( (m_entryCount % LAP_LENGTH) == 0 ) { + System.err.println( m_entryCount + " entries" ); + System.err.println( " " + m_lapWriteTime + + " ms to write" ); + m_lapWriteTime = 0; + System.err.println( " " + (now - m_lapTime) + + " ms total this lap" ); + m_lapTime = now; + } + } + } + + /** + * Temporary class to subclass from LDIFWriter + */ + static class MyLDIFWriter extends netscape.ldap.util.LDIFWriter { + public MyLDIFWriter( PrintWriter pw ) { + super( pw ); + } + + /** + * Print prologue to entry + * + * @param dn the DN of the entry + */ + protected void printEntryStart( String dn ) { + if ( dn == null ) { + dn = ""; + } else { + byte[] b = null; + try { + b = dn.getBytes( "UTF8" ); + } catch ( UnsupportedEncodingException ex ) { + } + if ( !LDIF.isPrintable(b) ) { + dn = getPrintableValue( b ); + printString( "dn" + "::" + " " + dn ); + return; + } + } + printString( "dn" + ":" + " " + dn ); + } + } + + /** + * Main routine for the tool. + */ + public static void main(String[] args) { + + m_verify = Boolean.getBoolean("verify"); + parseParameters( args ); + + DSMLReader reader = null; + + try { + if ( m_infile == null ) { + reader = new DSMLReader(); + } + else { + reader = new DSMLReader( m_infile ); + } + } catch (Exception e) { + System.err.println("Error encountered in input"); + System.err.println(e.toString()); + System.exit(1); + } + + m_ldifWriter = new MyLDIFWriter( m_pw ); + + if (m_verify) { + if (m_pw != null) { + m_pw.close(); + } + System.exit( 0 ); + } + + try { + if ( m_doProfile ) { + m_startTime = System.currentTimeMillis(); + m_lapTime = m_startTime; + } + reader.parseDocument(); + } catch( SAXException e ) { + System.err.println("Error encountered in parsing the DSML document"); + System.err.println(e.getMessage()); + e.printStackTrace(); + System.exit(1); + } catch( Exception e ) { + e.printStackTrace(); + } finally { + if (m_pw != null) { + m_pw.flush(); + m_pw.close(); + } + } + + if ( m_doProfile ) { + System.err.println( + (System.currentTimeMillis() - m_startTime) / 1000 + + " seconds total for " + m_entryCount + " entries" ); + } + + System.exit( 0 ); + } + + static private PrintWriter m_pw = new PrintWriter(System.out, true);; + static private boolean m_verbose = false; + static private String m_outfile = null; + static private String m_infile = null; + static private LDIFWriter m_ldifWriter = null; + static private boolean m_verify = false; + static boolean m_doProfile = Boolean.getBoolean("com.netscape.xmltools.doProfile"); + static long m_startTime; + static long m_toEntryTime = 0; + static long m_writeTime = 0; + static long m_lapTime; + static long m_lapToEntryTime = 0; + static long m_lapWriteTime = 0; + static long m_entryCount; + static final int LAP_LENGTH = 1000; +} diff --git a/ldap/admin/src/java/com/netscape/xmltools/DSMLReader.java b/ldap/admin/src/java/com/netscape/xmltools/DSMLReader.java new file mode 100644 index 00000000..f6080433 --- /dev/null +++ b/ldap/admin/src/java/com/netscape/xmltools/DSMLReader.java @@ -0,0 +1,47 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +package com.netscape.xmltools; + +import java.io.*; +import java.util.*; +import org.xml.sax.*; +import netscape.ldap.*; +import netscape.ldap.util.*; + +/** + * Class for reading a DSML document according to the DSML 1.0 spec. + */ +public class DSMLReader { + + /** + * Default no argument constructor + */ + public DSMLReader() throws IOException { + m_ds = new DataInputStream( System.in ); + } + + /** + * Constructor for a dsml reader based on a file + * + * @param filename system-dependent filename + */ + public DSMLReader( String filename ) throws IOException { + m_ds = new DataInputStream( new FileInputStream( filename ) ); + } + + /** + * Parses the input stream as a DSML document + * + * @throws SAXException on parsing errors + */ + public void parseDocument() throws SAXException { + DSMLSAXBuilder builder = new DSMLSAXBuilder(); + builder.parse( new InputSource( m_ds ) ); + } + + private DataInputStream m_ds = null; +} diff --git a/ldap/admin/src/java/com/netscape/xmltools/DSMLSAXBuilder.java b/ldap/admin/src/java/com/netscape/xmltools/DSMLSAXBuilder.java new file mode 100644 index 00000000..4f85d2db --- /dev/null +++ b/ldap/admin/src/java/com/netscape/xmltools/DSMLSAXBuilder.java @@ -0,0 +1,86 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +package com.netscape.xmltools; + +import javax.xml.parsers.*; +import org.xml.sax.*; +import org.xml.sax.helpers.*; + +/** + * A skeletal SAX driver, which doesn't create a document. Its content handler + * is a DSMLSAXHandler which creates and dispatches LDAP entries from a + * DSML document on the fly. + */ +public class DSMLSAXBuilder { + + /** + * <p> + * Creates a new DSMLSAXBuilder with parser that will not validate. + * </p> + */ + public DSMLSAXBuilder() { + } + + /** + * <p> + * Creates a new DSMLSAXBuilder which will validate + * according to the given parameter. + * </p> + * + * @param validate <code>boolean</code> indicating if + * validation should occur. + */ + public DSMLSAXBuilder(boolean validate) { + m_validate = validate; + } + + /** + * Processes the supplied input source + * + * @param in <code>InputSource</code> to read from + * @throws SAXException when errors occur in parsing + */ + public void parse(InputSource in) throws SAXException { + DSMLSAXHandler contentHandler = null; + + try { + // Create the parser + SAXParserFactory fac = SAXParserFactory.newInstance(); + fac.setValidating( m_validate ); + + XMLReader parser = fac.newSAXParser().getXMLReader(); + parser.setFeature( "http://xml.org/sax/features/namespaces", + true ); + parser.setFeature( "http://xml.org/sax/features/namespace-prefixes", + true ); + + // Create and configure the content handler + parser.setContentHandler( new DSMLSAXHandler() ); + + // Parse the document + parser.parse( in ); + } catch (Exception e) { + if (e instanceof SAXParseException) { + SAXParseException p = (SAXParseException)e; + String systemId = p.getSystemId(); + if (systemId != null) { + throw new SAXException("Error on line " + + p.getLineNumber() + " of document " + + systemId, e); + } else { + throw new SAXException("Error on line " + + p.getLineNumber(), e); + } + } else if (e instanceof SAXException) { + throw (SAXException)e; + } else { + throw new SAXException("Error in parsing", e); + } + } + } + + private boolean m_validate = false; +} diff --git a/ldap/admin/src/java/com/netscape/xmltools/DSMLSAXHandler.java b/ldap/admin/src/java/com/netscape/xmltools/DSMLSAXHandler.java new file mode 100644 index 00000000..73b067d7 --- /dev/null +++ b/ldap/admin/src/java/com/netscape/xmltools/DSMLSAXHandler.java @@ -0,0 +1,299 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +package com.netscape.xmltools; + +import java.util.*; + +import org.xml.sax.*; +import org.xml.sax.helpers.*; + +import netscape.ldap.*; +import netscape.ldap.util.*; + +/** + * Content handler which dispatches each LDAP entry composed from a dsml:entry + * element and its children. No document is built. + */ +public class DSMLSAXHandler extends DefaultHandler { + /** The DSML namespace */ + private static final String DSML_NS = "http://www.dsml.org/DSML"; + + /** Element stack */ + private Stack stack = new Stack(); + + /** Whether to ignore ignorable whitespace */ + private boolean ignoringWhite = true; + + /** Keeps track of name spaces */ + private NamespaceSupport namespaces = new NamespaceSupport(); + + /** + * Creates a new <code>SAXHandler</code> that listens to SAX + * events and dispatches LDAP entries as they are found + */ + public DSMLSAXHandler() { + } + + /** + * Returns the value of a particular attribute from an array of + * attributes + * + * @param atts Array of attributes to process + * @param name The name of the attribute to return + * @return The value of the matching attribute, or null if not there + */ + private String findAttribute( Attributes atts, String name ) { + for (int i = 0, len = atts.getLength(); i < len; i++) { + String attLocalName = atts.getLocalName(i); + String attQName = atts.getQName(i); + // Bypass any xmlns attributes which might appear, as we got + // them already in startPrefixMapping(). + + if (attQName.startsWith("xmlns:") || attQName.equals("xmlns")) { + continue; + } + + if ( name.equalsIgnoreCase( attLocalName ) ) { + return atts.getValue(i); + } + } + return null; + } + + /** + * Creates and returns an object corresponding to the element type + * + * @param prefix Namespace + * @param localName Element name without namespace + * @param atts Any attributes of the element + * @return An object corresponding to the element type + */ + private Object getObjectForElement( String prefix, + String localName, + Attributes atts ) { + // Should not assume the "dsml" prefix. Any prefix can + // be mapped to the DSML namespace URI. + String uri = namespaces.getURI( prefix ); + if ( (uri != null) && uri.equalsIgnoreCase( DSML_NS ) ) { + if ( "entry".equalsIgnoreCase( localName ) ) { + String dn = findAttribute( atts, "dn" ); + if ( dn != null ) { + LDAPEntry entry = new LDAPEntry( dn ); + return entry; + } else { + System.err.println( "No DN for entry" ); + } + } else if ( "attr".equalsIgnoreCase( localName ) ) { + String name = findAttribute( atts, "name" ); + if ( name != null ) { + LDAPAttribute attr = new LDAPAttribute( name ); + return attr; + } else { + System.err.println( "No name for attribute" ); + } + } else if ( "objectclass".equalsIgnoreCase( localName ) ) { + LDAPAttribute attr = new LDAPAttribute( "objectclass" ); + return attr; + } else if ( "oc-value".equalsIgnoreCase( localName ) ) { + return new StringAttrValue(); + } else if ( "value".equalsIgnoreCase( localName ) ) { + String enc = findAttribute( atts, "encoding" ); + if ( "Base64".equalsIgnoreCase( enc ) ) { + return new BinaryAttrValue(); + } else { + return new StringAttrValue(); + } + } + } + return null; + } + + + /** + * This reports the occurrence of an actual element. It will include + * the element's attributes, with the exception of XML vocabulary + * specific attributes, such as + * <code>xmlns:[namespace prefix]</code> and + * <code>xsi:schemaLocation</code>. + * + * @param namespaceURI <code>String</code> namespace URI this element + * is associated with, or an empty + * <code>String</code> + * @param localName <code>String</code> name of element (with no + * namespace prefix, if one is present) + * @param qName <code>String</code> XML 1.0 version of element name: + * [namespace prefix]:[localName] + * @param atts <code>Attributes</code> list for this element + * @throws SAXException when things go wrong + */ + public void startElement(String namespaceURI, String localName, + String qName, Attributes atts) + throws SAXException { + Object obj = null; + + int split = qName.indexOf(":"); + String prefix = (split > 0) ? qName.substring(0, split) : null; + if ( prefix != null ) { + // Save the prefix to URI mapping + if ((namespaceURI != null) && (!namespaceURI.equals(""))) { + namespaces.pushContext(); + if ( namespaces.getPrefix( namespaceURI ) == null ) { + namespaces.declarePrefix( prefix, namespaceURI ); + } + } + obj = getObjectForElement( prefix, localName, atts ); + if ( obj instanceof LDAPEntry ) { + m_entry = (LDAPEntry)obj; + } else if ( obj instanceof LDAPAttribute ) { + m_attr = (LDAPAttribute)obj; + } + } else { + // This should never happen + System.err.println( "No namespace for [" + qName + "]" ); + m_entry = null; + m_attr = null; + } + + if ( obj != null ) { + // Put the DSML object on the stack + stack.push(obj); + } + } + + /** + * This will report character data (within an element) + * + * @param ch <code>char[]</code> character array with character data + * @param start <code>int</code> index in array where data starts. + * @param length <code>int</code> length of data. + * @throws SAXException when things go wrong + */ + public void characters(char[] ch, int start, int length) + throws SAXException { + + // Ignore whitespace + boolean empty = true; + int maxOffset = start+length; + for( int i = start; i < maxOffset; i++ ) { + if ( (ch[i] != ' ') && (ch[i] != '\n') ) { + empty = false; + break; + } + } + if ( empty ) { + return; + } + + m_sb.append( ch, start, length ); + } + + /** + * Captures ignorable whitespace as text. If + * setIgnoringElementContentWhitespace(true) has been called then this + * method does nothing. + * + * @param ch <code>[]</code> - char array of ignorable whitespace + * @param start <code>int</code> - starting position within array + * @param length <code>int</code> - length of whitespace after start + * @throws SAXException when things go wrong + */ + public void ignorableWhitespace(char[] ch, int start, int length) + throws SAXException { + if (ignoringWhite) return; + + characters(ch, start, length); + } + + /** + * Takes any action appropriate for a particular object when it has + * been composed from an element and any children + * + * @param obj A DSML object + * @return The updated object + */ + private Object processElementByObject( Object obj ) { + if ( obj instanceof LDAPEntry ) { + // An entry is ready to be processed + LDAPEntry entry = (LDAPEntry)obj; + // Rather than a static method, this should be an object that + // implements an interface and is provided with a setEntryProcessor + // method + DSML2LDIF.processEntry( entry ); + } else if ( obj instanceof StringAttrValue ) { + if ( m_attr == null ) { + // This should never happen + System.err.println( "dsml:value or dsml:oc-value element " + + "not inside dsml:attr or " + + "dsml:objectclass" ); + } else { + String val = new String( m_sb ); + m_attr.addValue( val ); + } + m_sb.setLength( 0 ); + } else if ( obj instanceof BinaryAttrValue ) { + if ( m_attr == null ) { + System.err.println( "dsml:value element not inside dsml:attr" ); + } else { + ByteBuf inBuf = new ByteBuf( new String( m_sb ) ); + ByteBuf decodedBuf = new ByteBuf(); + // Decode base 64 into binary + m_decoder.translate( inBuf, decodedBuf ); + int nBytes = decodedBuf.length(); + if ( nBytes > 0 ) { + String decodedValue = new String(decodedBuf.toBytes(), 0, + nBytes); + m_attr.addValue( decodedValue); + } + } + m_sb.setLength( 0 ); + } else if ( obj instanceof LDAPAttribute ) { + if ( m_entry == null ) { + // This should never happen + System.err.println( "dsml:attr element not inside dsml:entry" ); + } else { + m_entry.getAttributeSet().add( (LDAPAttribute)obj ); + } + m_attr = null; + } + return obj; + } + + /** + * Indicates the end of an element + * (<code></[element name]></code>) is reached. Note that + * the parser does not distinguish between empty + * elements and non-empty elements, so this will occur uniformly. + * + * @param namespaceURI <code>String</code> URI of namespace this + * element is associated with + * @param localName <code>String</code> name of element without prefix + * @param qName <code>String</code> name of element in XML 1.0 form + * @throws SAXException when things go wrong + */ + public void endElement(String namespaceURI, String localName, + String qName) throws SAXException { + if ( !stack.empty() ) { + Object obj = stack.pop(); + + processElementByObject( obj ); + } + + if ((namespaceURI != null) && + (!namespaceURI.equals(""))) { + namespaces.popContext(); + } + } + + private LDAPEntry m_entry = null; + private LDAPAttribute m_attr = null; + private StringBuffer m_sb = new StringBuffer(1024); + static private MimeBase64Decoder m_decoder = new MimeBase64Decoder(); + + class StringAttrValue { + } + class BinaryAttrValue { + } +} diff --git a/ldap/admin/src/java/com/netscape/xmltools/DSMLWriter.java b/ldap/admin/src/java/com/netscape/xmltools/DSMLWriter.java new file mode 100644 index 00000000..82ebc3d0 --- /dev/null +++ b/ldap/admin/src/java/com/netscape/xmltools/DSMLWriter.java @@ -0,0 +1,315 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +package com.netscape.xmltools; + +import java.util.*; +import netscape.ldap.*; +import java.io.*; +import netscape.ldap.util.*; + +/** + * Class for outputting LDAP entries to a stream as DSML. + * + * @version 1.0 + */ +public class DSMLWriter extends LDAPWriter { + +// static final long serialVersionUID = -2710382547996750924L; + + /** + * Constructs a <CODE>DSMLWriter</CODE> object to output entries + * to a stream as DSML. + * + * @param pw output stream + */ + public DSMLWriter( PrintWriter pw ) { + super( pw ); + } + + /** + * Prints the schema from an entry containing subschema + * + * entry entry containing schema definitions + */ + public void printSchema( LDAPEntry entry ) { + LDAPSchema schema = new LDAPSchema( entry ); + printString( " <dsml:directory-schema>" ); + printObjectClassSchema( schema ); + printAttributeSchema( schema ); + printString( " </dsml:directory-schema>" ); + } + + + /** + * Prints the object class schema from a schema object + * + * schema schema elements + */ + protected void printObjectClassSchema( LDAPSchema schema ) { + Enumeration en = schema.getObjectClasses(); + while( en.hasMoreElements() ) { + LDAPObjectClassSchema s = (LDAPObjectClassSchema)en.nextElement(); + printString( " <dsml:class" ); + printString( " id=\"" + s.getName() + "\"" ); + printString( " oid=\"" + s.getID() + "\"" ); + String[] superiors = s.getSuperiors(); + if ( superiors != null ) { + for( int i = 0; i < superiors.length; i++ ) { + printString( " superior=\"#" + superiors[i] + "\"" ); + } + } + String classType = "structural"; + switch( s.getType() ) { + case LDAPObjectClassSchema.ABSTRACT: classType = "abstract"; + break; + case LDAPObjectClassSchema.AUXILIARY: classType = "auxiliary"; + break; + } + printString( " type=\"" + classType + "\">" ); + if ( s.isObsolete() ) { + printString( " obsolete=true" ); + } + printString( " <dsml:name>" + s.getName() + "</dsml:name>" ); + printString( " <dsml:description>" + s.getDescription() + + "</dsml:description>" ); + Enumeration attrs = s.getRequiredAttributes(); + while( attrs.hasMoreElements() ) { + printString( " <dsml:attribute ref=\"#" + + (String)attrs.nextElement() + + "\" required=\"true\"/>" ); + } + attrs = s.getOptionalAttributes(); + while( attrs.hasMoreElements() ) { + printString( " <dsml:attribute ref=\"#" + + (String)attrs.nextElement() + + "\" required=\"false\"/>" ); + } + printString( " </dsml:class>" ); + } + } + + + /** + * Prints the attribute schema from a schema object + * + * schema schema elements + */ + protected void printAttributeSchema( LDAPSchema schema ) { + Enumeration en = schema.getAttributes(); + while( en.hasMoreElements() ) { + LDAPAttributeSchema s = (LDAPAttributeSchema)en.nextElement(); + printString( " <dsml:attribute-type" ); + printString( " id=\"" + s.getName() + "\"" ); + printString( " oid=\"" + s.getID() + "\"" ); + String superior = s.getSuperior(); + if ( superior != null ) { + printString( " superior=\"#" + superior + "\"" ); + } + if ( s.isSingleValued() ) { + printString( " single-value=true" ); + } + if ( s.isObsolete() ) { + printString( " obsolete=true" ); + } + if ( s.getQualifier( s.NO_USER_MODIFICATION ) != null ) { + printString( " user-modification=false" ); + } + String[] vals = s.getQualifier( s.EQUALITY ); + if ( (vals != null) && (vals.length > 0) ) { + printString( " equality=" + vals[0] ); + } + vals = s.getQualifier( s.ORDERING ); + if ( (vals != null) && (vals.length > 0) ) { + printString( " ordering=" + vals[0] ); + } + vals = s.getQualifier( s.SUBSTR ); + if ( (vals != null) && (vals.length > 0) ) { + printString( " substring=" + vals[0] ); + } + printString( " <dsml:name>" + s.getName() + "</dsml:name>" ); + printString( " <dsml:description>" + s.getDescription() + + "</dsml:description>" ); + printString( " <dsml:syntax>" + s.getSyntaxString() + + "</dsml:syntax>" ); + printString( " </dsml:attribute-type>" ); + } + } + + + /** + * Print an attribute of an entry + * + * @param attr the attribute to format to the output stream + */ + protected void printAttribute( LDAPAttribute attr ) { + String attrName = attr.getName(); + + // Object classes are treated differently in DSML. Also, they + // are always String-valued + if ( attrName.equalsIgnoreCase( "objectclass" ) ) { + Enumeration enumVals = attr.getStringValues(); + if ( enumVals != null ) { + printString( " <dsml:objectclass>" ); + while ( enumVals.hasMoreElements() ) { + String s = (String)enumVals.nextElement(); + printString( " <dsml:oc-value>" + s + + "</dsml:oc-value>" ); + } + printString( " </dsml:objectclass>" ); + } + return; + } + + printString( " <dsml:attr name=\"" + attrName + "\">" ); + + /* Loop on values for this attribute */ + Enumeration enumVals = attr.getByteValues(); + + if ( enumVals != null ) { + while ( enumVals.hasMoreElements() ) { + byte[] b = (byte[])enumVals.nextElement(); + String s; + if ( LDIF.isPrintable(b) ) { + try { + s = new String( b, "UTF8" ); + } catch ( UnsupportedEncodingException e ) { + s = ""; + } + printEscapedValue( " <dsml:value>", s, + "</dsml:value>" ); + } else { + s = getPrintableValue( b ); + if ( s.length() > 0 ) { + printString( " " + + "<dsml:value encoding=\"base64\">" ); + printString( " " + s ); + printString( " </dsml:value>" ); + } + } + } + } + printString( " </dsml:attr>" ); + } + + /** + * Print prologue to entry + * + * @param dn the DN of the entry + */ + protected void printEntryStart( String dn ) { + +/* + if ( dn == null ) { + dn = ""; + } else { + byte[] b = null; + try { + b = dn.getBytes( "UTF8" ); + } catch ( UnsupportedEncodingException ex ) { + } + + if ( !LDIF.isPrintable(b) ) { + dn = getPrintableValue( b ); + printString( " <dsml:entry dn=\"" + dn + "\" encoding=\"base64\">" ); + return; + } + + } + printString( " <dsml:entry dn=\"" + dn + "\">" ); +*/ + + + if ( dn == null ) { + dn = ""; + } + m_pw.print( " <dsml:entry dn=\"" ); + printEscapedAttribute( dn ); + m_pw.println( "\">" ); + } + + /** + * Print epilogue to entry + * + * @param dn the DN of the entry + */ + protected void printEntryEnd( String dn ) { + printString( " </dsml:entry>" ); + } + + /** + * Print the element start, the value with escaping of special + * characters, and the element end + * + * @param prolog element start + * @param value value to be escaped + * @param epilog element end + */ + protected void printEscapedValue( String prolog, String value, + String epilog ) { + m_pw.print( prolog ); + int l = value.length(); + char[] text = new char[l]; + value.getChars( 0, l, text, 0 ); + for ( int i = 0; i < l; i++ ) { + char c = text[i]; + switch (c) { + case '<' : + m_pw.print( "<" ); + break; + case '&' : + m_pw.print( "&" ); + break; + default : + m_pw.print( c ); + } + } + // m_pw.print( epilog); + // m_pw.print( '\n' ); + m_pw.println( epilog ); + } + + /** + * Print the element attribute escaping of special + * characters + * + * @param attribute Attribute value to be escaped + */ + protected void printEscapedAttribute( String attribute ) { + + int l = attribute.length(); + char[] text = new char[l]; + attribute.getChars( 0, l, text, 0 ); + for ( int i = 0; i < l; i++ ) { + char c = text[i]; + switch (c) { + case '<' : + m_pw.print( "<" ); + break; + case '>': + m_pw.print( ">" ); + break; + case '&' : + m_pw.print( "&" ); + break; + case '"': + m_pw.print( """ ); + break; + case '\'': + m_pw.print( "'" ); + break; + default : + m_pw.print( c ); + } + } + } + + protected void printString( String value ) { + // m_pw.print( value ); + // m_pw.print( '\n' ); + m_pw.println( value ); + } +} diff --git a/ldap/admin/src/java/com/netscape/xmltools/GetOpt.java b/ldap/admin/src/java/com/netscape/xmltools/GetOpt.java new file mode 100644 index 00000000..91d17e18 --- /dev/null +++ b/ldap/admin/src/java/com/netscape/xmltools/GetOpt.java @@ -0,0 +1,222 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +package com.netscape.xmltools; +import java.util.*; + +/** + * This class is similar to the <CODE>getopt()</CODE> function in + * UNIX System V. You can use this class to parse command-line + * arguments. + * <P> + * + * When you create an object of this class, you specify a string + * containing the command-line options that you want to check for. + * The string should contain the letters of these options. If an + * option requires an argument (for example, "-h <hostname>"), + * you should add a colon after the letter in this string. + * <P> + * + * For example, in the following string, the <CODE>-h</CODE>, + * <CODE>-p</CODE>, <CODE>-D,</CODE>, and <CODE>-w</CODE> options + * all require arguments. The <CODE>-H</CODE> option does not + * require any arguments. + * <PRE> + * "h:p:D:w:H" + * </PRE> + * + * You can use the <CODE>hasOption</CODE> method to determine if + * an option has been specified and the <CODE>getOptionParam</CODE> + * method to get the argument specified after a particular option. + * <P> + * + * If an option not specified in the string is passed in as an + * argument, the <CODE>GetOpt</CODE> object prints out an error + * message. Note that the object does not throw an exception or + * exit the application if an invalid option is specified. + * <P> + * + * Note that you are still responsible for verifying that any + * required arguments have been specified. + * <P> + * + * The following example parses the command-line arguments for + * the hostname, port number, DN, and password to use when + * connecting and authenticating to an LDAP server. + * <PRE> + * import netscape.ldap.*; + * import netscape.ldap.controls.*; + * import netscape.ldap.util.*; + * import java.util.*; + * + * public class SearchDirectory { + * + * public static void main( String[] args ) + * { + * + * String usage = "Usage: java SearchDirectory -h <host> -p <port> " + * + "[-D <bind dn>] [-w <password>]" + * + * int portnumber = LDAPv2.DEFAULT_PORT; + * + * // Check for these options. -H means to print out a usage message. + * GetOpt options = new GetOpt( "h:p:D:w:H", args ); + * + * // Get the arguments specified for each option. + * String hostname = options.getOptionParam( 'h' ); + * String port = options.getOptionParam( 'p' ); + * String bindDN = options.getOptionParam( 'D' ); + * String bindPW = options.getOptionParam( 'w' ); + * + * // Check to see if the hostname (which is mandatory) + * // is not specified or if the user simply wants to + * // see the usage message (-H). + * if ( hostname == null || options.hasOption( 'H' ) ) { + * System.out.println( usage ); + * System.exit( 1 ); + * } + * + * // If a port number was specified, convert the port value + * // to an integer. + * if ( port != null ) { + * try { + * portnumber = java.lang.Integer.parseInt( port ); + * } catch ( java.lang.Exception e ) { + * System.out.println( "Invalid port number: " + port ); + * System.out.println( usage ); + * System.exit( 1 ); + * } + * } + * + * // Create a new connection. + * LDAPConnection ld = new LDAPConnection(); + * + * try { + * // Connect and authenticate to server. + * ld.connect( 3, hostname, portnumber, bindDN, bindPW ); + * ... + * } catch ( LDAPException e ) { + * System.out.println( "Error: " + e.toString() ); + * } + * ... + * } + * } + * </PRE> + * + * @version 1.0 + */ +public class GetOpt implements java.io.Serializable { + /** + * Internal variables + */ + private int m_pos; + private String optarg; + private String m_control; + private Vector m_option; + private Vector m_ParameterList; + private Hashtable m_optionHashTable; + private Hashtable m_optionParamHashTable; + static final long serialVersionUID = -2570196909939660248L; + + /** + * Constructs a <CODE>GetOpt</CODE> object. + * @param strControl a string specifying the letters of + * all available options. If an option requires an argument + * (for example, "-h <hostname>"), use a colon after the + * letter for that option (for example, "h:p:D:w:H"). + * @param args an array of strings representing the list + * of arguments to parse (for example, the + * array passed into Main). + */ + public GetOpt(String strControl, String args[]) { + m_option = new Vector(); + m_control = strControl; + m_optionHashTable = new Hashtable(); + m_optionParamHashTable = new Hashtable(); + m_ParameterList = new Vector(); + + for (int i=0;i<args.length ;i++ ) { + String sOpt = args[i]; + if (sOpt.length()>0) { + if (sOpt.charAt(0)=='-') { + if (sOpt.length()>1) { + int nIndex = m_control.indexOf(sOpt.charAt(1)); + if (nIndex == (-1)) { + System.err.println("Invalid usage. No option -" + + sOpt.charAt(1)); + } else { + char cOpt[]= new char[1]; + cOpt[0]= sOpt.charAt(1); + String sName = new String(cOpt); + m_optionHashTable.put(sName,"1"); + if ((m_control != null) && (m_control.length() > (nIndex+1))) { + if (m_control.charAt(nIndex+1)==':') { + i++; + if (i < args.length) + m_optionParamHashTable.put(sName,args[i]); + else + System.err.println("Missing argument for option "+ + sOpt); + } + } + } + } else { + System.err.println("Invalid usage."); + } + } else { + // probably parameters + m_ParameterList.addElement(args[i]); + } + } + } + } + + /** + * Determines if an option was specified. For example, + * <CODE>hasOption( 'H' )</CODE> checks if the -H option + * was specified. + * <P> + * + * @param c letter of the option to check + * @return <code>true</code> if the option was specified. + */ + public boolean hasOption(char c) { + boolean fReturn = false; + char cOption[]=new char[1]; + cOption[0]=c; + String s = new String(cOption); + if (m_optionHashTable.get(s)=="1") { + fReturn = true; + } + return(fReturn); + } + + /** + * Gets the argument specified with an option. + * For example, <CODE>getOptionParameter( 'h' )</CODE> + * gets the value of the argument specified with + * the -h option (such as "localhost" in "-h localhost"). + * <P> + * + * @param c the letter of the option to check + * @return the argument specified for this option. + */ + public String getOptionParam(char c) { + char cOption[] = new char[1]; + cOption[0]=c; + String s = new String(cOption); + String sReturn=(String)m_optionParamHashTable.get(s); + return(sReturn); + } + + /** + * Gets a list of any additional parameters specified + * (not including the arguments for any options). + * @return a list of the additional parameters. + */ + public Vector getParameters() { + return(m_ParameterList); + } +} diff --git a/ldap/admin/src/java/com/netscape/xmltools/LDIF2DSML.java b/ldap/admin/src/java/com/netscape/xmltools/LDIF2DSML.java new file mode 100644 index 00000000..ae4ada4f --- /dev/null +++ b/ldap/admin/src/java/com/netscape/xmltools/LDIF2DSML.java @@ -0,0 +1,214 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +package com.netscape.xmltools; + +import java.io.*; +import java.util.*; +import netscape.ldap.util.GetOpt; +import netscape.ldap.util.*; +import netscape.ldap.*; + +/** + * Tool for converting LDIF document to DSML document + */ +public class LDIF2DSML { + + /** + * Default no argument constructor. + */ + public LDIF2DSML() { + } + + /** + * Converter taking a filename argument for the input LDIF file + * + * @param filename system-dependent file name for the input LDIF file + */ + public LDIF2DSML( String filename ) throws IOException { + + DataInputStream ds = null; + + if( filename == null || filename.length() == 0 ) { + ds = new DataInputStream( System.in ); + } + else { + ds = new DataInputStream( new FileInputStream( filename) ); + } + + // set up the ldif parser with the input stream + // + m_ldifReader = new LDIF( ds ); + } + + /** + * Converts an LDIF record to an LDAPEntry. Only convert if the content + * of the LDIF record is of the type LDIFContent.ATTRIBUTE_CONTENT. + * + * @param rec An LDIFRecord to be converted + * @returns The converted LDAPEntry. null is returned for any ldif record not + * being recognized with attribute content + */ + public LDAPEntry toLDAPEntry( LDIFRecord rec ) { + + String dn = rec.getDN(); + LDIFContent content = rec.getContent(); + + if (content.getType() == LDIFContent.ATTRIBUTE_CONTENT) { + LDIFAttributeContent entry = (LDIFAttributeContent)content; + /* LDAPAttribute attrs[] = entry.getAttributes(); + for( int i = 0; i < attrs.length; i++ ) { + System.err.println( attrs[i].toString() ); + }*/ + return new LDAPEntry( dn, new LDAPAttributeSet( entry.getAttributes()) ); + } + return null; + } + + /** + * Conversion from ldif to dsml document. + */ + public void convert() { + DSMLWriter writer = new DSMLWriter( m_pw ); + int recCount = 0; + int rejectCount = 0; + + try { + + m_pw.println( "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); + m_pw.println( "<dsml:dsml xmlns:dsml=\"http://www.dsml.org/DSML\">"); + m_pw.println( " <dsml:directory-entries>" ); + + for( LDIFRecord rec = m_ldifReader.nextRecord(); + rec != null; rec = m_ldifReader.nextRecord(), recCount++ ) { + LDAPEntry entry = toLDAPEntry( rec ); + if (entry != null) { + writer.printEntry( entry ); + entry = null; + } + } + + m_pw.println( " </dsml:directory-entries>" ); + m_pw.println( "</dsml:dsml>" ); + + } catch (IOException e) { + e.printStackTrace(); + } finally { + m_pw.flush(); + m_pw.close(); + } + } + + /** + * Parse the command line parameters and setup the options parameters + */ + static private GetOpt parseParameters( String[] args ) { + + GetOpt options = new GetOpt("H?so:", args); + + if (options.hasOption('H') || options.hasOption('?')) { + usage(); + System.exit(0); + } + + if (options.hasOption('v')) { + m_verbose = true; + } + + if (options.hasOption('o')) { + m_outfile = options.getOptionParam('o'); + if (m_outfile == null) { + System.err.println( "Missing argument for output filename" ); + usage(); + System.exit(0); + } + + try { + /* + m_pw = null; + m_pw = new PrintWriter( new FileOutputStream(m_outfile), true ); + */ + + m_pw = null; + // always write DSML document out in UTF8 encoding + // + OutputStreamWriter os = new OutputStreamWriter( new FileOutputStream(m_outfile), "UTF8" ); + m_pw = new PrintWriter( os, true ); + } catch (IOException e) { + System.err.println( "Can't open " + m_outfile ); + System.err.println( e.toString() ); + System.exit(1); + } + } + + Vector extras = options.getParameters(); + if (extras.size() == 1 ) { + m_infile = new String( (String)extras.get(0) ); + } else { + if ( options.hasOption('s') ) { + // System.err.println( "Use standard input for input of ldif file" ); + m_infile = null; + } else { + usage(); + System.exit(0); + } + } + return options; + } + + /** + * Print out usage of the tool + */ + static private void usage() { + System.err.println("Usage: java [-classpath $CLASSPATH] LDIF2DSML infile.ldif [-s] [-o outfile.dsml]"); + System.err.println("options"); + System.err.println(" -s use standard input for input of ldif file" ); + System.err.println(" -o outfile filename for the output DSML file" ); + System.err.println(" -H -? for usage" ); + // System.err.println(" -v for verbose mode" ); + + } + + /** + * Main routine for the tool. + */ + static public void main(String[] args){ + + m_verify = Boolean.getBoolean("verify"); + + parseParameters( args); + + LDIF2DSML converter = null; + + try { + if (m_infile== null) { + converter = new LDIF2DSML( null ); + } + else { + converter = new LDIF2DSML( m_infile ); + } + } catch( IOException e ) { + System.err.println( "Error encountered in input" ); + System.err.println( e.toString() ); + System.exit( 1 ); + } + + if (m_verify) { + System.exit( 0 ); + } + + converter.convert(); + System.exit( 0 ); + + } + + static private PrintWriter m_pw = new PrintWriter(System.out, true); + static private boolean m_verbose = false; + static private String m_outfile = null; + static private String m_infile = null; + static private LDIF m_ldifReader = null; + static private boolean m_verify = false; +} diff --git a/ldap/admin/src/java/com/netscape/xmltools/Makefile b/ldap/admin/src/java/com/netscape/xmltools/Makefile new file mode 100644 index 00000000..61b4b535 --- /dev/null +++ b/ldap/admin/src/java/com/netscape/xmltools/Makefile @@ -0,0 +1,67 @@ +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +# Name: +# Platform: gmake +# -------------------------------------------------------------------------- +override BUILD_MODULE=HTTP_ADMIN + +NOSTDCLEAN=true +NO_BUILD_NUM=true +COMPONENT_DEPS=true + +MCOM_ROOT=../../../../../../../.. + +include ../../../../../../../nsconfig.mk +include ../../../../../../../ldap/javarules.mk +CLASS_DIR=$(JAVA_DEST_DIR)/xmltools +PACKAGE_DIR=$(ABS_ROOT)/dist/$(BUILD_DEBUG) +_PACKAGE_DIR=$(MCOM_ROOT)/dist/$(BUILD_DEBUG) +DEST_DIR=$(CLASS_DIR)/com/netscape/xmltools +JARS_DIR=lib +TOOLS_JARS=$(JARS_DIR)/crimson.jar$(PATH_SEP)$(JARS_DIR)/ldapjdk.jar +TOOLS_JAR_FILE=xmltools.jar +# +# programs list +# +source = \ + $(DEST_DIR)/DSML2LDIF.class \ + $(DEST_DIR)/LDIF2DSML.class \ + $(DEST_DIR)/DSMLReader.class \ + $(DEST_DIR)/DSMLWriter.class \ + $(DEST_DIR)/GetOpt.class \ + $(DEST_DIR)/DSMLSAXBuilder.class \ + $(DEST_DIR)/DSMLSAXHandler.class + + +package: all $(_PACKAGE_DIR) +# when zip finds nothing to do, it exits with code 12 which is not an error +# so we turn that 12 into a 0 which means success so make will continue + cd $(CLASS_DIR); zip -r -u $(PACKAGE_DIR)/$(TOOLS_JAR_FILE) com || if [ $$? -eq 12 ]; then exit 0 ; else exit $$? ; fi + +all: $(DEST_DIR) $(CRIMSONJAR_DEP) $(LDAPJDK_DEP) $(source) + +clean: + rm -f $(DEST_DIR)/*.class; rm -f $(PACKAGE_DIR)/$(TOOLS_JAR_FILE) + +fresh: $(clean) $(all) + + +jdoc: ./doc + $(JAVADOC) -classpath "$(CLASSPATH)$(PATH_SEP)$(CLASS_DIR)$(PATH_SEP)$(CRIMSONJAR_FILE)" -d ./doc com.netscape.xmltools + +jdoc.clean : + rm -rf ./doc + +$(_PACKAGE_DIR): + mkdir -p $(_PACKAGE_DIR) + +$(DEST_DIR)/%.class : %.java + $(JAVAC) -deprecation -classpath "$(CLASSPATH)$(PATH_SEP)$(CLASS_DIR)$(PATH_SEP)$(CRIMSONJAR_FILE)" -d $(CLASS_DIR) $< + +$(DEST_DIR) ./doc: + mkdir -p $@ diff --git a/ldap/admin/src/java/install b/ldap/admin/src/java/install new file mode 100755 index 00000000..e307f782 --- /dev/null +++ b/ldap/admin/src/java/install @@ -0,0 +1,17 @@ +#!/bin/sh +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +if [ $# -lt 1 ] +then + echo >&2 "Usage: $0 targetDirectory" + exit 2 +fi +mkdir -p $1 +mkdir -p $1/jars +cp -p `dirname $0`/mcc $1 +cp -p -r `dirname $0`/jars/* $1/jars diff --git a/ldap/admin/src/java/mcc b/ldap/admin/src/java/mcc new file mode 100755 index 00000000..080ffb98 --- /dev/null +++ b/ldap/admin/src/java/mcc @@ -0,0 +1,38 @@ +#!/bin/sh +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +if [ $# -lt 2 ] +then + echo >&2 "Usage: $0 host port [[user] [password]" + exit 2 +fi +MCC_HOST=$1 +MCC_PORT=$2 +# Has to be in the jars subdirectory +JARDIR=./jars +# +DS=${JARDIR}/ds40.jar +ADMIN=${JARDIR}/admserv.jar +KINGPIN=${JARDIR}/kingpin.jar +SWING=${JARDIR}/swingall.jar +LF=${JARDIR}/nmclf.jar +LAYOUT=${JARDIR}/layout.jar +LDAP=${JARDIR}/ldapjdk.jar +BASE=o=netscaperoot +CLASSPATH=${DS}:${KINGPIN}:${ADMIN}:${SWING}:${LAYOUT}:${LF}:${LDAP};export CLASSPATH +cd `dirname $0` +if [ $# -gt 3 ] +then + java com.netscape.management.client.console.Console -d ${MCC_HOST} -p ${MCC_PORT} -u "$3" -w "$4" -b ${BASE} +elif [ $# -gt 2 ] +then + java com.netscape.management.client.console.Console -d ${MCC_HOST} -p ${MCC_PORT} -u "$3" -b ${BASE} +else + java com.netscape.management.client.console.Console -d ${MCC_HOST} -p ${MCC_PORT} -b ${BASE} +fi + diff --git a/ldap/admin/src/java/mcc.bat b/ldap/admin/src/java/mcc.bat new file mode 100644 index 00000000..4caccf18 --- /dev/null +++ b/ldap/admin/src/java/mcc.bat @@ -0,0 +1,45 @@ +@rem // +@rem // BEGIN COPYRIGHT BLOCK +@rem // Copyright 2001 Sun Microsystems, Inc. +@rem // Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +@rem // All rights reserved. +@rem // END COPYRIGHT BLOCK +@rem // +@echo off +setlocal +set MCC_HOST=%1 +set MCC_PORT=%2 +if "%MCC_HOST%x"=="x" goto usage +if "%MCC_PORT%x"=="x" goto usage +rem +set MCC_USER= +if %3x==x goto nouser +set MCC_USER=-u %3 +echo MCC_USER = %MCC_USER% +:nouser +set MCC_PASSWORD= +if %4x==x goto nopass +set MCC_PASSWORD=-w %4 +:nopass +rem +set JARDIR=./jars +set JDK=%JARDIR%/classes.zip +set DS=%JARDIR%/ds40.jar +set ADMIN=%JARDIR%/admserv.jar +set KINGPIN=%JARDIR%/kingpin.jar +set SWING=%JARDIR%/swingall.jar +set LF=%JARDIR%/nmclf.jar +set LAYOUT=%JARDIR%/layout.jar +set LDAP=%JARDIR%/ldapjdk.jar +set BASE=o=netscaperoot +set CLASSPATH=%DS%;%KINGPIN%;%ADMIN%;%SWING%;%LAYOUT%;%LF%;%LDAP% +rem echo java com.netscape.management.client.console.Console -d %MCC_HOST% -p %MCC_PORT% %MCC_USER% %MCC_PASSWORD% -b %BASE% +java com.netscape.management.client.console.Console -d %MCC_HOST% -p %MCC_PORT% %MCC_USER% %MCC_PASSWORD% -b %BASE% +goto end + +:usage +echo Usage: mcc HOST PORT [[user] [password]] + +:end +endlocal + diff --git a/ldap/admin/src/key.rc b/ldap/admin/src/key.rc new file mode 100644 index 00000000..7568ac91 --- /dev/null +++ b/ldap/admin/src/key.rc @@ -0,0 +1,150 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +//Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_GETPATH DIALOG DISCARDABLE 0, 0, 293, 155 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "NETSCAPE KEY PAIR FILE GENERATION" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDE_PATH,93,110,159,13,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,39,130,50,14 + PUSHBUTTON "Cancel",IDCANCEL,193,129,50,14 + LTEXT "Welcome to the key pair file generator. With this program you can generate the public and private keys that your server uses for secure communications.Make sure that you enter the full pathname of the key file.", + IDC_STATIC,17,17,253,28 + LTEXT "First the server needs to know where to put the new key. You should NOT overwrite an existing key pair file ! Place the new key in a separate location. Make a note of the new key's location ! You will need it later when you request a certificate.", + IDC_STATIC,17,50,251,33 + LTEXT "Key File Location:",IDC_STATIC,17,113,63,8 + LTEXT "If you installed the server into the root c:\\Navgold, you can store the key file in c:\\Navgold\\Server\\<serverid>\\ssl\\key.db", + IDC_STATIC,17,87,251,16 +END + +IDD_GETPASSWORD DIALOG DISCARDABLE 0, 0, 293, 144 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "NETSCAPE KEY PAIR FILE PASSWORD" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDE_GETPASSWORD,98,104,159,13,ES_PASSWORD | + ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,45,125,50,14 + PUSHBUTTON "Cancel",IDCANCEL,190,123,50,14 + LTEXT "Finally, enter a password which will be used to encrypt the key pair file. You will use this password when starting up and shutting down your server.", + IDC_STATIC,18,24,253,20 + LTEXT "Note: Be sure to keep this password safe ! If you must write down the password, the physical safety of the recording is your responsibility.", + IDC_STATIC,18,50,251,19 + LTEXT "Password",IDC_STATIC,18,105,63,8 + LTEXT "The password must be at least 8 characters long, and must contain at least one non-alphabetic character in it. It should not be a word in any dictionary.", + IDC_STATIC,18,77,255,24 + LTEXT "A random seed has been successfully generated !!", + IDC_STATIC,18,4,246,15 +END + +IDD_GETPASSWORD2 DIALOG DISCARDABLE 0, 0, 265, 116 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "NETSCAPE KEY PAIR FILE PASSWORD" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDE_GETPASSWORD2,67,50,159,13,ES_PASSWORD | + ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,67,78,50,14 + PUSHBUTTON "Cancel",IDCANCEL,176,78,50,14 + LTEXT "Password",-1,10,54,50,8 + LTEXT "Reenter the password for verification:",-1,10,18,255,24 +END + +IDD_GETCERT DIALOG DISCARDABLE 0, 0, 293, 115 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "NETSCAPE KEY CERTIFICATE GENERATION" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,125,90,50,14 + LTEXT "Congratulations ! Your new key is in the file:", + IDC_STATIC,19,17,253,14 + LTEXT "The next step is to generate a certificate. Select the hyperlink ""Request or renew a certificate from the server manager.", + IDC_STATIC,19,60,251,22 + LTEXT "Static",IDC_KEYFILE,19,38,223,8 +END + +IDD_GETSEED DIALOG DISCARDABLE 0, 0, 301, 156 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "NETSCAPE RANDOM NUMBER SEED GENERATION" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Next a random seed must be generated to complete the creation of your key pair file. You have to provide mouse input for this to happen. Move your mouse continuously and randomly on the desktop to provide this input.", + IDC_STATIC,15,12,250,29 + LTEXT "On NT3.51 systems a progress bar will appear to inform you how much more random mouse input the program needs to generate its random seed. When enough input has been obtained from you, another dialog box will notify you.", + IDC_STATIC,15,48,259,25 + LTEXT "As you move the mouse, the location of the cursor is sampled at random intervals and this is added to a sample of a high frequency counter to generate the random seed. Click OK to begin.", + IDC_STATIC,15,83,256,33 + PUSHBUTTON "OK",IDOK,125,137,50,14 + LTEXT "This process could take from 30 seconds to a minute of continuous mouse input.", + IDC_STATIC,15,119,281,8 +END + +IDD_UPDATE DIALOG DISCARDABLE 0, 0, 185, 74 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Collecting Random User Input ....." +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Static",IDC_UPDATE,13,8,150,59 +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +///////////////////////////////////////////////////////////////////////////// +#endif // APSTUDIO_INVOKED + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/ldap/admin/src/latest_file.c b/ldap/admin/src/latest_file.c new file mode 100644 index 00000000..5a6be701 --- /dev/null +++ b/ldap/admin/src/latest_file.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 **/ +/*********************************************************************** +** +** NAME +** latest_file.c +** +** DESCRIPTION +** Creates a batch file which assigns the latest file matching a given +** pattern to the environment variable LATEST_FILE. For use in NT batch +** files. +** +** AUTHOR +** <rweltman@netscape.com> +** +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ + + +/* + * Given a pattern to match, creates a batch file with the latest full + * file name to set to LATEST_FILE. No file is created if there are no + * matching files. + */ +#if defined( _WIN32 ) +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <io.h> + + +int main (int argc, char **argv) +{ + char *szWildcardFileSpec; + char *szOutput; + char dir[1024]; + char latest[1024]; + char *dirEnd; + time_t latest_time = 0; + long hFile; + struct _finddata_t fileinfo; + FILE *fBatch; + + if ( argc < 3 ) { + fprintf( stderr, "Usage: %s PATTERN OUTPUTFILE\n", argv[0] ); + return 1; + } + + szWildcardFileSpec = argv[1]; + szOutput = argv[2]; + + /* Get directory part of path */ + strcpy( dir, szWildcardFileSpec ); + dirEnd = strrchr( dir, '\\' ); + if ( dirEnd != NULL ) { + *dirEnd = 0; + } + + /* Expand file specification */ + hFile = _findfirst( szWildcardFileSpec, &fileinfo); + if( hFile == -1 ) { + perror( "No matching files!" ); + return -1; + } + + sprintf( latest, "%s\\%s", dir, fileinfo.name ); + latest_time = fileinfo.time_create; + + while( _findnext( hFile, &fileinfo ) == 0 ) { + if ( fileinfo.time_create > latest_time ) { + sprintf( latest, "%s\\%s", dir, fileinfo.name ); + latest_time = fileinfo.time_create; + } + } + + _findclose( hFile ); + + /* create batch file */ + fBatch = fopen (szOutput, "w"); + if ( fBatch == NULL ) { + perror ("Unable to create batch file!"); + return 1; + } + fprintf( fBatch, "set LATEST_FILE=%s\n", latest ); + fclose (fBatch); + + return 0; +} +#endif /* ( XP_WIN32 ) */ diff --git a/ldap/admin/src/makemccvlvindexes b/ldap/admin/src/makemccvlvindexes new file mode 100644 index 00000000..a8e46efd --- /dev/null +++ b/ldap/admin/src/makemccvlvindexes @@ -0,0 +1,211 @@ +#!perl +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# makemccvlvindexes + +sub usage_and_exit +{ + print "makemccvlvindexes usage\n"; + print "\n"; + print "This script analyses an LDAP directory in order to create VLV indices which\n"; + print "could be configured to improve the performance of one-level searches.\n"; + print "This is principally to be used to tune the directory browsing feature\n"; + print "of the Mission Control Console.\n"; + print "\n"; + print "An LDAP client can only take advantage of these indices if it is itself\n"; + print "VLV enabled. See the following specification for full details.\n"; + print "\n"; + print "ftp://ftp.ietf.org/internet-drafts/draft-ietf-ldapext-ldapv3-vlv-00.txt\n"; + print "\n"; + print "Command Line Arguments\n"; + print "-? - help\n"; + print "-D rootdn - Provide a root DN. Default= '$rootdn'\n"; + print "-w password - Provide a password for the root DN.\n"; + print "-h host - Provide a host name. Default= '$host'\n"; + print "-p port - Provide a port. Default= '$port'\n"; + print "-t threshold - Provide a container subordinate threshold. Default= $threshold\n"; + print "-f filter - Provide a search filter. Default= '$vlvfilter'\n"; + print "-s sort - Provide a sort specification. Default='$vlvsort'\n"; + print "-n - Do the work, but don't create the indices\n"; + exit; +} + +# Initialise some things +$vlvfilter= "(objectclass=*)"; +$vlvsort= "sn givenname cn ou o"; +$rootdn= "cn= Directory Manager"; +$host= "localhost"; +$port= "389"; +$threshold= 1000; +$really_do_it= "1"; + +# Process the command line arguments +while( $arg = shift) +{ + if($arg eq "-?") + { + usage_and_exit(); + } + elsif($arg eq "-D") + { + $rootdn= shift @ARGV; + } + elsif($arg eq "-w") + { + $rootpw= shift @ARGV; + } + elsif($arg eq "-h") + { + $host= shift @ARGV; + } + elsif($arg eq "-p") + { + $port= shift @ARGV; + } + elsif($arg eq "-t") + { + $threshold= shift @ARGV; + } + elsif($arg eq "-f") + { + $vlvfilter= shift @ARGV; + } + elsif($arg eq "-s") + { + $vlvsort= shift @ARGV; + } + elsif($arg eq "-n") + { + $really_do_it= "0"; + } + else + { + print "$arg: Unknown command line argument.\n"; + } +} + +$ldapsearch= "ldapsearch -h $host -p $port"; +$ldapmodify= "ldapmodify -h $host -p $port -D \"$rootdn\" -w $rootpw"; + +if( $vlvfilter eq "" || + $vlvsort eq "" || + $rootdn eq "" || + $host eq "" || + $port eq "" || + $threshold eq "") +{ + print "Error: Need command line information..\n"; + usage_and_exit(); +} + +if( $rootpw eq "" ) +{ + print "Warning: No root DN password provided. Won't be able to add VLV Search and Index entries.\n"; +} + +# Tell the user what we're up to. +print "Searching all naming contexts on '$host:$port' for containers with more than $threshold subordinate entries\n"; + +# Read the naming contexts from the root dse +@namingcontexts= `$ldapsearch -s base -b \"\" \"objectclass=*\" namingcontexts`; + +# Get rid of the first line 'dn:' +shift @namingcontexts; + +# Foreach naming context... +foreach $nc (@namingcontexts) +{ + # Extract the base from the naming context + @base= split ' ', $nc; + shift @base; + + # Find all the containers + print "Searching naming context '@base' for containers.\n"; + @containers= `$ldapsearch -s subtree -b \"@base\" \"numsubordinates=*\" numsubordinates`; + chop @containers; + + # Foreach container + + while(@containers) + { + # <dn, count, blank> + $dn_line= shift @containers; + $count_line= shift @containers; + shift @containers; + + # Extract the count, and check it against the threshold + @count_array= split ' ', $count_line; + $count= @count_array[1]; + $dn= substr($dn_line,4); + print "Found container '$dn' with $count subordinates. "; + if($count > $threshold) + { + # We've found a container that should be indexed. + # Extract the DN and RDN of the container + $comma_position= (index $dn, ','); + if($comma_position== -1) + { + $rdn= $dn + } + else + { + $rdn= substr($dn, 0, $comma_position); + } + + # Tell the user what we're up to. + print "Adding VLV Search and Index entries.\n"; + + # Build the vlv search and index entries to be added. + $vlvsearch_name= "MCC $rdn"; + @vlvsearch= ( + "dn: cn=$vlvsearch_name, cn=config, cn=ldbm\n", + "objectclass: top\n", + "objectclass: vlvSearch\n", + "cn: $vlvsearch_name\n", + "vlvbase: $dn\n", + "vlvfilter: $vlvfilter\n", + "vlvscope: 1\n\n" ); + + $vlvindex_name= "SN $vlvsearch_name"; + @vlvindex= ( + "dn: cn=$vlvindex_name, cn=$vlvsearch_name, cn=config, cn=ldbm\n", + "objectclass: top\n", + "objectclass: vlvIndex\n", + "cn: $vlvindex_name\n", + "vlvsort: $vlvsort\n\n" ); + + @vlvnames = ( @vlvnames, "\"" . $vlvindex_name . "\""); + + if($really_do_it eq "1") + { + open(FD,"| $ldapmodify -a -c"); + print FD @vlvsearch; + print FD @vlvindex; + close(FD); + } + } + else + { + print "Too small.\n"; + } + } +} + +# Dump a script to actually create the indexes +if($really_do_it eq "1" && $#vlvnames > 0) +{ + print "\n"; + print "$#vlvnames VLV indices have been declared. Execute the following commands to build the index files.\n"; + print "\n"; + print "<instance-dir>\\stop\n"; + print "slapd db2index -f <instance-dir>\\config\\slapd.conf -V @vlvnames\n"; + print "<instance-dir>\\start\n"; +} + + diff --git a/ldap/admin/src/makevlvindex b/ldap/admin/src/makevlvindex new file mode 100644 index 00000000..ef68798c --- /dev/null +++ b/ldap/admin/src/makevlvindex @@ -0,0 +1,109 @@ +#!perl +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# makevlvindex + +sub usage_and_exit +{ + print "makevlvindex [options]\n"; + print "\n"; + print "Options:\n"; + print "-? - help\n"; + print "-D rootdn - Provide a root DN. Default= '$rootdn'\n"; + print "-w password - Provide a password for the root DN.\n"; + print "-h host - Provide a host name. Default= '$host'\n"; + print "-p port - Provide a port. Default= '$port'\n"; + print "-sn search_name - RDN of the vlvSearch parent entry.\n"; + print "-in index_name - RDN for the vlvIndex child entry.\n"; + print "-s sort - Provide a sort specification. Default='$vlvsort'\n"; + exit; +} + +# Initialise some things +$vlvsearch_name= ""; +$vlvindex_name= ""; +$vlvsort= "sn givenname cn ou o"; +$rootdn= "cn=Directory Manager"; +$host= "localhost"; +$port= "389"; + +# Process the command line arguments +while( $arg = shift) +{ + if($arg eq "-?") + { + usage_and_exit(); + } + elsif($arg eq "-D") + { + $rootdn= shift @ARGV; + } + elsif($arg eq "-w") + { + $rootpw= shift @ARGV; + } + elsif($arg eq "-h") + { + $host= shift @ARGV; + } + elsif($arg eq "-p") + { + $port= shift @ARGV; + } + elsif($arg eq "-sn") + { + $vlvsearch_name= shift @ARGV; + } + elsif($arg eq "-in") + { + $vlvindex_name= shift @ARGV; + } + elsif($arg eq "-s") + { + $vlvsort= shift @ARGV; + } + else + { + print "$arg: Unknown command line argument.\n"; + } +} + +$ldapmodify= "ldapmodify -h $host -p $port -D \"$rootdn\" -w $rootpw"; + +if( $vlvsearch_name eq "" || + $vlvindex_name eq "" || + $vlvsort eq "" || + $rootdn eq "" || + $host eq "" || + $port eq "") +{ + print "Error: Need command line information..\n"; + usage_and_exit(); +} + +if( $rootpw eq "" ) +{ + print "Warning: No root DN password provided. Won't be able to add VLV Search and Index entries.\n"; +} + +# Tell the user what we're up to. +print "Adding VLV Search entry.\n"; + +@vlvindex= ( + "dn: cn=$vlvindex_name, cn=$vlvsearch_name, cn=config, cn=ldbm\n", + "objectclass: top\n", + "objectclass: vlvIndex\n", + "cn: $vlvindex_name\n", + "vlvsort: $vlvsort\n\n" ); + +open(FD,"| $ldapmodify -a -c"); +print FD @vlvindex; +close(FD); + + diff --git a/ldap/admin/src/makevlvsearch b/ldap/admin/src/makevlvsearch new file mode 100644 index 00000000..45616e02 --- /dev/null +++ b/ldap/admin/src/makevlvsearch @@ -0,0 +1,138 @@ +#!perl +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# makevlvsearch + +sub usage_and_exit +{ + print "makevlvsearch [options]\n"; + print "\n"; + print "May be used to create just a vlvSearch entry, or to create\n"; + print "both a vlvSearch and vlvIndex entry.\n"; + print "\n"; + print "Options:\n"; + print "-? - help\n"; + print "-D rootdn - Provide a root DN. Default= '$rootdn'\n"; + print "-w password - Provide a password for the root DN.\n"; + print "-h host - Provide a host name. Default= '$host'\n"; + print "-p port - Provide a port. Default= '$port'\n"; + print "-b scope - Provide a scope. 1 or 2. Default= '$vlvscope'\n"; + print "-f filter - Provide a search filter. Default= '$vlvfilter'\n"; + print "-sn search_name - RDN of the vlvSearch parent entry.\n"; + print "-in index_name - RDN for the vlvIndex child entry.\n"; + print "-s sort - Provide a sort specification. Default='$vlvsort'\n"; + exit; +} + +# Initialise some things +$vlvsearch_name= ""; +$vlvindex_name= ""; +$vlvscope= "2"; +$vlvfilter= "(objectclass=*)"; +$vlvsort= ""; +$rootdn= "cn=Directory Manager"; +$host= "localhost"; +$port= "389"; + +# Process the command line arguments +while( $arg = shift) +{ + if($arg eq "-?") + { + usage_and_exit(); + } + elsif($arg eq "-D") + { + $rootdn= shift @ARGV; + } + elsif($arg eq "-w") + { + $rootpw= shift @ARGV; + } + elsif($arg eq "-h") + { + $host= shift @ARGV; + } + elsif($arg eq "-p") + { + $port= shift @ARGV; + } + elsif($arg eq "-b") + { + $vlvscope= shift @ARGV; + } + elsif($arg eq "-f") + { + $vlvfilter= shift @ARGV; + } + elsif($arg eq "-s") + { + $vlvsort= shift @ARGV; + } + elsif($arg eq "-sn") + { + $vlvsearch_name= shift @ARGV; + } + elsif($arg eq "-in") + { + $vlvindex_name= shift @ARGV; + } + else + { + print "$arg: Unknown command line argument.\n"; + } +} + +$ldapmodify= "ldapmodify -h $host -p $port -D \"$rootdn\" -w $rootpw"; + +if( $vlvfilter eq "" || + $vlvscope eq "" || + $vlvsearch_name eq "" || + $rootdn eq "" || + $host eq "" || + $port eq "") +{ + print "Error: Need command line information..\n"; + usage_and_exit(); +} + +if( $rootpw eq "" ) +{ + print "Warning: No root DN password provided. Won't be able to add VLV Search and Index entries.\n"; +} + +# Tell the user what we're up to. +print "Adding VLV Search and Index entries.\n"; + +# Build the vlv search and index entries to be added. +@vlvsearch= ( + "dn: cn=$vlvsearch_name, cn=config, cn=ldbm\n", + "objectclass: top\n", + "objectclass: vlvSearch\n", + "cn: $vlvsearch_name\n", + "vlvbase: $dn\n", + "vlvfilter: $vlvfilter\n", + "vlvscope: $vlvscope\n\n" ); + +@vlvindex= ( + "dn: cn=$vlvindex_name, cn=$vlvsearch_name, cn=config, cn=ldbm\n", + "objectclass: top\n", + "objectclass: vlvIndex\n", + "cn: $vlvindex_name\n", + "vlvsort: $vlvsort\n\n" ); + +open(FD,"| $ldapmodify -a -c"); +print FD @vlvsearch; +if( not($vlvindex_name eq "" || $vlvsort eq "")) +{ + print FD @vlvindex; +} +close(FD); + + diff --git a/ldap/admin/src/migrateInstance b/ldap/admin/src/migrateInstance new file mode 100644 index 00000000..0480ec47 --- /dev/null +++ b/ldap/admin/src/migrateInstance @@ -0,0 +1,549 @@ +#!perl +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# migrate an old server instance to a new server instance + +BEGIN { + $| = 1; + # print CGI header + print "Content-type: text/plain\n\n"; + require 'uname.lib'; + + $isNT = -d '\\'; + $PATHSEP = $isNT ? "\\" : "/"; + # get the server root directory + $sroot = $ENV{'NETSITE_ROOT'}; + $exitCode = 0; + @INC = ( '.', '../../../admin/admin/bin' ); + grep { s@/@\\@g } @INC if $isNT; + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + $slapdExecName = $isNT ? 'slapd.exe' : 'ns-slapd'; + $nullFile = $isNT ? 'nul' : '/dev/null'; + # NT needs quotes around some things unix doesn't + $quote = $isNT ? "\"" : ""; + if ($isNT) { + # we have to pass batch files directly to the NT command interpreter + $com_spec = $ENV{ComSpec}; + if (!$com_spec) { + $com_spec = $ENV{COMSPEC}; + } + if (!$com_spec || ! -f $com_spec) { + # find the first available command interpreter + foreach $drive (c..z) { + $com_spec = "$drive:\\winnt\\system32\\cmd.exe"; + last if (-f $com_spec); + $com_spec = undef; + } + if (! $com_spec) { + # punt and pray + $com_spec = 'c:\winnt\system32\cmd.exe'; + } + } + $os = "WINNT"; + } else { + $os = &uname("-s"); + } + + if ( ($os eq "AIX") || ($os eq "HP-UX") ) { + $sigChildHandler = 'sigChildHandler'; + } +} + +sub mySystem { + my $cmd = $_[0]; + # the system {$cmd} avoids some NT shell quoting problems if the $cmd + # needs to be quoted e.g. contains spaces; the map puts double quotes + # around the arguments on NT which are stripped by the command + # interpreter cmd.exe; but don't quote things which are already quoted + my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @_; + my $rc = 0; + if ($cmd =~ /[.](bat|cmd)$/) { + # we have to pass batch files directly to the NT command interpreter + $cmd = $com_spec; +# print "system $cmd /c \"@fixargs\"\n"; + $rc = system {$cmd} '/c', "\"@fixargs\""; + } else { +# print "system $cmd \"@fixargs\"\n"; + $rc = system {$cmd} @fixargs; + } + + return $rc; +} + +sub getNextEntry { + my $fh = shift; + my @entry = (); # an array of strings, each string is 1 attr/value pair + my $line = ""; + while (($line = <$fh>) && !($line =~ /^$/)) { # entry is terminated by EOF or empty line34 + chop $line; + if ($line =~ /^\s/) { # line begins with a single space char + $entry[@entry-1] .= $'; # add continuation to line + } else { + push @entry, $line; + } + } + return @entry; +} + +sub runAndIgnoreOutput { + my $cmd = shift; + print "\n."; + open(RUNCMD, "${quote}$cmd${quote} 2>&1 |") or die "Error: could not run $cmd: $!"; + print "\n." ; + sleep(1); # allow pipe to fill with data + print "\n." ; + while (<RUNCMD>) { +# print; + } + my $code = close(RUNCMD); +# print "runAndIgnore: code=$code status=$?\n"; + return $?; +} + +sub printEntry { + my $fh = shift; + foreach (@_) { + print $fh $_, "\n"; + } + print $fh "\n"; +} + +sub reportAndExit { + my $now_time = gmtime; + print "END migration at ", $now_time, " GMT\n"; + print "Exit status is ", $exitCode, "\n"; + if ($? == 0 && $exitCode == 0) { + print "NMC_STATUS: 0\n"; + } else { + # not necessary to show this + print '$?=', $?+0, ' $!=', $!+0, ' $exitCode=', $exitCode, "\n"; + print shift, "\n"; + print "NMC_STATUS: $exitCode\n"; + } + + print "###MIGRATION FINISHED###\n"; + + exit($exitCode); +} + +# put stderr on stdout +open(STDERR, ">&STDOUT" ); +# use unbuffered output +select(STDERR); +$| = 1; +select(STDOUT); +$| = 1; +$TRACELEVEL = 0 ; + +sub sigChildHandler { +# print "in sig child handler\n"; +# print "args = @_\n"; +} + +$SIG{__DIE__} = 'exit'; +$SIG{'QUIT'} = 'exit'; +$SIG{'INT'} = 'exit'; +$SIG{'TERM'} = 'exit'; +# AIX needs a SIGCHILD handler for pipes +if (defined($sigChildHandler)) { + $SIG{'CHLD'} = $sigChildHandler; + $SIG{'CLD'} = $sigChildHandler; +} + +# the atexit handler +END { + $! = 0; + $? = $exitCode; + if ($exitCode == 0) { + # just give a report if the operation was successfull + &reportAndExit; } +} + +# process the CGI input +use Cgi; + +if (($sroot =~ m#/$#) || ($sroot =~ m#\\$#)) { + chop $sroot; +} + +if (($cgiVars{'oldServerRoot'} =~ m#/$#) || ($cgiVars{'oldServerRoot'} =~ m#\\$#)) { + chop $cgiVars{'oldServerRoot'}; +} + +$instanceDir = $sroot . $PATHSEP . 'slapd-' . $cgiVars{'servid'}; + +######################################################################################### +# get the Directory Server version +# For the moment the migration works only from 4.x version to 5.0 version +# As for as previous versions are concerned we don't migrate neither 1.x nor 3.x +######################################################################################### + +($oldVersion, $oldMinor) = &getVersion($cgiVars{'oldServerRoot'}); +print "\n\noldVersion: $oldVersion, oldMinor: $oldMinor" ; + + +if ($oldVersion < 4) { + # migration of version under 4 is not supported + # abort the use of the migration script up to 5.1 + $exitCode = 1 ; + die "\n\n\n\n\n\n\nThe migration of a $oldVersion.x directory instance is not available." . + "\n\nINFORMATION" . + "\nYou can also migrate a 4.x directory server." . + "\nIt must be executed manually through a command line." . + "\nPlease refer to the product documentation to get usage and prerequisites\n"; +} +else { + # print begin message + $now_time = gmtime; + print "BEGIN migration at: ", $now_time, " GMT\n"; + $oldSlapdConf = $cgiVars{'oldServerRoot'} . $PATHSEP . 'slapd-' . + $cgiVars{'oldServerName'} . $PATHSEP . 'config' . $PATHSEP . + 'slapd.conf'; + + open(OLDSLAPDCONF, $oldSlapdConf) or + die "Error: could not open old config file $oldSlapdConf: $!"; + while(<OLDSLAPDCONF>) { + chop; + if (/^port\s+/i) { + if (! $cgiVars{'servport'}) { + $cgiVars{'servport'} = $'; + $old_port = $' ; + $Cgi::CONTENT .= '&servport=' . $'; + if ($ENV{'QUERY_STRING'}) { + $ENV{'QUERY_STRING'} .= '&servport=' . $'; + } + } + } elsif (/^rootdn\s+/i) { + if (! $cgiVars{'rootdn'}) { + ($value = $') =~ s/^[\"]//; + # remove leading " + $value =~ s/[\"]$//; + # remove trailing " + $cgiVars{'rootdn'} = $value; + $Cgi::CONTENT .= '&rootdn=' . $value; + if ($ENV{'QUERY_STRING'}) { + $ENV{'QUERY_STRING'} .= '&rootdn=' . $value; + } + } + } + } + close(OLDSLAPDCONF); + + $testDir = $instanceDir . $PATHSEP . 'config'; + + # check if it's necessary or not to stop the old server + if (-d $testDir) { + printTrace("\ninstance already exists \n",3) ; + # the instance already exists + $DSEldif = $instanceDir. $PATHSEP . 'config' . $PATHSEP . 'dse.ldif'; + open(DSELDIF, $DSEldif) or + die "Error: could not open old config file $DSEldif: $!"; + while(<DSELDIF>) { + chop; + if (/^nsslapd-port:\s+/i) { + $cgiVars{'servport'} = $'; + $Cgi::CONTENT .= '&servport=' . $'; + if ($ENV{'QUERY_STRING'}) { + $ENV{'QUERY_STRING'} .= '&servport=' . $'; + } + } elsif (/^nsslapd-rootdn:\s+/i) { + ($value = $') =~ s/^[\"]//; + # remove leading " + $value =~ s/[\"]$//; + # remove trailing " + $cgiVars{'rootdn'} = $value; + $Cgi::CONTENT .= '&rootdn=' . $value; + if ($ENV{'QUERY_STRING'}) { + $ENV{'QUERY_STRING'} .= '&rootdn=' . $value; + } + } + } + close(DSELDIF); + if ($old_port eq $cgiVars{'servport'}) { + # need to stop the old instance + if ($cgiVars{'shutdown_old_server'}) { + &stopServer($cgiVars{'oldServerRoot'}, 'slapd-' . $cgiVars{'oldServerName'}); + } + } + &startServer(); + } + else { + # need to stop the old instance + if ($cgiVars{'shutdown_old_server'}) { + &stopServer($cgiVars{'oldServerRoot'}, 'slapd-' . $cgiVars{'oldServerName'}); + } + } + + @cgi = keys(%cgiVars); + printTrace("\ncgi: @cgi",3); + printTrace("\npwd: $cgiVars{'rootpw'}, rootdn: $cgiVars{'rootdn'}, port: $cgiVars{'servport'}, + old_instance -o: $cgiVars{'oldServerRoot'}$PATHSEPslapd-$cgiVars{'oldServerName'}, + new_instance -n: $sroot$PATHSEPslapd-$cgiVars{'servid'}",3) ; + + # if the instance does not exist, create it + if (! -d $testDir) { + print "Creating the new instance . . .\n"; + printTrace("\nbefore instance creation\n",3) ; + # call the instance creation program; we should already be in the same + # directory; if we are being called as a CGI, index will parse the CGI + # parameters, otherwise, it will use the command line parameters + if ($isNT) { + $myprog = "ds_create.exe"; + } else { + $myprog = "./ds_create"; + } + printTrace("\nafter instance creation\n",3) ; + + # since we already parsed stdin, we need to pass it to the instance creation + # CGI somehow; fortunately, we saved the old contents of stdin in the + # $Cgi::CONTENT, so just pipe that into our CGI + # print "executing $myprog @ARGV\n"; + open(INDEX, "|$myprog @ARGV") or die "Error: system($myprog, @ARGV): $!"; + sleep(1); # allow prog to init stdin read buffers + print INDEX $Cgi::CONTENT, "\n"; + close INDEX; + + $exitCode = $?; + if ($exitCode != 0) { + die "Error: could not create new instance: $!"; + } + + + } else { + } + + + printTrace("\nBefore instance created test\n",3) ; + + chdir("$sroot${PATHSEP}bin${PATHSEP}slapd${PATHSEP}admin${PATHSEP}bin"); + + # Now that the new instance is created, merge in the old configuration data + # $cgiVars{'oldServerRoot'} will contain the full path of the old server + # root directory + # $cgiVars{'oldServerName'} will contain the old instance name + $myscript = "migrateInstance5"; + # print "executing $myscript $sroot $cgiVars{'oldServerRoot'} $cgiVars{'servid'} $cgiVars{'oldServerName'} $savedLdif\n"; + + @args = ($, $myscript, '-p', $cgiVars{'servport'}, '-D', $cgiVars{'rootdn'}, '-w', $cgiVars{'rootpw'}, '-o', + $cgiVars{'oldServerRoot'} . $PATHSEP . 'slapd-' . $cgiVars{'oldServerName'}, '-n', + $sroot . $PATHSEP . 'slapd-' . $cgiVars{'servid'}, '-noinput'); + $exitCode = &mySystem(@args); + die "Error: @args: $!" if ($exitCode != 0); + } + + +sub startServer { + my $errLog = $instanceDir . $PATHSEP . 'logs' . $PATHSEP . 'errors'; + # emulate tail -f + # if the last line we see does not contain "slapd started", try again + my $done = 0; + my $started = 0; + my $code = 0; + my $lastLine = ""; + my $timeout = time + 60; # 1 minute + my $startCmd = $instanceDir . $PATHSEP . 'start' . $script_suffix; + if (! -f $startCmd) { + $startCmd = $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix; + } + $code = &mySystem($startCmd); + open(IN, $errLog) or die "Could not open error log $errLog: $!"; + my $pos = tell(IN); + while (($done == 0) && (time < $timeout)) { + for (; ($done == 0) && ($_ = <IN>); $pos = tell(IN)) { + $lastLine = $_; +# print; + # the server has already been started and shutdown once . . . + if (/slapd started\./) { + $started++; + if ($started == 2) { + $done = 1; + } + # sometimes the server will fail to come up; in that case, restart it + } elsif (/Initialization Failed/) { +# print "Server failed to start: $_"; + $code = &mySystem($startCmd); + # sometimes the server will fail to come up; in that case, restart it + } elsif (/exiting\./) { +# print "Server failed to start: $_"; + $code = &mySystem($startCmd); + } + } + if ($lastLine =~ /PR_Bind/) { + # server port conflicts with another one, just report and punt + print $lastLine; + print "This server cannot be started until the other server on this\n"; + print "port is shutdown.\n"; + $done = 1; + } + if ($done == 0) { + # rest a bit, then . . . + sleep(2); + # . . . reset the EOF status of the file desc + seek(IN, $pos, 0); + } + } + close(IN); + + if ($started < 2) { + $! = $code; +# $now = time; +# if ($now > $timeout) { +# print "Possible timeout: timeout=$timeout now=$now\n"; +# } + die "Error: could not start server: $!"; + } + + return 0; +} + +sub stopServer { + my $root = shift; + my $name = shift; + $maxStopIterations = 60; + print "Shutting down server $name . . .\n"; + $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop' . $script_suffix . $quote; + if (! -f $stopCmd) { + $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop-slapd' . $script_suffix . $quote; + } + + if (! -f $stopCmd) { + # no stop command, probably a 1.X system; for NT, we'll try net stop + # for unix, we'll get the pid and kill it + if ($isNT) { + $stopCmd = 'net stop ' . $name; + } else { + # see if there is a pid file + $pidfile = $root . $PATHSEP . $name . $PATHSEP . 'logs' . + $PATHSEP . 'pid'; + if (open(PIDFILE, $pidfile)) { + chomp($pid = <PIDFILE>); + close(PIDFILE); + while ($maxStopIterations-- && !$exitCode) { + $exitCode = kill(15, $pid); + } + $stopCmd = undef; + } + } + } + + # keep looping until the stop cmd returns an error code, which usually + # means that what ever we want to stop is stopped, or some other error + # occurred e.g. permission, or no such service + $exitCode = &runAndIgnoreOutput($stopCmd); +# print "stopServer: exitCode=$exitCode\n"; + while ($stopCmd && $maxStopIterations-- && !$exitCode) { + $exitCode = &runAndIgnoreOutput($stopCmd); +# print "stopServer: exitCode=$exitCode\n"; + } + + if (!$maxStopIterations) { + print "Warning: could not shutdown the old server: $!\n"; + } + + sleep(10) if ($isNT); + + $exitCode = 0; +} + +############################################################################# +# print message error to the user standard output. + +sub printTrace { + + my $Msg = shift ; + my $level = shift ; + if ($level <= $TRACELEVEL) { + print($Msg); + } + +} + +############################################################################# + +sub getVersion { + my $rootDir = shift; + my $version = 0; + my $minor = 0; + my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}"; + # get the current directory so we can go back to it + my $curdir = &getCwd; + + # find the slapd executable + $prog = $rootDir . $progDir . $slapdExecName; + if (! -f $prog) { + $prog = $rootDir . $progDir2 . $slapdExecName; + if (-f $prog && $isNT) { + # if slapd is in bin/slapd and we're on NT, just assume version 1; + # apparently, slapd.exe doesn't like the -v argument . . . + return ( '1', $minor ); + } + } + + # read the old version from the old slapd program + chdir($rootDir . $progDir) or + die "Could not chdir to $rootDir${progDir}: $!: "; + open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or + die "Could not run slapd program $prog: $!"; + sleep(1); # allow some data to accumulate in the pipe +# print "Output from $prog -v:\n"; + while (<F>) { + print; + if (/^Netscape-Directory\/(\d+)\.(\d+)/) { + $version = $1; + $minor = $2; + last; + } + elsif (/^Netscape-Directory\(restriced-mode\)\/(\d+)\.(\d+)/) { + $version = $1; + $minor = $2; + last; + } + } + $code = close(F); +# print "$prog returned code=$code status=$?\n"; + + # done determining versions; go back to orig directory + chdir($curdir) or die "Could not chdir to $curdir: $!: "; + + $version == 0 and + die "Could not determine version of the directory server in $rootDir: "; + + return ( $version, $minor ); +} + + +############################################################################# + +sub getCwd { + my $command = $isNT ? "cd" : "/bin/pwd"; + open(PWDCMD, "$command 2>&1 |") or + die "Error: could not execute $command: $!"; + # without the following sleep, reading from the pipe will + # return nothing; I guess it gives the pwd command time + # to get some data to read . . . + sleep(1); + my $curdir; + while (<PWDCMD>) { + if (!$curdir) { + chomp($curdir = $_); + } + } + my $code = close(PWDCMD); +# if ($code || $?) { +# print "$command returned code=$code status=$? dir=$curdir\n"; +# } +# print "getCwd curdir=\[$curdir\]\n"; + return $curdir; +} + +############################################################################# +############################################################################# +############################################################################# diff --git a/ldap/admin/src/migrateLocalDB b/ldap/admin/src/migrateLocalDB new file mode 100644 index 00000000..3dfeb106 --- /dev/null +++ b/ldap/admin/src/migrateLocalDB @@ -0,0 +1,265 @@ +#!perl +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# Migrate a SuiteSpot 2.X or 3.X localdb to a 4.0 directory server + +BEGIN { + $isNT = -d '\\'; + $PATHSEP = $isNT ? "\\" : "/"; + @INC = ( '.', '../../../admin/admin/bin' ); + grep { s@/@\\@g } @INC if $isNT; + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + # NT needs quotes around some things unix doesn't + $quote = $isNT ? "\"" : ""; +} + +sub getNextEntry { + my $fh = shift; + my @entry = (); # an array of strings, each string is 1 attr/value pair + my $line = ""; + while (($line = <$fh>) && !($line =~ /^$/)) { # entry is terminated by EOF or empty line34 + chop $line; + if ($line =~ /^\s/) { # line begins with a single space char + $entry[@entry-1] .= $'; # add continuation to line + } else { + push @entry, $line; + } + } + return @entry; +} + +# given a string of the form string:value, return everything to the left of the : +sub getAttrName { + my $s = shift; + $s =~ s/[:].*$//; + return $s; +} + +sub printEntry { + my $fh = shift; + foreach (@_) { + print $fh $_, "\n"; + } + print $fh "\n"; +} + +sub usage { + print 'Usage: perl migrateLocalDb <userdb> <new suffix> [<new instance>]', "\n"; + print "\t", '<userdb> - full path to the userdb directory to migrate', "\n"; + print "\t", ' e.g. /usr/netscape/suitespot3/userdb', "\n"; + print "\t", '<new suffix> - new suffix e.g. dc=example,dc=com; may be empty', "\n"; + print "\t", '<new instance> - full path to the destination instance', "\n"; + print "\t", ' e.g. /usr/netscape/server4/slapd-foo', "\n"; + print "The new instance is optional. If not given, the local db will\n"; + print "be converted to the LDIF file userdb/localdb.ldif, but\n"; + print "it will not be added to the database of the new instance.\n"; +} + +sub sigDieHandler { + print @_, "\n"; + print "\n"; + &usage(); + print "\n"; + print "NMC_STATUS: ", 0+$!, "\n"; + exit $!; +} + +$SIG{__DIE__} = 'sigDieHandler'; + +# check for command line arguments +if (@ARGV > 0) { + $localDBPath = $ARGV[0]; + $newSuffix = $ARGV[1]; + $instanceDir = $ARGV[2]; + $bindDN = $ARGV[3]; + $bindPwd = $ARGV[4]; + # the perl executable should be in server root/install/ + $relPath = '/install/'; + $relPath =~ s#/#\\#g if ($isNT); + ($sroot = $) =~ s#$relPath.*$##; +} elsif ($ENV{'REQUEST_METHOD'}) { + $| = 1; + # print CGI header + print "Content-type: text/plain\n\n"; + + # process the CGI input + use Cgi; + + # get the server root directory + $sroot = $ENV{'NETSITE_ROOT'}; + + $localDBPath = $cgiVars{'localDBPath'}; + $newSuffix = $cgiVars{'newSuffix'}; + $instanceDir = $cgiVars{'instanceDir'}; + $bindDN = $cgiVars{'bindDN'}; + $bindPwd = $cgiVars{'bindPwd'}; +} else { + die ""; +} + +# this is a table of attributes which have DN syntax +%dnAttrs = ( + 'aliasedobjectname', "\n", + 'member', "\n", + 'owner', "\n", + 'roleoccupant', "\n", + 'seealso', "\n", + 'dn', "\n", + 'uniquemember', "\n", + 'creatorsname', "\n", + 'modifiersname', "\n", + 'manager', "\n", + 'documentauthor', "\n", + 'secretary', "\n", + 'associatedname', "\n", + 'ditredirect', "\n", + 'targetdn', "\n", + 'newrdn', "\n", + 'newsuperior', "\n", + 'lastmodifiedby', "\n", + 'replicaroot', "\n", + 'replicabinddn', "\n", + 'cirreplicaroot', "\n", + 'cirbinddn', "\n", + 'vlvbase', "\n", + 'netscapemdsuffix', "\n", + 'changelog', "\n", + 'obsoletedbydocument', "\n", + 'obsoletesdocument', "\n", + 'reciprocalnaminglink', "\n", + 'updatedbydocument', "\n", + 'updatesdocument', "\n" +); + +print "Begin local db migration\n"; + +# see if the parameters are valid +# check localdb path +die "Error: could not find the local db $localDBPath" if (! -d $localDBPath); +# check suffix? + +# get the old server root directory +# step 1: convert the local db to an ldif file +# lookup the old suffix from the lcache.conf +$lcache = $localDBPath . $PATHSEP . 'ldap' . $PATHSEP . 'config' . $PATHSEP . + 'lcache.conf'; +open(LCACHE, "$lcache") or die "Error: could not open config file $lcache"; +while (<LCACHE>) { + chop; + if (/^suffix\s+/i) { + $oldSuffix = $'; + $oldSuffix =~ s/^[\"]//; + # trim leading " + $oldSuffix =~ s/[\"]$//; + # trim trailing " + print "The old suffix is $oldSuffix\n"; + } +} +close(LCACHE); + +print "Converting the local db to LDIF . . .\n"; +# run the ldapsearch -C command +$cmddir = $localDBPath . $PATHSEP . 'ldap' . $PATHSEP . 'tools'; +@cmd = ($quote . $cmddir . $PATHSEP . 'ldapsearch' . $quote, '-C', + "${quote}$lcache${quote}", + '-s', 'sub', '-b', "\"$oldSuffix\"", '"objectclass=*"'); +chdir($cmddir) or die "Error: could not change to directory $cmddir"; +open(READCMD, "${quote}@cmd${quote}|") or die "Error: could not execute @cmd"; +if ($instanceDir) { + $outputFile = $instanceDir . $PATHSEP . 'ldif' . $PATHSEP . 'localdb.ldif'; +} else { + $outputFile = $localDBPath . $PATHSEP . 'localdb.ldif'; +} + +open(OUT, ">$outputFile") or die "Error: could not write file $outputFile"; +while (@entry = getNextEntry(\*READCMD)) { + # for each entry, replace the old suffix with the new one; if there + # was no old suffix, just append the new one to the DN value attrs + if ($newSuffix && $newSuffix ne '""') { + if ($oldSuffix && $oldSuffix ne '""') { + grep { s/$oldSuffix/$newSuffix/ig } @entry; + } else { + for ($ii = 0; $ii < @entry; ++$ii) { + $name = &getAttrName($entry[$ii]); + if ($dnAttrs{lc($name)}) { + $entry[$ii] .= ", $newSuffix"; + } + } + } + } + + printEntry(\*OUT, @entry); +} +close(READCMD); +close(OUT); + +if ($? != 0) { + die "Error: could not read local db from $localDBPath"; +} elsif (! -s $outputFile) { + die "Error: converted local db is empty"; +} + +# check instance dir + +if ($instanceDir) { + if (! -d $instanceDir) { + # use may have given relative path + $instanceDir = $sroot . $PATHSEP . $instanceDir; + die "Error: could not find the instance dir $instanceDir in server root $sroot" + if (! -d $instanceDir); + } + +# step 2: load the converted LDIF file into the target directory server +# if the bindDN and password were given, attempt to use ldif2ldap, otherwise, +# shutdown the server and use ldif2db + + if ($bindDN && $bindPwd) { + } else { + print "Shutting down the server . . .\n"; + # shutdown the server + $stopCmd = $quote . $instanceDir . $PATHSEP . 'stop-slapd' . $script_suffix . $quote; + system($stopCmd); + print "Warning: could not shutdown the server in $instanceDir.\nThe server may already be down." if ($? != 0); + sleep(10); # give the server time to shutdown + + # add the new suffix to the slapd.ldbm.conf + if ($newSuffix && $newSuffix ne '""') { + print "Adding suffix $newSuffix . . .\n"; + $slc = $instanceDir . $PATHSEP . 'config' . $PATHSEP . 'slapd.ldbm.conf'; + open(SLC, ">>$slc") or + print "Warning: could not add the suffix $newSuffix: import may fail.\n"; + print SLC "suffix\t\"$newSuffix\"\n"; + close(SLC); + } + + print "Importing the local db LDIF file . . .\n"; + # import the LDIF file + @impCmd = ($quote . $instanceDir . $PATHSEP . 'ldif2db' . $quote, + '-C', '-i', "${quote}$outputFile${quote}"); + system(@impCmd); + die "Error: could not import LDIF file $outputFile" if ($? != 0); + + print "Restarting the server . . .\n"; + # start the server + $startCmd = $quote . $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix . $quote; + system($startCmd); + print "Warning: could not restart the server in $instanceDir" if ($? != 0); + } + + print "Finished. The local db has been imported to $instanceDir.\n"; +} else { + print "Finished. The local db has been written to $outputFile.\n"; +} + +if (%cgiVars) { + print "NMC_STATUS: 0\n"; +} + +exit 0; diff --git a/ldap/admin/src/migratePwdFile b/ldap/admin/src/migratePwdFile new file mode 100644 index 00000000..45b90629 --- /dev/null +++ b/ldap/admin/src/migratePwdFile @@ -0,0 +1,90 @@ +#!perl +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +# +# Convert an old password.txt file into the new pin.txt format +# This script requires a single argument which is the directory and +# server instance prefix of the two files (e.g. /servers/alias/slapd-foo) +# +# ISSUES: +# This code sets the mode of the created file to 660 (allows suitespot +# group access. Should it also set the user and group values? Where +# should they come from? +# +BEGIN { + $isNT = -d "\\"; + $PS = $isNT ? "\\" : "/"; +} + +$sroot = $ARGV[0]; +$prefix = $ARGV[1]; + +# +# create the names for the old (password) and new (pin) files +# +$pwdfile = "${prefix}-password.txt"; +$pinfile = "${prefix}-pin.txt"; + +if (-f $pwdfile && ! -f $pinfile) { + open(PWDFILE, $pwdfile) || die "Cannot open password file: $pwdfile\n"; + + my $count = 0; + my $pin; + while(<PWDFILE>) { + chomp; # trim new line + + if ($count == 0) { + $pin = $_; + } + + $count = $count+1; + } + close PWDFILE; + + if ($count == 0) { + die "No password found in password file\n"; + } elsif ($count != 1) { + print "Extra lines found in password file\n"; + } + + open(PINFILE, ">$pinfile") || die "Cannot create pin file: $pinfile\n"; + print PINFILE "Software (Internal) Token:$pin\n"; + close PINFILE; + chmod 0660, $pinfile; + + # set the ownership of the file; should be the same as the slapd user id + if (! $isNT) { + $confFile = "$sroot${PS}$prefix${PS}config${PS}slapd.conf"; + open(CONF, $confFile) or die "Error: cannot open $confFile: $!"; + while (<CONF>) { + if (/^localuser\s+/i) { + chomp($newuser = $'); + last; + } + } + close(CONF); + if (!$newuser) { + $confFile = "$sroot${PS}shared${PS}config${PS}ssusers.conf"; + open(SSUSERS, $confFile) or + die "Error: could not open $confFile: $!"; + while (<SSUSERS>) { + chop; + if (/^SuiteSpotUser\s+/i) { + $newuser = $'; + last; + } + } + close(SSUSERS); + } + if ($newuser) { + chown $newuser, $pinfile; + } + } +} + +exit 0; diff --git a/ldap/admin/src/migrateTo4 b/ldap/admin/src/migrateTo4 new file mode 100644 index 00000000..862bfff2 --- /dev/null +++ b/ldap/admin/src/migrateTo4 @@ -0,0 +1,1581 @@ +#!perl +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +BEGIN { + require 'uname.lib'; + $isNT = -d '\\'; + @INC = ( '.', '../../../admin/admin/bin' ); + grep { s@/@\\@g } @INC if $isNT; + $PATHSEP = $isNT ? '\\' : '/'; + # NT needs quotes around some things unix doesn't + $quote = $isNT ? "\"" : ""; + + # If this variable is set, all file/directory creation will make sure the mode + # and ownership of the destination is the same as the source + $PRESERVE = 1 if (!$isNT); + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + if ($isNT) { + $os = "WINNT"; + } else { + $os = &uname("-s"); + } + + if ($isNT) { + # we have to pass batch files directly to the NT command interpreter + $com_spec = $ENV{ComSpec}; + if (!$com_spec) { + $com_spec = $ENV{COMSPEC}; + } + if (!$com_spec || ! -f $com_spec) { + # find the first available command interpreter + foreach $drive (c..z) { + $com_spec = "$drive:\\winnt\\system32\\cmd.exe"; + last if (-f $com_spec); + $com_spec = undef; + } + if (! $com_spec) { + # punt and pray + $com_spec = 'c:\winnt\system32\cmd.exe'; + } + } + } + + # dll suffix for shared libraries in old instance; note that the dll suffix + # may have changed for the new instance e.g. AIX now uses .so + if ( $os eq "AIX" ) { + $dll_suffix = "_shr.a"; + } + elsif ( $os eq "HP-UX" ) { + $dll_suffix = ".sl"; + } + elsif ( $os eq "WINNT" ) { + $dll_suffix = ".dll"; + } + else { + $dll_suffix = ".so"; + } + $slapdExecName = $isNT ? 'slapd.exe' : 'ns-slapd'; + # if this flag is set, we will migrate the 3.0 and 3.1 databases + # by doing a db2ldif -> ldif2db; if this is not set, we will just + # copy the directories; right now, we cannot copy the directories, + # because the database format has changed for 4.0, and the new + # code does not recognize the old db format. It is hoped that it + # will by RTM . . . + $convertToLDIF = 1; + select STDERR; + $| = 1; + select STDOUT; + $| = 1; + + # if the old value for dbcachesize is less than this, make it this + $MIN_DBCACHESIZE = '500000'; +} + +sub getCwd { + my $command = $isNT ? "cd" : "/bin/pwd"; + open(PWDCMD, "$command 2>&1 |") or + die "Error: could not execute $command: $!"; + # without the following sleep, reading from the pipe will + # return nothing; I guess it gives the pwd command time + # to get some data to read . . . + sleep(1); + my $curdir; + while (<PWDCMD>) { + if (!$curdir) { + chomp($curdir = $_); + } + } + my $code = close(PWDCMD); +# if ($code || $?) { +# print "$command returned code=$code status=$? dir=$curdir\n"; +# } +# print "getCwd curdir=\[$curdir\]\n"; + return $curdir; +} + +sub fixBinaryAttr { + my $foo = shift; + $foo =~ s/;binary//ig; + return $foo; +} + +$type = "slapd"; +$root = $ARGV[0]; +$oldDir = $ARGV[1]; +$newname = $ARGV[2]; +$oldname = $ARGV[3]; +$savedMDLdif = $ARGV[4]; +$savedLdif = $ARGV[5]; +$sieName = $ARGV[6]; +$secPwd = $ARGV[7]; + +if (($root =~ m#/$#) || ($root =~ m#\\$#)) { + chop $root; +} + +if (($oldDir =~ m#/$#) || ($oldDir =~ m#\\$#)) { + chop $oldDir; +} + +sub basename { + my @list = split(/[\\\/]/, $_[0]); + return $list[@list - 1]; +} + +# this is used to strip html formatting from output to user +sub localprint { + # arg 1 is string to print + # arg 2 is beginning html directive + # arg 3 is closing html directive + my ($str, $begin, $end) = @_; + print $str; +} + +# this is used to run the system() call, capture exit and signal codes, +# and die() upon badness; the first argument is a directory to change +# dir to, if any, and the rest are passed to system() +sub mySystem { + my $rc = &mySystemNoDie(@_); + my ($dir, @args) = @_; + if ($rc == 0) { +# success + } elsif ($rc == 0xff00) { + die "Error executing @args: error code $rc: $!"; + } elsif ($rc > 0x80) { + $rc >>= 8; + die "Error executing @args: error code $rc: $!"; + } else { + if ($rc & 0x80) { + $rc &= ~0x80; + } + die "Error executing @args: received signal $rc: $!"; + } + + # usually won't get return value + return $rc; +} + +# This version does not die but just returns the error code +sub mySystemNoDie { + my ($dir, @args) = @_; + if ($dir && ($dir ne "")) { + chdir($dir) or die "Could not change directory to $dir: $!"; + } + my $cmd = $args[0]; + # the system {$cmd} avoids some NT shell quoting problems if the $cmd + # needs to be quoted e.g. contains spaces; the map puts double quotes + # around the arguments on NT which are stripped by the command + # interpreter cmd.exe; but don't quote things which are already quoted + my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @args; + my $rc = 0; + if ($cmd =~ /[.](bat|cmd)$/) { + # we have to pass batch files directly to the NT command interpreter + $cmd = $com_spec; +# print "system $cmd /c \"@fixargs\"\n"; + $rc = 0xffff & system {$cmd} '/c', "\"@fixargs\""; + } else { +# print "system $cmd @fixargs\n"; + $rc = 0xffff & system {$cmd} @fixargs; + } + return $rc; +} + +$serverHome = "$root${PATHSEP}$type-$newname"; + +$oldHome = "$oldDir${PATHSEP}slapd-$oldname"; + +# these are the default values used by the 4.0 installer +$DEFAULT_CHANGELOG_DIR = $serverHome . $PATHSEP . 'logs' . $PATHSEP . 'changelogdb'; +$DEFAULT_CHANGELOG_SUFFIX = "cn=changelog"; + +# get some information from the new slapd.conf file +open(INPUT, "$serverHome${PATHSEP}config${PATHSEP}slapd.conf") or + die "Could not open file $serverHome${PATHSEP}config${PATHSEP}slapd.conf"; +while (<INPUT>) { + if (/^port\s+/i) { chomp($newport = $'); } + elsif (/^localhost\s+/i) { chomp($newlocalhost = $'); } + elsif (/^localuser\s+/i) { chomp($newuser = $'); } +} +close INPUT; + +# get some information from the new slapd.ldbm.conf file +open(INPUT, "$serverHome${PATHSEP}config${PATHSEP}slapd.ldbm.conf") or + die "Could not open file $serverHome${PATHSEP}config${PATHSEP}slapd.ldbm.conf"; +while (<INPUT>) { + if (/^directory\s+[\"]?(.*?)[\"]?\s*$/i) { + # " + $newDbDir = $1; + # paths are stored in unix format in the config files . . . + $newDbDir =~ s#/#\\#g if ($isNT); + } +} +close INPUT; + +# get some information from the old slapd.conf file +open(INPUT, "$oldHome${PATHSEP}config${PATHSEP}slapd.conf") or + die "Could not open file $oldHome${PATHSEP}config${PATHSEP}slapd.conf"; +while (<INPUT>) { + if (/^changelogdir\s+[\"]?(.*?)[\"]?\s*$/i) { + # " + $oldChangeLogDir = $1; + # paths are stored in unix format in the config files . . . + $oldChangeLogDir =~ s#/#\\#g if ($isNT); + } + elsif (/^changelogsuffix\s+[\"]?(.*?)[\"]?\s*$/i) { + # " + $oldChangeLogSuffix = $1; + } + elsif (/^directory\s+[\"]?(.*?)[\"]?\s*$/i) { + # " + $oldDbDir = $1; + # paths are stored in unix format in the config files . . . + $oldDbDir =~ s#/#\\#g if ($isNT); + } + elsif (/^localuser\s+/i) { chomp($olduser = $'); } + elsif (/^encryption-alias\s+/i) { chomp($encryption_alias = $'); } + # the user may have given us a network mounted old home directory, but in the + # old instance's config files, the root directory referred to is usually + # a local directory. For example, suppose there is an automounter map for + # hosts which maps onto /h e.g. /h/oldhost would contain all directories + # exported via NFS. Similarly, for NT, you could do \\oldhost\c to look + # at the C: drive on the old host. Or the user may have network mounted + # the old server root some other way. Anyway, we need to determine what + # the old server root was local to the original host because that is what + # will be referred to it the old config files. So, we look at the errorlog + # directive in slapd.conf and use whatever comes before the slapd-oldname + elsif (/^errorlog\s+[\"]?(.*)$type-$oldname/i) { + # there may be leading " + chop($realOldDir = $1); + } +} +close INPUT; + +if (! $realOldDir) { + $realOldDir = $oldDir; +} + +$realOldHome = $realOldDir . $PATHSEP . $type . '-' . $oldname; + +# the oldDbDir is stored as a local dir, but we may need a network dir +($networkDbDir = $oldDbDir) =~ s/^$realOldDir/$oldDir/ig; + +# list of standard plugins configured out of the box in version 3 +# all of these paths are in unix format . . . +$oldLibDir = lc("$realOldDir/lib/"); +$oldConfDir = lc("$realOldHome/config/"); +$oldLogsDir = lc("$realOldHome/logs/"); +$oldLibDir =~ s#\\#/#g if ($isNT); +$oldConfDir =~ s#\\#/#g if ($isNT); +$oldLogsDir =~ s#\\#/#g if ($isNT); + +# note that all of these should be lower case, since NT does not distinguish case +# and we don't really care about case for plugin directives anyway . . . +%stdPlugins = ( + "plugin syntax \"${oldLibDir}syntax-plugin${dll_suffix}\" cis_init", "\n", + "plugin syntax \"${oldLibDir}syntax-plugin${dll_suffix}\" ces_init", "\n", + "plugin syntax \"${oldLibDir}syntax-plugin${dll_suffix}\" bin_init", "\n", + "plugin syntax \"${oldLibDir}syntax-plugin${dll_suffix}\" tel_init", "\n", + "plugin syntax \"${oldLibDir}syntax-plugin${dll_suffix}\" int_init", "\n", + "plugin syntax \"${oldLibDir}syntax-plugin${dll_suffix}\" dn_init", "\n", + "plugin matchingrule \"${oldLibDir}liblcoll${dll_suffix}\" orderingrule_init ${quote}${oldConfDir}slapd-collations.conf$quote", "\n", + "plugin database \"${oldLibDir}libback-ldbm${dll_suffix}\" ldbm_back_init", "\n", + "plugin postoperation ${quote}${oldLibDir}referint-plugin${dll_suffix}${quote} referint_postop_init 0 ${quote}${oldLogsDir}referint${quote} member uniquemember owner seealso", "\n", + "plugin postoperation ${quote}${oldLibDir}referint-plugin${dll_suffix}${quote} referint_postop_init 0 ${quote}${oldLogsDir}referint${quote} 0 member uniquemember owner seealso", "\n", + "plugin preoperation ${quote}${oldLibDir}libntsynch${dll_suffix}${quote} libntsynch_plugin_preop_init", "\n", + "plugin postoperation ${quote}${oldLibDir}libntsynch${dll_suffix}${quote} libntsynch_plugin_postop_init", "\n" +); + +# list of standard indexes configured out of the box in version 3 +%stdIndex = ( + 'index aci pres', "\n", + 'index cn pres,eq,sub', "\n", + 'index sn pres,eq,sub', "\n", + 'index givenName pres,eq,sub', "\n", + 'index mail pres,eq,sub', "\n", + 'index telephoneNumber pres,eq,sub', "\n", + 'index ntUserDomainId pres,eq,sub', "\n", + 'index uid eq', "\n", + 'index changenumber eq', "\n", + 'index uniquemember eq', "\n", + 'index member eq', "\n", + 'index owner eq', "\n", + 'index seeAlso eq', "\n" +); + +# These are files included into slapd.conf, slapd.dynamic-ldbm.conf and +# slapd.ldbm.conf by default in earlier releases. We use this hash to +# determine if there are user defined files which have been included +# into the slapd.conf e.g. for user defined attributes, object classes, +# indexes, etc. +%stdIncludes = ( + "${oldConfDir}slapd.at.conf", "\n", + "${oldConfDir}slapd.oc.conf", "\n", + "${oldConfDir}ns-schema.conf", "\n", + "${oldConfDir}ns-globopt.conf", "\n", +); + + +# list of parameters that we don't care about; these are usually just parameters +# which hold paths relative to this instance and server root, which change anyway +%oldParametersToSkip = ( + 'userat', "\n", # use the new one + 'useroc', "\n", # use the new one + 'instancedir', "\n", # must be the new one + 'dynamicconf', "\n", # use the new one + 'directory', "\n", # use the new one + 'access', "\n", # obsolete + 'defaultaccess', "\n", # obsolete + 'security-path', "\n", # obsolete + 'localuser', "\n", # use the newly configured suitespot user + 'port', "\n", # the new port must already be set either as determined from + # the old config or because we are migrating into the MC + # instance and cannot change the port number + 'rootdn', "\n", # the new rootdn must already be set either as determined from + # the old config or because we are migrating into the MC + # instance and cannot change it + 'rootpw', "\n", # the new rootpw must already be set either as determined from + # the old config or because we are migrating into the MC + # instance and cannot change it +); + +# list of old ldbm specific parameters. These parameters may be present in the +# old slapd.conf, but have been moved to the new slapd.ldbm.conf +%oldLdbmParameters = ( + 'database', "\n", + 'lookthroughlimit', "\n", + 'mode', "\n", + 'cachesize', "\n", + 'dbcachesize', "\n", + 'allidsthreshold', "\n", + 'parentcheck', "\n", +); + +# list of old slapd.conf parameters which have been moved to the new dse.ldif +%oldDSEParameters = ( + 'encryption-alias', "\n", + 'sslclientauth', "\n" +); + +($oldversion,$oldminor) = &getVersion($oldDir); +($newversion,$newminor) = &getVersion($root); + +# if there was no old user specified +if (! $isNT && ! $olduser) { + # get the olduid and oldgid from doing a stat of the db directory + ($olduid, $oldgid) = (stat($networkDbDir))[4..5]; +} +# convert the user names to numeric uids +if ($PRESERVE) { + if (! $olduid && $olduser) { + ($login,$pass,$olduid,$oldgid) = getpwnam($olduser); + } + ($login,$pass,$newuid,$newgid) = getpwnam($newuser); +} + +# copy the old config files +©Dir("$oldHome${PATHSEP}config", "$serverHome${PATHSEP}migrate_config"); + +print "Migrating log files . . .\n"; +# copy the log files +$srcdir = "$oldHome${PATHSEP}logs"; +opendir(LOGDIR, $srcdir) or + die "Error: could not open log file dir $srcdir : $!"; +foreach (readdir(LOGDIR)) { + if (! /[.][.]?/ && -f "$srcdir${PATHSEP}$_") { + ©BinFile("$srcdir${PATHSEP}$_", + "$serverHome${PATHSEP}logs${PATHSEP}${_}.migrate"); + } +} +closedir(LOGDIR); + +# copy the ssl directory +©Dir("$oldHome${PATHSEP}ssl", "$serverHome${PATHSEP}ssl"); + +# copy the cert db and key files +if ( -d "$oldDir${PATHSEP}alias" && $encryption_alias ) { + $aliasDir = "$root${PATHSEP}alias"; + if (! -d $aliasDir) { + mkdir($aliasDir, 0750); + } + $adminDir = $root . $PATHSEP . 'bin' . $PATHSEP . 'admin' . $PATHSEP . + 'admin' . $PATHSEP . 'bin'; + print "Migrating the key and certificate databases . . .\n"; + mySystem($adminDir, $adminDir . $PATHSEP . 'sec-migrate', + $oldDir, $encryption_alias, $root, $sieName, $secPwd); + # copy the old password file + if (-f "$oldDir${PATHSEP}alias${PATHSEP}$encryption_alias-password.txt") { + ©BinFile( + "$oldDir${PATHSEP}alias${PATHSEP}$encryption_alias-password.txt", + "$aliasDir${PATHSEP}$type-$newname-password.txt" + ); + if ($newversion >= 4 && $newminor >= 1) { + # need to convert the old format to new pin format + print "Converting password file to new pin format . . .\n"; + $script = "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}admin${PATHSEP}bin${PATHSEP}migratePwdFile"; + mySystem($aliasDir, $, $script, $root, "$type-$newname"); + } + } + + # get the new key/cert db filenames + opendir(CERTDIR, $aliasDir) or + die "Error: could not open cert dir $aliasDir: $!"; + foreach (readdir(CERTDIR)) { + if (/^$sieName/i) { + if (/[-]cert/) { + $newcertdb = $_; + } elsif (/[-]key/) { + $newkeydb = $_; + } + } + } + closedir(CERTDIR); +} + +$needAclUpg = 0; +if ($oldversion == 1) { + $needAclUpg = 1; + $convertToLDIF = 1; # always need this for conversion from 1.X db +} + +# Copy/Convert ldif files in ldif/ +print "Migrating old LDIF files . . .\n"; +©Ldif; + +if ($convertToLDIF) { + # Converting database + print "Migrating database to LDIF . . .\n"; + $oldLdif = "$oldHome${PATHSEP}ldif${PATHSEP}old.ldif"; + &db2ldif($networkDbDir, $oldLdif); + if ($needAclUpg) { + print "Converting ACLs in old data . . .\n"; + &mySystem("$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server", + "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}" . + "aclupg$exe_suffix", '-d', '-i', + $oldLdif, '-o', + "$oldHome${PATHSEP}ldif${PATHSEP}aclupg.ldif"); + unlink($oldLdif); + rename("$oldHome${PATHSEP}ldif${PATHSEP}aclupg.ldif", $oldLdif); + } + chown $newuid, $newgid, $oldLdif if (!$isNT); +# copy the changelogdb directory +# how to handle a 1.0 change log? +# ©Dir($changelogdir, "$serverHome${PATHSEP}changelogdb") if ($changelogdir); +} + +# Compare each configuration file against its default version. If it has changed, +# notify the user that the file has changed and will need to be checked by the +# user. This should be safe to do because there should be no path information +# stored in these conf files, which are just schema stuff. +print "Migrating configuration files . . .\n"; +$origFilePath = "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}install${PATHSEP}version${oldversion}"; +$srcdir = "$serverHome${PATHSEP}migrate_config"; +opendir(CONFDIR, $srcdir) or + die "Error: could not open migrated config dir $srcdir: $!"; +foreach $file (readdir(CONFDIR)) { + $origFile = $origFilePath . $file; + if (-f $origFile) { + $diffs = &diff("$srcdir${PATHSEP}$file", $origFile); + if ($diffs) { + print "File $srcdir${PATHSEP}$file could not be migrated\n"; + print "because it is different than\n"; + print "the standard installed version. You will need to check this\n"; + print "file and make sure its changes are compatible with the new\n"; + print "directory server. Here are the differences:\n"; + print $diffs, "\n"; + } else { +# print "No changes to old config file $srcdir${PATHSEP}$file\n"; + } + } +} +closedir(CONFDIR); + +# make a backup of the current user_at and user_oc files, and copy the old ones +# into the config directory + +©BinFile("$serverHome${PATHSEP}config${PATHSEP}slapd.user_at.conf", + "$serverHome${PATHSEP}config${PATHSEP}slapd.user_at.conf.bak"); +©BinFile("$serverHome${PATHSEP}config${PATHSEP}slapd.user_oc.conf", + "$serverHome${PATHSEP}config${PATHSEP}slapd.user_oc.conf.bak"); + +if (-f "$serverHome${PATHSEP}migrate_config${PATHSEP}slapd.user_at.conf") { + ©AndEditTextFile( + "$serverHome${PATHSEP}migrate_config${PATHSEP}slapd.user_at.conf", + "$serverHome${PATHSEP}config${PATHSEP}slapd.user_at.conf", + \&fixBinaryAttr); +} + +if (-f "$serverHome${PATHSEP}migrate_config${PATHSEP}slapd.user_oc.conf") { + ©AndEditTextFile( + "$serverHome${PATHSEP}migrate_config${PATHSEP}slapd.user_oc.conf", + "$serverHome${PATHSEP}config${PATHSEP}slapd.user_oc.conf", + \&fixBinaryAttr); +} + +# parse the parameters from the old configuration files and put them into +# the new configuration files +&fixConf("$serverHome${PATHSEP}migrate_config${PATHSEP}slapd.conf", + "$serverHome${PATHSEP}migrate_config${PATHSEP}slapd.dynamic_ldbm.conf", + "$serverHome${PATHSEP}migrate_config${PATHSEP}dse.ldif", + "$serverHome${PATHSEP}config${PATHSEP}slapd.conf", + "$serverHome${PATHSEP}config${PATHSEP}slapd.ldbm.conf", + "$serverHome${PATHSEP}config${PATHSEP}dse.ldif"); + +# copy in old data and any data we wanted to save +if ($convertToLDIF) { + print "Migrating old database to new database . . .\n"; + &manyLdif2db($savedMDLdif, $oldLdif, $savedLdif); + unlink $savedMDLdif, $savedLdif; +} + +if ($oldChangeLogDir && -e $oldChangeLogDir) { + print "Migrating changelog database . . .\n"; + my $realDir = $oldChangeLogDir; + $realDir =~ s/^$realOldDir/$oldDir/ig; + if ($convertToLDIF) { + $srcDir = $realDir; + $destDir = $DEFAULT_CHANGELOG_DIR; + $srcLDIF = "$oldHome${PATHSEP}ldif${PATHSEP}changelog.ldif"; + $destLDIF = "$serverHome${PATHSEP}ldif${PATHSEP}changelog.ldif"; + mkdir( $destDir , 0755 ) if !( -e $destDir); + # Converting database + if ( !$isNT && $newuser ) { + chown($newuid, $newgid, $destDir); + } + &other_db2ldif($srcDir, $srcLDIF); + if ($needAclUpg) { + &mySystem("$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server", + "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" . + "${PATHSEP}aclupg$exe_suffix", '-d', '-i', + $srcLDIF, '-o', $destLDIF); + } else { + ©BinFile($srcLDIF, $destLDIF); + } + &other_ldif2db($destLDIF, $destDir, 'slapd.ldbm.conf', + "suffix \"$oldChangeLogSuffix\""); + } else { + # the dir is stored as a local dir, but we may need a network dir here + ©Dir($realDir, $DEFAULT_CHANGELOG_DIR, '\.share$'); + } +} + +if ($convertToLDIF) { + # Convert the db backup, bak/ + print "Migrating database backups . . .\n"; + ©Bak; +} else { + # just copy the directories over + ©Dir($networkDbDir, "$serverHome${PATHSEP}db", '\.share$'); + ©Dir("$oldHome${PATHSEP}bak", "$serverHome${PATHSEP}bak", '\.share$'); +} + +if (-f $oldLdif) { + unlink($oldLdif); +} + +exit(0); + +############# END OF PROCESSING; SUBROUTINES FOLLOW + +# This subroutine merges the old and new source files into the new destination file +sub fixConf { + my $oldsrc = shift; + my $oldldbmsrc = shift; + my $olddseldif = shift; + my $newsrc = shift; + my $newldbmsrc = shift; + my $newdseldif = shift; + + # read the old conf file into a hash table + open( OLDSRC, $oldsrc ) || + die "Can't open $oldsrc: $!: "; + LINE: while ( <OLDSRC> ) { + if (/^\s*#/) { # skip comments + next LINE; + } + if (/^\s*$/) { # skip blank lines + next LINE; + } elsif (/^plugin/i) { + chomp($_); + if (! &isAStandardPlugin($_)) { + push @badPlugins, $_; + } + } elsif (/^index/i) { + chomp($_); + if (! &isAStandardIndex($_)) { + push @newIndex, $_; + } + } elsif (/^include\s+[\"]?(.*?)[\"]?\s*$/i) { + # strip leading and trailing " + if (! &isAStandardInclude($1)) { + push @newInclude, $1; + } + } elsif (/^dbcachesize\s+[\"]?(.*?)[\"]?\s*$/i) { + # strip leading and trailing " + $param = 'dbcachesize'; + $value = $1; + if ($value < $MIN_DBCACHESIZE) { + $value = $MIN_DBCACHESIZE; + } + + if ($oldLdbmParameters{lc($param)}) { + $oldldbmhash{lc($param)} = $value; + } else { + $oldhash{lc($param)} = $value; + + } + } elsif (/^errorlog/i) { + $oldhash{'errorlog-logging-enabled'} = "on"; + } elsif (/^accesslog/i) { + $oldhash{'accesslog-logging-enabled'} = "on"; + } elsif (/^auditlog/i) { + $oldhash{'auditlog-logging-enabled'} = "on"; + } elsif (/^replogfile/i) { + # replogfile was only used in 1.X, and it had no suffix + $oldhash{'changelogdir'} = $DEFAULT_CHANGELOG_DIR; + $oldhash{'changelogsuffix'} = $DEFAULT_CHANGELOG_SUFFIX; + } elsif (/^changelogdir/i) { + # force use of default + $oldhash{'changelogdir'} = $DEFAULT_CHANGELOG_DIR; + } elsif (/^\s*(\S+)\s+[\"]?(.*?)[\"]?\s*$/i) { + # strip leading and trailing " + $param = $1; + $value = $2; + if ($oldParametersToSkip{lc($param)}) { + next LINE; + } elsif (lc($param) eq 'suffix') { + if (lc($value) cmp 'cn=schema') { + $oldsuffix{lc($value)} = $value; + } + } else { + if ($oldLdbmParameters{lc($param)}) { + $oldldbmhash{lc($param)} = $value; + } elsif ($oldDSEParameters{lc($param)}) { + if (lc($param) eq 'encryption-alias') { + if ($newcertdb) { + $olddsehash{'nscertfile'} = "alias/$newcertdb"; + } else { + $olddsehash{'nscertfile'} = "alias/$type-$newname-cert.db"; + } + if ($newkeydb) { + $olddsehash{'nskeyfile'} = "alias/$newkeydb"; + } else { + $olddsehash{'nskeyfile'} = "alias/$type-$newname-key.db"; + } + } elsif (lc($param) eq 'sslclientauth') { + $olddsehash{'nssslclientauth'} = $value; + } else { + $olddsehash{lc($param)} = $value; + } + } elsif (($param eq 'passwdhash') && + ((! $value) || ($value eq ""))) { + # 3.X used "" as an alias for "clear" + $oldhash{lc($param)} = 'clear'; + } else { + $oldhash{lc($param)} = $value; + } + } + } + } + close(OLDSRC); + + $oldhash{'errorlog-logging-enabled'} = "off" + if (! $oldhash{'errorlog-logging-enabled'}); + $oldhash{'accesslog-logging-enabled'} = "off" + if (! $oldhash{'accesslog-logging-enabled'}); + $oldhash{'auditlog-logging-enabled'} = "off" + if (! $oldhash{'auditlog-logging-enabled'}); + + # read the old ldbm conf file into a hash table; note that there may not be + # one, so don't complain + open( OLDSRC, $oldldbmsrc ); + LINE2: while ( <OLDSRC> ) { + if (/^\s*#/) { # skip comments + next LINE2; + } + if (/^\s*$/) { # skip blank lines + next LINE2; + } + if (/^index/i) { + chomp($_); + if (! &isAStandardIndex($_)) { + push @newIndex, $_; + } + next LINE2; + } + if (/^plugin/i) { + chomp($_); + if (! &isAStandardPlugin($_)) { + push @badLdbmPlugins, $_; + } + next LINE2; + } + if (/^include\s+/i) { + chomp($inc = $'); + $inc =~ s/\"//g; + # strip " characters + if (! &isAStandardInclude($inc)) { + push @newLdbmInclude, $inc; + } + next LINE2; + } + if (/^dbcachesize\s+[\"]?(.*?)[\"]?\s*$/i) { + # strip leading and trailing " + $param = 'dbcachesize'; + $value = $1; + if ($value < $MIN_DBCACHESIZE) { + $value = $MIN_DBCACHESIZE; + } + + $oldldbmhash{lc($param)} = $value; + next LINE2; + } + + if (/^\s*(\S+)\s+[\"]?(.*?)[\"]?\s*$/) { + # strip leading and trailing " + $param = $1; + $value = $2; + if ($oldParametersToSkip{lc($param)}) { + next LINE2; + } elsif (lc($param) eq 'suffix') { + if (lc($value) cmp 'cn=schema') { + $oldsuffix{lc($value)} = $value; + } + } else { + $oldldbmhash{lc($param)} = $value; + } + } + } + close(OLDSRC); + + # read the old dse.ldif file into a hash table; note that there may not be + # one, so don't complain + open(OLDSRC, $olddseldif); + while ( <OLDSRC> ) { + chomp($_); + if ( /^passwordchange:\s*/i ) { + if ($' eq "must") { + $oldhash{'pw_change'} = "on"; + $oldhash{'pw_must_change'} = "on"; + } elsif ($' eq "may") { + $oldhash{'pw_change'} = "on"; + $oldhash{'pw_must_change'} = "off"; + } else { + $oldhash{'pw_change'} = "off"; + $oldhash{'pw_must_change'} = "off"; + } + } elsif ( /^passwordchecksyntax:\s*/i ) { + if ($' > 0) { + $oldhash{'pw_syntax'} = "on"; + } else { + $oldhash{'pw_syntax'} = "off"; + } + } elsif ( /^passwordminlength:\s*/i ) { + $oldhash{'pw_minlength'} = $'; + } elsif ( /^passwordexp:\s*/i ) { + if ($' > 0) { + $oldhash{'pw_exp'} = "on"; + } else { + $oldhash{'pw_exp'} = "off"; + } + } elsif ( /^passwordmaxage:\s*/i ) { + $oldhash{'pw_maxage'} = $'; + } elsif ( /^passwordwarning:\s*/i ) { + $oldhash{'pw_warning'} = $'; + } elsif ( /^passwordkeephistory:\s*/i ) { + if ($' > 0) { + $oldhash{'pw_history'} = "on"; + } else { + $oldhash{'pw_history'} = "off"; + } + } elsif ( /^passwordinhistory:\s*/i ) { + $oldhash{'pw_inhistory'} = $'; + } elsif ( /^passwordlockoutduration:\s*/i ) { + $oldhash{'pw_lockduration'} = $'; + } elsif ( /^passwordlockout:\s*/i ) { + if ($' > 0) { + $oldhash{'pw_lockout'} = "on"; + } else { + $oldhash{'pw_lockout'} = "off"; + } + } elsif ( /^passwordmaxfailure:\s*/i ) { + $oldhash{'pw_maxfailure'} = $'; + } elsif ( /^passwordunlock:\s*/i ) { + if ($' > 0) { + $oldhash{'pw_unlock'} = "on"; + } else { + $oldhash{'pw_unlock'} = "off"; + } + } elsif ( /^passwordresetduration:\s*/i ) { + $oldhash{'pw_resetfailurecount'} = $'; + } + } + close(OLDSRC); + + open(NEWSRC, $newsrc ) || die "Can't open $newsrc: $!: "; + open(NEWDEST, ">$newsrc.tmp" ) || die "Can't create $newsrc.tmp: $!: "; + while ( <NEWSRC> ) { + # make sure the dynamicconf parameter is the last one in the file + if (/^dynamicconf/i) { + # print the parameters which exist in the old file but do not + # exist in the new file; these are the parameters we have not + # deleted from oldhash + print NEWDEST "#These additional parameters have been migrated\n"; + foreach $param (sort keys %oldhash) { + if (lc($param) eq 'passwdhash') { + $pwhash = $oldhash{lc($param)}; + # if the old value was not set, don't set the new value either + # just have the server use the default value + if ($pwhash && $pwhash ne "" && $pwhash ne '""') { + print NEWDEST 'pw_storagescheme', "\t", $pwhash, "\n"; + } + } elsif (lc($param) eq 'ntsynchusessl') { + print NEWDEST 'NTSynchUseSSL', "\t", $oldhash{lc($param)}, "\n"; + } else { + print NEWDEST $param, "\t", "\"$oldhash{lc($param)}\"", + "\n"; + } + } + print NEWDEST "#End of additional migrated parameters\n\n"; + # use the temp one for now until we have the real one in place, then + # we will change this back + print NEWDEST "dynamicconf\t\"$newldbmsrc.tmp\"\n"; + } elsif (/^\s*#/) { + print NEWDEST $_; + } elsif (/^include/ && @newInclude) { + my $newConfDir = $serverHome . '/' . 'config' . '/'; + $newConfDir =~ s#\\#/#g if ($isNT); + print NEWDEST "# These non standard includes were migrated:\n"; + print "These non standard includes were migrated:\n"; + while (@newInclude) { + my $oldPath = shift @newInclude; + # oldPath is a local path; we need a network path here because + # we will be copying the file + $oldPath =~ s/^$realOldDir/$oldDir/ig; + my $base = &basename($oldPath); + my $newone = $newConfDir . $base; + # convert to new path + print NEWDEST "include ", $quote, $newone, $quote, "\n"; + print $newone, "\n"; + # now, change path separators back to the correct ones for + # the os + $oldPath =~ s#/#\\#g if ($isNT); + $newone =~ s#/#\\#g if ($isNT); + ©AndEditTextFile($oldPath, $newone, \&fixBinaryAttr); + } + print NEWDEST "# end of migrated includes\n"; + print "Be sure to check the new slapd.conf file to make sure the order\n"; + print "is correct and there are no conflicts with new config files,\n"; + print "object classes, attributes, etc.\n"; + print NEWDEST $_; + } elsif (/^\s*(\S+)\s+[\"]?(.*?)[\"]?\s*$/) { + $param = $1; + $value = $2; + # see if the parameter is set in the old config file + if ($oldhash{lc($param)}) { + # only set the parameter if the old value is different than + # the new value + if ($value cmp $oldhash{lc($param)}) { + print NEWDEST "#This parameter was migrated: the original value was $value\n"; + print NEWDEST $param, "\t", "\"$oldhash{lc($param)}\"", "\n"; + } else { + print NEWDEST $_; + } + delete $oldhash{lc($param)}; + } else { + # just print the parameter + print NEWDEST $_; + } + } else { + print NEWDEST $_; + } + } + close (NEWSRC); + + # print the bad plugins, commented out, at the end of the file + if (@badPlugins) { + print NEWDEST "#The following non standard plugins were detected:\n"; + print "The following non standard plugins were detected:\n"; + foreach (@badPlugins) { + print NEWDEST "#", $_, "\n"; + print $_, "\n"; + } + print NEWDEST "#These plugins will probably need to be recompiled for this release\n"; + print "These plugins will probably need to be recompiled for this release\n"; + print NEWDEST "#of directory server, or at the very least, reconfigured.\n"; + print "of directory server, or at the very least, reconfigured.\n"; + } + + close( NEWDEST ); + + open(NEWSRC, $newldbmsrc ) || die "Can't open $newldbmsrc: $!: "; + open(NEWDEST, ">$newldbmsrc.tmp" ) || die "Can't create $newldbmsrc.tmp: $!: "; + while ( <NEWSRC> ) { + if (/^\s*#/) { + print NEWDEST $_; + } elsif (/^include/ && @newLdbmInclude) { + my $newConfDir = $serverHome . '/' . 'config' . '/'; + $newConfDir =~ s#\\#/#g if ($isNT); + print NEWDEST "# These non standard ldbm includes were migrated:\n"; + print "These non standard includes were migrated:\n"; + while (@newLdbmInclude) { + my $oldPath = shift @newInclude; + # oldPath is a local path; we need a network path here because + # we will be copying the file + $oldPath =~ s/^$realOldDir/$oldDir/ig; + my $base = &basename($oldPath); + my $newone = $newConfDir . $base; + # convert to new path + print NEWDEST "include ", $quote, $newone, $quote, "\n"; + print $newone, "\n"; + # now, change path separators back to the correct ones for + # the os + $oldPath =~ s#/#\\#g if ($isNT); + $newone =~ s#/#\\#g if ($isNT); + ©BinFile($oldPath, $newone); + } + print NEWDEST "# end of migrated includes\n"; + print "Be sure to check the new slapd.ldbm.conf file to make sure the order\n"; + print "is correct and there are no conflicts with new config files,\n"; + print "object classes, attributes, etc.\n"; + print NEWDEST $_; + } elsif (/^\s*(\S+)\s+[\"]?(.*?)[\"]?\s*$/) { + # strip " characters + $param = $1; + $value = $2; + if (lc($param) eq 'suffix') { + if ($oldsuffix{lc($value)}) { + delete $oldsuffix{lc($value)}; + } + print NEWDEST $_; + } elsif ($oldhash{lc($param)}) { + # only set the parameter if the old value is different than + # the new value + if ($value cmp $oldhash{lc($param)}) { + print NEWDEST "#This parameter was migrated: the original value was $value\n"; + print NEWDEST $param, "\t", "\"$oldhash{lc($param)}\"", "\n"; + } else { + print NEWDEST $_; + } + delete $oldhash{lc($param)}; + } elsif ($oldldbmhash{lc($param)}) { + # only set the parameter if the old value is different than + # the new value + if ($value cmp $oldldbmhash{lc($param)}) { + print NEWDEST "#This parameter was migrated: the original value was $value\n"; + print NEWDEST $param, "\t", "\"$oldldbmhash{lc($param)}\"", "\n"; + } else { + print NEWDEST $_; + } + delete $oldldbmhash{lc($param)}; + } else { + # just print the parameter + print NEWDEST $_; + } + } else { + print NEWDEST $_; + } + } + close (NEWSRC); + + # add the suffixes we didn't already have + if (%oldsuffix) { + print NEWDEST "#These suffixes were migrated\n"; + foreach (values %oldsuffix) { + print NEWDEST 'suffix', "\t", "\"$_\"", "\n"; + } + } + + # add the user defined indexes + if (@newIndex) { + print NEWDEST "#These indexes were migrated\n"; + while (@newIndex) { + print NEWDEST shift(@newIndex), "\n"; + } + } + + # print the bad plugins, commented out, at the end of the file + if (@badLdbmPlugins) { + print NEWDEST "#The following non standard plugins were detected:\n"; + print "The following non standard ldbm plugins were detected:\n"; + foreach (@badLdbmPlugins) { + print NEWDEST "#", $_, "\n"; + print $_, "\n"; + } + print NEWDEST "#These plugins will probably need to be recompiled for this release\n"; + print "These plugins will probably need to be recompiled for this release\n"; + print NEWDEST "#of directory server, or at the very least, reconfigured.\n"; + print "of directory server, or at the very least, reconfigured.\n"; + } + + close( NEWDEST ); + + open(NEWSRC, $newdseldif ) || die "Can't open $newdseldif: $!: "; + open(NEWDEST, ">$newdseldif.tmp" ) || die "Can't create $newdseldif.tmp: $!: "; + $inEncryptionConfig = 0; + while ( <NEWSRC> ) { + if (/^\s*#/) { + print NEWDEST $_; + } elsif (/^\s*$/) { + if ($inEncryptionConfig) { # end of entry + $inEncryptionConfig = 0; + # if attributes were present in the old config but not + # in the new one, add them to the end of the entry + foreach $key (keys %olddsehash) { + print NEWDEST $key, ': ', $olddsehash{$key}, "\n"; + } + } + print NEWDEST $_; + } elsif (/cn=encryption\s*,\s*cn=config/) { + $inEncryptionConfig = 1; + print NEWDEST $_; + } elsif (/^\s*(\S+):\s*(.*)$/) { + $param = $1; + $value = $2; + if ($olddsehash{lc($param)}) { + # only set the parameter if the old value is different than + # the new value + if ($value cmp $olddsehash{lc($param)}) { + print NEWDEST $param, "\t", $olddsehash{lc($param)}, "\n"; + } else { + print NEWDEST $_; + } + delete $olddsehash{lc($param)}; + } else { + # just print the parameter + print NEWDEST $_; + } + } else { + print NEWDEST $_; + } + } + close (NEWSRC); + close( NEWDEST ); + + # final step: use the slapd_config program to check the new config file + my $rc = &mySystemNoDie("$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server", + "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" . + "${PATHSEP}slapd_config${exe_suffix}", + '-c', '-f', "$newsrc.tmp"); + + # if the check failed, run slapd_config again in verbose mode to provide + # more information to the user; this will die and abort processing + if ($rc) { + print "The following problems were found with the new configuration:\n"; + &mySystem("$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server", + "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" . + "${PATHSEP}slapd_config${exe_suffix}", + '-f', "$newsrc.tmp"); + } + + # if we got here, the files were good + # save a copy of the old config files + ©BinFile("$newsrc", "$newsrc.save"); + ©BinFile("$newldbmsrc", "$newldbmsrc.save"); + + # replace the temporary dynamicconf directive with the real one + open(NEWSRC, "$newsrc.tmp") or die "Could not open file $newsrc.tmp: $!"; + open(NEWDEST, ">$newsrc") or die "Could not write file $newsrc: $!"; + while(<NEWSRC>) { + if (/^dynamicconf/i) { + print NEWDEST "dynamicconf\t\"$newldbmsrc\"\n"; + } else { + print NEWDEST; + } + } + close NEWSRC; + close NEWDEST; + + ©BinFile("$newldbmsrc.tmp", "$newldbmsrc"); + ©BinFile("$newdseldif.tmp", "$newdseldif"); +} + +sub copyDir { + my $src = shift; + my $dest = shift; + my $exclude = shift; + + opendir( SRC, $src ) or die "Can't open directory $src: $!: "; + my $mode; + my $uid; + my $gid; + mkdir ( $dest , 0755 ) if !( -e $dest ); + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + local ( @files ) = readdir ( SRC ); + closedir( SRC ); + for ( @files ) { + if ( $_ eq "." || $_ eq ".." ) { + next; + } elsif ( $exclude && /$exclude/ ) { + next; + } elsif( -d "$src${PATHSEP}$_") { + ©Dir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" ); + } else { + ©BinFile ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_"); + } + } +} + +sub copyBinFile { + my $src = shift; + my $dest = shift; + my $buf = ""; + my $bufsize = 8192; + + open( SRC, $src ) || die "Can't open $src: $!\n"; + # if we are given a directory destination instead of a file, extract the + # filename portion of the source to use as the destination filename + if (-d $dest) { + $dest = $dest . $PATHSEP . &basename($src); + } + open( DEST, ">$dest" ) || die "Can't create $dest: $!\n"; + binmode SRC; + binmode DEST; + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + while (read(SRC, $buf, $bufsize)) { + print DEST $buf; + } + close( SRC ); + close( DEST ); +} + +sub isAStandardPlugin { + my $line = shift; + + chomp($line); + return $stdPlugins{lc($line)}; +} + +sub isAStandardIndex { + my $line = shift; + + chomp($line); + return $stdIndex{$line}; +} + +sub isAStandardInclude { + my $line = shift; + + chomp($line); + return $stdIncludes{lc($line)}; +} + +# Do a file copy, but convert path names as the file gets copied +# Don't convert paths that don't point anywere, except for log files +# push non-converted paths to the results list +# If you are xlating paths that contain one another, the long paths must come +# first +sub xlatePath { + my $src = shift; + my $dest = shift; + + open( SRC, $src ) || die "Can't open $src: $!: "; + open( DEST, ">$dest" ) || die "Can't create $dest: $!: "; + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + while ( <SRC> ) { + print DEST &xlatePaths( $_, @_ ); + } + close( SRC ); + close( DEST ); +} + +# translate paths in the string +sub xlatePaths { + my $line = shift; + my @otherParams = @_; + my $numXs = shift; + my @srcPaths = splice( @_, 0, $numXs ); + my @destPaths = splice( @_, 0, $numXs ); + my @allowedEmpty = @_; + my @pathLengths = map { length( $_ ) } @srcPaths; + my $i; + my $pre; + my $post; + my $allowed; + my $path; + my $destPath; + + # replace the src paths with the dest paths + # NOTE: this algorithm will only work if the longest paths + # are replaced first e.g. strlen(srcPath[N]) > strlen(srcPath[N+1]) + # and none of the destpaths match any of the srcpaths + for ( $i = 0 ; $i < $numXs ; ++$i ) { + if ($srcPaths[$i] ne $destPaths[$i]) { + $line =~ s/$srcPaths[$i]/$destPaths[$i]/g; + } + } + + return $line; +} + +sub copyBak { + opendir( OLDBAK, "$oldHome${PATHSEP}bak" ) || + die "Can't open directory $oldHome${PATHSEP}bak: $!: "; + local ( @dirs ) = readdir( OLDBAK ); + closedir ( OLDBAK ); + for ( @dirs ) { + if ( $_ eq "." || $_ eq ".." ) { + next; + } elsif ( -d "$oldHome${PATHSEP}bak${PATHSEP}$_" ) { + $srcDir = "$oldHome${PATHSEP}bak${PATHSEP}$_"; + $destDir = "$serverHome${PATHSEP}bak${PATHSEP}$_"; + $srcLDIF = "$oldHome${PATHSEP}ldif${PATHSEP}bak.ldif"; + $destLDIF = "$serverHome${PATHSEP}ldif${PATHSEP}bak.ldif"; + mkdir( $destDir , 0755 ) if !( -e $destDir); + # Converting database + if ( !$isNT && $newuser ) { + chown($newuid, $newgid, + "$serverHome${PATHSEP}bak", $destDir); + } + &other_db2ldif($srcDir, $srcLDIF); + if ($needAclUpg) { + &mySystem("$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server", + "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" . + "${PATHSEP}aclupg$exe_suffix", '-d', '-i', + $srcLDIF, '-o', $destLDIF); + } else { + ©BinFile($srcLDIF, $destLDIF); + } + &other_ldif2db($destLDIF, $destDir); + } + } +} + +sub other_db2ldif { + my $srcDbDir = shift; + my $ldif = shift; + + if ($oldversion == 1) { + &db2ldif($srcDbDir, $ldif); + } else { + # make a dummy version of the current slapd.conf and tell it that + # the db directory is really the back up directory so that we can + # trick ns-slapd db2ldif to do the right thing; Oh how I wish there + # were a simple ldbmcat utility for 3.X and 4.0 . . . + &xlatePath("$oldHome${PATHSEP}config${PATHSEP}slapd.conf", + "$oldHome${PATHSEP}config${PATHSEP}slapd.conf.bak", + 3, + "$realOldHome", + "$oldDbDir", + "slapd.dynamic_ldbm.conf", + "$oldHome", + "$srcDbDir", + "slapd.dynamic_ldbm.conf.bak", + '/logs/'); + &xlatePath("$oldHome${PATHSEP}config${PATHSEP}slapd.dynamic_ldbm.conf", + "$oldHome${PATHSEP}config${PATHSEP}slapd.dynamic_ldbm.conf.bak", + 2, + "$realOldHome", + "$oldDbDir", + "$oldHome", + "$srcDbDir", + '/logs/'); + # now do the ldif2db with our munged conf files . . . + &db2ldif($srcDbDir, $ldif, + "$oldHome${PATHSEP}config${PATHSEP}slapd.conf.bak"); + unlink("$oldHome${PATHSEP}config${PATHSEP}slapd.conf.bak"); + unlink("$oldHome${PATHSEP}config${PATHSEP}slapd.dynamic_ldbm.conf.bak"); + } +} + +sub other_ldif2db { + my $ldif = shift; + my $destDbDir = shift; + my $confFile = shift; + my $directiveToAdd = shift; + + # make a dummy version of the current slapd.conf and slapd.ldbm.conf + # to point to the database directory we want to populate instead of + # the standard + &xlatePath("$serverHome${PATHSEP}config${PATHSEP}slapd.conf", + "$serverHome${PATHSEP}config${PATHSEP}slapd.conf.bak", + 3, + "$newDbDir", + "slapd.ldbm.conf", + "slapd.dynamic_ldbm.conf", + "$destDbDir", + "slapd.ldbm.conf.bak", + "slapd.ldbm.conf.bak", + '/logs/'); + &xlatePath("$serverHome${PATHSEP}config${PATHSEP}slapd.ldbm.conf", + "$serverHome${PATHSEP}config${PATHSEP}slapd.ldbm.conf.bak", + 1, + "$newDbDir", + "$destDbDir", + '/logs/'); + + # we may need to add something to a config file e.g. when migrating the change + # log, we need to add suffix $changeLogSuffix to slapd.ldbm.conf in order to + # ldif2db it without error + if ($confFile && $directiveToAdd) { + open(CONFADD, ">>$serverHome${PATHSEP}config${PATHSEP}${confFile}.bak") or + die "Could not append to $serverHome${PATHSEP}config${PATHSEP}${confFile}.bak: $!"; + print CONFADD $directiveToAdd, "\n"; + close(CONFADD); + } + + &mySystem("$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server", + "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" . + "${PATHSEP}$slapdExecName", + "ldif2db", '-C', '-f', + "$serverHome${PATHSEP}config${PATHSEP}slapd.conf.bak", '-i', + "$ldif"); + unlink("$serverHome${PATHSEP}config${PATHSEP}slapd.conf.bak"); + unlink("$serverHome${PATHSEP}config${PATHSEP}slapd.ldbm.conf.bak"); + unlink($ldif); +} + +sub manyLdif2db { + my @args = (); + while (@_) { + push @args, '-i', shift(@_); + } + &mySystem("$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server", + "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" . + "${PATHSEP}$slapdExecName", "ldif2db", '-C', '-f', + "$serverHome${PATHSEP}config${PATHSEP}slapd.conf", @args); +} + +sub copyLdif { + opendir (LDIFDIR, "$oldHome${PATHSEP}ldif" ); + local ( @files ) = readdir ( LDIFDIR ); + closedir(LDIFDIR); + for ( @files ) { + if ( $_ eq "." || $_ eq ".." || $_ eq "demo.ldif" ) { + next; + } + + if ($needAclUpg) { + &mySystem("$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server", + "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}" . + "aclupg$exe_suffix", '-d', '-i', + "$oldHome${PATHSEP}ldif${PATHSEP}$_", '-o', + "$serverHome${PATHSEP}ldif${PATHSEP}$_"); + } else { + ©BinFile("$oldHome${PATHSEP}ldif${PATHSEP}$_", + "$serverHome${PATHSEP}ldif${PATHSEP}$_"); + } + } +} + +sub genAcl { + my $filename = "$root${PATHSEP}httpacl${PATHSEP}generated.$type-$newname.acl"; + + open( S, ">$filename" ) || die "Can't create file $filename: $!: "; + print S "version $newversion.0;\n"; + print S "acl agents;\n"; + print S "authenticate (user, group) {\n"; + print S " prompt = \"Agent Service\";\n"; + print S "};\n"; + print S "deny absolute (all) (user != all);\n"; + print S "allow absolute (all) (user = all);\n"; + print S "\n"; + print S "acl \"default\";\n"; + print S "allow (read, list, execute,info) user = \"anyone\";\n"; + print S "allow (write, delete) user = \"all\";\n"; + close( S ); +} + +sub getVersion { + my $rootDir = shift; + my $version = 0; + my $minor = 0; + my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}"; + # get the current directory so we can go back to it + my $curdir = &getCwd; + + # find the slapd executable + $prog = $rootDir . $progDir . $slapdExecName; + if (! -f $prog) { + $prog = $rootDir . $progDir2 . $slapdExecName; + if (-f $prog && $isNT) { + # if slapd is in bin/slapd and we're on NT, just assume version 1; + # apparently, slapd.exe doesn't like the -v argument . . . + return ( '1', $minor ); + } + } + + # read the old version from the old slapd program + chdir($rootDir . $progDir) or + die "Could not chdir to $rootDir${progDir}: $!: "; + open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or + die "Could not run slapd program $prog: $!"; + sleep(1); # allow some data to accumulate in the pipe +# print "Output from $prog -v:\n"; + while (<F>) { +# print; + if (/^Netscape-Directory\/(\d+)\.(\d+)/) { + $version = $1; + $minor = $2; + last; + } + } + $code = close(F); +# print "$prog returned code=$code status=$?\n"; + + # done determining versions; go back to orig directory + chdir($curdir) or die "Could not chdir to $curdir: $!: "; + + $version == 0 and + die "Could not determine version of the directory server in $rootDir: "; + + return ( $version, $minor ); +} + +# this subroutine implements a very stupid version of diff +sub diff { + my $f1 = shift; + my $f2 = shift; + my $retval = ""; + + open(F1, "$f1") or die "Could not open file $f1"; + open(F2, "$f2") or close(F1), die "Could not open file $f2"; + + while (defined($l1 = <F1>) && defined($l2 = <F2>)) { + if (!($l1 eq $l2)) { + # ignore comments + if (($l1 =~ /^#/) && ($l2 =~ /^#/)) { + next; + } + # ignore whitespace + $l1 =~ s/\s//g; + $l2 =~ s/\s//g; + + if (!($l1 eq $l2)) { + $retval .= "< ${l1}> $l2"; + } + } + } + + close(F1); + close(F2); + + if ($retval eq "") { + return undef; + } + + return $retval; +} + +# unfortunately, we can't use the shell script/batch file because it may +# not have been updated if the user changed the database directory +sub db2ldif { + my ($srcDbDir, $ldif, $conf) = @_; + + if ($oldversion == 1) { + my $dir = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server"; + chdir($dir) or die "Error: could not change directory to $dir: $!"; + my @cmd = ("${quote}$dir${PATHSEP}ldbmcat${exe_suffix}${quote}", '-n', + "${quote}$srcDbDir${PATHSEP}id2entry.dbb${quote}"); + open(LDBMCAT, "${quote}@cmd${quote}|") or + die "Error: could not execute @cmd: $!"; + open(OUTLDIF, "> $ldif") or + die "Error: could not write to $ldif: $!"; + sleep(1); # allow pipe to fill with data + $ii = 0; # counter + while (<LDBMCAT>) { + print OUTLDIF; + ++$ii; + if (($ii % 250) == 0) { + print " Processed ", $ii, " lines\n"; + } + } + close(LDBMCAT); + close(OUTLDIF); + } else { + if (!$conf) { + $conf = "$oldHome${PATHSEP}config${PATHSEP}slapd.conf"; + } + my $baseldif = &basename($ldif); + if ($baseldif eq $ldif) { + $ldif = "$oldHome${PATHSEP}ldif${PATHSEP}$ldif"; + } + my $dir = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server"; + chdir($dir) or + die "Error: could not change directory to $dir: $!"; + + my @cmd = + ( "${quote}$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" . + "${PATHSEP}$slapdExecName${quote}", "db2ldif", '-n', '-f', + "${quote}$conf${quote}", '-a', "${quote}$ldif${quote}", + '-d', '1' ); + open(DB2LDIF, "${quote}@cmd${quote} 2>&1|") or + die "Error: could not execute @cmd: $!"; + sleep(1); # allow pipe to fill with data + $ii = 0; # counter + while (<DB2LDIF>) { + ++$ii; + if (($ii % 250) == 0) { + print " Processing...\n"; + } + } + close(DB2LDIF); + } + print " Done.\n"; +} + +# this subroutine works like sed in that it will create another version +# of the input file with some editing done +# the file should be a text file +sub copyAndEditTextFile { + my $srcFile = shift; + my $destFile = shift; + my $sub = shift; + + open(SRCFILE, "$srcFile") or die "Error: could not open file $srcFile: $!"; + open(DESTFILE, ">$destFile") or die "Error: could not write file $destFile: +$!"; + + while (<SRCFILE>) { + my $newline = &$sub($_); + if ($newline cmp $_) { + print "The line: $_"; + print "Was converted to: $newline"; + print "File: $srcFile\n"; + } + print DESTFILE $newline; + } + + close(SRCFILE); + close(DESTFILE); +} diff --git a/ldap/admin/src/migratedsgw b/ldap/admin/src/migratedsgw new file mode 100755 index 00000000..8874c02d --- /dev/null +++ b/ldap/admin/src/migratedsgw @@ -0,0 +1,445 @@ +#!perl +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# print begin message +$now_time = gmtime; +print "BEGIN DSGW migration at ", $now_time, " GMT\n"; + +# get the commandline options +if (!getopts('s:d:h:') || !$opt_s || !$opt_d || !$opt_h ) { + print "usage: dsgwmig options\n"; + print "\noptions:\n"; + print " -s directory\tdirectory containing the 3.0 Gateway\n"; + print " -d directory\tdirectory containing the 4.1 Gateway\n"; + print " -h host[:port]\tthe host and port of the directory server\n"; + print " \t\t\tto which the migrated gateway will query\n"; + print "\nexample:\n dsgwmig -s /usr/tmp/ds30/slapd-host/dsgw -d /usr/tmp/ds40/dsgw -h gargoyle:1974\n"; + + exit; +} + +sub reportAndExit { + my $now_time = gmtime; + print "END DSGW migration at ", $now_time, " GMT\n"; + print "DSGW Exit status is ", $exitCode, "\n"; + if ($? == 0 && $exitCode == 0) { + print "NMC_STATUS: 0\n"; + } else { + print '$?=', $?+0, ' $!=', $!+0, ' $exitCode=', $exitCode, "\n"; + print shift, "\n"; + print "NMC_STATUS: $exitCode\n"; + } + + print "###DSGW MIGRATION FINISHED###\n"; + + exit($exitCode); +} + +$SIG{__DIE__} = 'exit'; +$SIG{'QUIT'} = 'exit'; +$SIG{'INT'} = 'exit'; +$SIG{'TERM'} = 'exit'; + +# the atexit handler +END { + $! = 0; + $? = $exitCode; + &reportAndExit; +} + +# setup the path separator +$isNT = -d '\\'; +$PS = $isNT ? "\\" : "/"; + +#make sure that the target directory exists +if (! -e $opt_d) { + print "$opt_d does not exist\n"; + exit; +} + +print "Migrating the config directory...\n"; +# First migrate the config directory +migrate_html("config"); + +print "Migrating the html directory...\n"; +# Then migrate the html directory +migrate_html("html"); + +print "Migrating the dsgw.conf...\n"; +# Then migrate dsgw.conf +migrate_config(); + +# Then copy over certain files like alert.html, confirm.html and emptyFrame from +# the regular *4.1* DSGW to the newly migrated *4.1* gateway. +if (! -e "$opt_d"."$PS"."html-30"."$PS"."alert.html") { + print "copy ", "$opt_d"."$PS"."html"."$PS"."alert.html", " $opt_d"."$PS"."html-30"."$PS"."alert.html", "\n"; + copyFile("$opt_d"."$PS"."html"."$PS"."alert.html", "$opt_d"."$PS"."html-30"."$PS"."alert.html"); +} + +if (! -e "$opt_d"."$PS"."html-30"."$PS"."confirm.html") { + print "copy ", "$opt_d"."$PS"."html"."$PS"."confirm.html", " $opt_d"."$PS"."html-30"."$PS"."confirm.html", "\n"; + copyFile("$opt_d"."$PS"."html"."$PS"."confirm.html", "$opt_d"."$PS"."html-30"."$PS"."confirm.html"); +} + +if (! -e "$opt_d"."$PS"."html-30"."$PS"."confirm.gif") { + copyFile("$opt_d"."$PS"."html"."$PS"."confirm.gif", "$opt_d"."$PS"."html-30"."$PS"."confirm.gif"); +} + +if (! -e "$opt_d"."$PS"."html-30"."$PS"."alert.gif") { + copyFile("$opt_d"."$PS"."html"."$PS"."alert.gif", "$opt_d"."$PS"."html-30"."$PS"."alert.gif"); +} + +if (! -e "$opt_d"."$PS"."html-30"."$PS"."emptyFrame.html") { + copyFile("$opt_d"."$PS"."html"."$PS"."emptyFrame.html", "$opt_d"."$PS"."html-30"."$PS"."emptyFrame.html"); +} + +print "end of migratedsgw\n"; +$exitCode = 0; +exit $exitCode; + +sub migrate_html +{ + my $target_dir = shift(@_); + my $orig_target = "$target_dir"; + my $full_target_dir; + my @subdirlist; + my @dsgwfiles; + +# cd into the source directory + chdir "$opt_s"."$PS"."$target_dir" or die "Unable to cd to $opt_s$PS$target_dir: $!\n"; + +# read the files + opendir DSGW_OLD, "." or die "$!"; + @dsgwfiles = grep !/^\.\.?$/, readdir DSGW_OLD; + closedir DSGW_OLD; + +# Before we go on, we need to make the directory +# in the 4.1 space. If we're working on the config +# or html directory, then we have to rename them. + $target_dir =~ s/^(config|html)/$1\-30/; + $full_target_dir = "$opt_d". "$PS". "$target_dir"; + if (! -d $full_target_dir) { + mkdir $full_target_dir, 0755 or + die "can't create $opt_d$PS$target_dir. $!\n"; + } + +# foreach file in the current directory, +# either skip it (if it's a subdir) +# copy it to the new directory +# copy and modify it to the new directory + foreach $file (@dsgwfiles){ # + #Skip directories + if (-d $file) { +# print "Skipping Directory $file\n"; + push @subdirlist, $file; + next; + } + + if ($file =~ m/.*?\.html/) { +# open the old file + open(OLDFILE, "$file") or die "Cannot read $file. $!\n"; + +# open the new file + open(NEWFILE, ">"."$full_target_dir"."$PS"."$file") or die "Cannot write $full_target_dir$PS$file. $!\n"; + + for ($line=<OLDFILE>; $line ; $line=<OLDFILE>) { + +# replace all ACTION=/ds/cgi with ACTION=/dsgw/bin/cgi + $line =~ s:(?i)(action\s*=\s*("){0,1}\s*(http(s){0,1}\://.*?){0,1})/ds/(\w*):$1/dsgw/bin/$5:g; #")) + +# Langify the gifs, but not those that are already langified. Look for ="blah.gif" + $line =~ s:(?i)=\s*("){0,1}\s*([\w|\-|_]*)\.(gif|jpg|jpeg):=$1/dsgw/bin/lang?\<!-- GCONTEXT --\>\&file=$2\.$3:g; #") + +# And html files. Look for SRC|HREF="blah.html" + $line =~ s:(?i)(HREF|SRC)(\s*=\s*("){0,1}\s*)([\w|\-|_]*)\.(html):$1$2/dsgw/bin/lang?\<!-- GCONTEXT --\>\&file=$4\.$5:g; #") + +# Any javascript files should become /dsgw/html-30/blah.js + $line =~ s:(?i)=\s*("){0,1}\s*([\w|\-|_]*)\.(js):=$1/dsgw/html-30/$2\.$3:g; #") + +# Look for /dshtml/ to langify the .gifs and .html. This rule can't +# precede the first langify rule. That would be bad because it looks for ="blah.gif" + $line =~ s:(?i)/dshtml/([\w|\-|_]*)\.(gif|jpg|jpeg|html):/dsgw/bin/lang?\<!-- GCONTEXT --\>\&file=$1\.$2:g; #") + +# GETs on the CGIs .... +# auth - dn is passed either as QUERY_STRING or PATH_INFO, but not both. + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))auth(/|\?dn=)([\w|%]*):$3$4/dsgw/bin/auth?dn=$9\&\<!-- GCONTEXT --\>:g; + +# auth - by itself + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))auth:$3$4/dsgw/bin/auth\?\<!-- GCONTEXT --\>:g; + + +# lang - The argument is always PATH_INFO and it is either a filename +# or a file name and "info=blah". No QUERY_STRING. + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))lang/([=|\w|\&|\.|\-|_]*):$3$4/dsgw/bin/lang?\<!-- GCONTEXT --\>\&file=$8:g; + +# lang could be called without an argument, although it's silly to do so. + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))lang:$3$4/dsgw/bin/lang\?\<!-- GCONTEXT --\>:g; + +# search - take one word arguments with PATH_INFO only. No QUERY_STRING + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))search/(\w*):$3$4/dsgw/bin/search?\<!-- GCONTEXT --\>\&file=$8:g; + + +# search could exist without an argument on a GET + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))search:$3$4/dsgw/bin/search?\<!-- GCONTEXT --\>:g; + + +# csearch - take one word arguments with PATH_INFO only. No QUERY_STRING + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))csearch/(\w*):$3$4/dsgw/bin/csearch?\<!-- GCONTEXT --\>\&file=$8:g; + + +# csearch could exist without an argument on a GET + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))csearch:$3$4/dsgw/bin/csearch?\<!-- GCONTEXT --\>:g; + + +# unauth - doesn't take any arguments + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))unauth:$3$4/dsgw/bin/unauth?\<!-- GCONTEXT --\>:g; + +# dnedit and edit - must always have a dn specified, so /ds/dnedit will +# never exist by itself on a GET. If it's PATH_INFO, then it's just the dn. +# If it's QUERY_STRING it's a bunch of stuff. Could be both. dnedit must +# have a QUERY_STRING. + +# PATH_INFO and QUERY_STRING + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))(dn){0,1}edit/([\w|%]*)\?([\&|=|\w|\-|_|\.]*):$3$4/dsgw/bin/$8edit?\<!-- GCONTEXT --\>\&dn=$9\&$10:g; + +# PATH_INFO only + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))(dn){0,1}edit/([\w|%]*):$3$4/dsgw/bin/$8edit?\<!-- GCONTEXT --\>\&dn=$9:g; + + +# QUERY_STRING only + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))(dn){0,1}edit\?:$3$4/dsgw/bin/$8edit\?\<!-- GCONTEXT --\>\&:g; + + +# doauth and domodify - No GET, only POST + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))do(auth|modify):$3$4/dsgw/bin/do$8\?\<!-- GCONTEXT --\>:g; + + +# newentry - takes PATH_INFO only or nothing. If there is a PATH_INFO, +# then it's 1 word: type or name + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))newentry/(type|name):$3$4/dsgw/bin/newentry?\<!-- GCONTEXT --\>\&file=$8:g; + + +# newentry - could exist on its own + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))newentry:$3$4/dsgw/bin/newentry?\<!-- GCONTEXT --\>:g; + +# tutor - hasn't changed. + +# dosearch - From .../dosearch[/host[:port]][?[dn=baseDN&][LDAPquery]] Or +# ../dosearch/host[:port]/[baseDN][?LDAPquery] + +# To: dosearch?context=BLAH[&hp=host[:port]][&dn=baseDN][&ldq=LDAPquery]] + +# dosearch - Everything there, except maybe the port. Rule 1 + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))dosearch(/){0,1}(\w+)(\:\d+){0,1}(/|\?)((dn=){0,1}([\w|%]+))(\?|\&)(.*?)(\s|"):$3$4/dsgw/bin/dosearch?\<!-- GCONTEXT --\>&hp=$9$10&dn=$14&ldq=$16$17:g; #") + + +# dosearch - no ldapquery +# current version rule 2 + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))dosearch/(\w+)(\:\d+){0,1}\?((dn=)([\w|%]+)):$3$4/dsgw/bin/dosearch?\<!-- GCONTEXT --\>&hp=$8$9&dn=$12:g; + +# older version (always needs host specified) rule 3 + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))dosearch/(\w+)(\:\d+){0,1}/([\w|%]+):$3$4/dsgw/bin/dosearch?\<!-- GCONTEXT --\>&hp=$8$9&dn=$10:g; + + +# dosearch - no basedn +# current version rule 4 + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))dosearch/(\w+)(\:\d+){0,1}\?(.*?)(\s|"):$3$4/dsgw/bin/dosearch?\<!-- GCONTEXT --\>&hp=$8$9&ldq=$10$11:g; #") + + +# older version (always needs host specified) rule 5 + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))dosearch/(\w+)(\:\d+){0,1}/\?(.*?)(\s|"):$3$4/dsgw/bin/dosearch?\<!-- GCONTEXT --\>&hp=$8$9&ldq=$10$11:g; #") + + +# dosearch - no host/port and ldapquery and dn rule 7 + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))dosearch\?(dn=[\w|%]+\&)(.*?)(\s|"):$3$4/dsgw/bin/dosearch?\<!-- GCONTEXT --\>&$8ldq=$9$10:g; #") + # + +# dosearch - no host/port and no ldapquery rule 6 + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))dosearch\?(dn=[\w|%]+):$3$4/dsgw/bin/dosearch?\<!-- GCONTEXT --\>&$8:g; + +# dosearch - host/port nothing else rule 9 + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))dosearch/(\w+)(\:\d+){0,1}(/){0,1}:$3$4/dsgw/bin/dosearch?\<!-- GCONTEXT --\>&hp=$8$9:g; + + +# dosearch - no host/port and no DN (current version only) rule 8 + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))dosearch\?(.*?)(\s|"):$3$4/dsgw/bin/dosearch?\<!-- GCONTEXT --\>&ldq=$8$9:g; #") + +# dosearch - Just by itself rule 10 + $line =~ s:(?i)(((FRAME\s*SRC|HREF)(\s*=\s*("){0,1}\s*)(/ds/){0,1})|(/ds/))dosearch:$3$4/dsgw/bin/dosearch?\<!-- GCONTEXT --\>:g; + +# For 3.0 (not 3.1), we need to update the advanced search page +# to use the csearch CGI instead of javascript. + $line =~ s:SRC\s*=\s*"\s*javascript\:parent.emptyFrame\s*"\s*NAME\s*=\s*"\s*searchTypeFrame":SRC="/dsgw/bin/csearch\?\<!-- GCONTEXT --\>\&file=type" NAME="searchTypeFrame":g; + + $line =~ s:SRC\s*=\s*"\s*javascript\:parent.emptyFrame\s*"\s*NAME\s*=\s*"\s*searchAttrFrame":SRC="/dsgw/bin/csearch\?\<!-- GCONTEXT --\>\&file=attr" NAME="searchAttrFrame":g; + + $line =~ s:SRC\s*=\s*"\s*javascript\:parent.emptyFrame\s*"\s*NAME\s*=\s*"\s*searchMatchFrame":SRC="/dsgw/bin/csearch\?\<!-- GCONTEXT --\>\&file=match" NAME="searchMatchFrame":g; + + $line =~ s:SRC\s*=\s*"\s*javascript\:parent.emptyFrame\s*"\s*NAME\s*=\s*"\s*searchBaseFrame":SRC="/dsgw/bin/csearch\?\<!-- GCONTEXT --\>\&file=base" NAME="searchBaseFrame":g; + + +# Now for the POSTS +# Replace all FORM directives (except the form ending ones) with +# that same directive plus the pcontext directive on a newline + $line =~ s:(?i)(^\<\!\-\- DS_(AUTH|CSEARCH|BEGIN|NEWENTRY|SEARCH)[\w|_]*FORM .*?\-\-\>):$1\n\<!-- PCONTEXT --\>\n:g; + +# Some people might put a form-writing javascript function in their HTML. +# This rule will keep that from getting crippled because otherwise +# the next rule would insert a newline in the middle of a javascript string. + $line =~ s:(?i)\'(.*?)(\<FORM\s*.*?\>)(.*?)\':'$1$2\\n\<!-- PCONTEXT --\>\\n$3':g; + +# Now replace all the explicit <FORM> tags with that same tag +# and the pcontext directive. But don't do it if it already +# has been done by the previous rule + $line =~ s:(?i)(\<FORM\s*.*?\>)(?!\\n):$1\n\<!-- PCONTEXT --\>\n:g;#") + + + print NEWFILE $line; + + } + + close(OLDFILE); + close(NEWFILE); + + +# } elsif ( ($file =~ m/.*?\.js/) && !( -e "$opt_d"."$PS"."bin"."$PS"."$file")) { +# copyFile ("$file", "$opt_d"."$PS"."bin". "$PS". "$file"); + } else { +# print "copy this file $file\n"; + copyFile ("$file","$full_target_dir"."$PS"."$file"); + } + + } + + + + # After we've copied over all the files in this + # directory, then it's time to recurse on all the + # directories below. + + foreach $subdir (@subdirlist) { +# print "recursing on $orig_target $subdir\n"; + migrate_html("$orig_target"."$PS"."$subdir"); + } + +} + + +sub copyFile +{ + my $src = shift; + my $dest = shift; + my $buf = ""; + my $bufsize = 8192; + + open( SRC, $src ) || die "Can't open $src: $!\n"; + # if we are given a directory destination instead of a file, extract the + # filename portion of the source to use as the destination filename + if (-d $dest ) { + $dest = $dest . $PS . &basename($src); + } + open( DEST, ">$dest" ) || die "Can't create $dest: $!\n"; + binmode SRC; + binmode DEST; + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + while (read(SRC, $buf, $bufsize)) { + print DEST $buf; + } + close( SRC ); + close( DEST ); +} + + +sub migrate_config +{ + #open a new dsgw-30.conf in the NS-HOME/dsgw/context directory + open (NEWCONF, ">"."$opt_d"."$PS"."context". "$PS". "dsgw-30.conf") or die "Can't open $opt_d${PS}context${PS}dsgw-30.conf. $!\n"; + print NEWCONF "# Used by Netscape Directory Server Gateway\n\n"; + print NEWCONF "# The htmldir directive tells the CGIs where to find the html files\n"; + print NEWCONF "htmldir\t../html-30\n\n"; + print NEWCONF "# The configdir directive tells the CGIs where to find the\n"; + print NEWCONF "# templates/configuration files\n"; + print NEWCONF "configdir\t../config-30\n\n"; + print NEWCONF "# The gwnametrans directive tells the CGIs what url to output\n"; + print NEWCONF "# for http redirection. It should be the same nameTrans set\n"; + print NEWCONF "# in the webserver, if any is being is used.\n"; + print NEWCONF "gwnametrans\t/dsgw/html-30/\n\n"; + + # now open the old dsgw.conf and start copying it over, line by line + # to the new config file, replacing the NLS directive and the securityPath + # directive with the correct values. Also replace the old host:port with the + # new host:port + open (OLDCONF, "$opt_d"."$PS"."config-30"."$PS"."dsgw.conf") or die "Can't open $opt_d${PS}config-30${PS}dsgw.conf. $!\n";; + + for ($line=<OLDCONF>; $line ; $line=<OLDCONF>) { + $line =~ s:^NLS\s*../../../nls:NLS\t../../lib/nls:g; + $line =~ s:^securitypath\s*(.*?)/slapd\-.*?/dsgw/ssl:securitypath\t$1/alias/dsgw-cert.db:g; + $line =~ s:^baseurl\s*("){0,1}\s*ldap(s){0,1}\://.*?/:baseurl\t$1ldap$2\://$opt_h/:og; + + print NEWCONF "$line"; + + } + + + close (NEWCONF); + close (OLDCONF); +} + +sub basename { + my @list = split(/[\\\/]/, $_[0]); + return $list[@list - 1]; +} + +sub getopts { + local($argumentative) = @_; + local(@args,$_,$first,$rest); + local($errs) = 0; + local($[) = 0; + + @args = split( / */, $argumentative ); + while(@ARGV && ($_ = $ARGV[0]) =~ /^-(.)(.*)/) { + ($first,$rest) = ($1,$2); + $pos = index($argumentative,$first); + if($pos >= $[) { + if($args[$pos+1] eq ':') { + shift(@ARGV); + if($rest eq '') { + ++$errs unless @ARGV; + $rest = shift(@ARGV); + } + eval "\$opt_$first = \$rest;"; + } + else { + eval "\$opt_$first = 1"; + if($rest eq '') { + shift(@ARGV); + } + else { + $ARGV[0] = "-$rest"; + } + } + } + else { + print STDERR "Unknown option: $first\n"; + ++$errs; + if($rest ne '') { + $ARGV[0] = "-$rest"; + } + else { + shift(@ARGV); + } + } + } + $errs == 0; +} diff --git a/ldap/admin/src/namegen.c b/ldap/admin/src/namegen.c new file mode 100644 index 00000000..6fc6d22f --- /dev/null +++ b/ldap/admin/src/namegen.c @@ -0,0 +1,107 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* namegen.c - utility program to generate name * + * of backup files in the format YYYY_MM_DD_HMS * + * and set it up as an environment variable to * + * be used by batch files on NT * + * * + * to use it do the following in your batch file* + * namegen * + * call bstart * + * ....... * + * call bend * + * rm end.bat * + * * + * start and end are batch files generated by * + * name gen. * + * Example: ldif2db.bat */ + +#include <stdlib.h> +#include <stdio.h> +#include <time.h> +#include <string.h> + +#define STARTFILE "bstart.bat" +#define ENDFILE "bend.bat" +#define CMD "set DATESTR=%0\n" + + +int main (int argc, char **argv) +{ + char szDate [64]; + char szDateFile [64]; + char szCmd [256]; + struct tm *sCurTime; + long lCurTime; + int rt; + FILE *fBatch; + + time( &lCurTime ); + + sCurTime = localtime( &lCurTime ); + + strftime(szDate, sizeof (szDateFile), "%Y_%m_%d_%H%M%S", + sCurTime); + + sprintf (szDateFile, "%s.bat", szDate); + + /* create date batch file */ + fBatch = fopen (szDateFile, "w"); + if (fBatch == NULL) + { + perror ("Unable to create date file!"); + exit (1); + } + + rt = fwrite (CMD, strlen (CMD), 1, fBatch); + if (rt != 1) + { + perror ("Unable to write date file\n"); + exit (1); + } + + fclose (fBatch); + + /* create bstart.bat that executest date batch file */ + fBatch = fopen (STARTFILE, "w"); + if (fBatch == NULL) + { + perror ("Unable to bstart file!"); + exit (1); + } + + sprintf (szCmd, "call %s", szDate); + + rt = fwrite (szCmd, strlen (szCmd), 1, fBatch); + if (rt != 1) + { + perror ("Unable to write bstart file\n"); + exit (1); + } + + fclose (fBatch); + + /* create bstart.bat that executest date batch file */ + fBatch = fopen (ENDFILE, "w"); + if (fBatch == NULL) + { + perror ("Unable to bend file!"); + exit (1); + } + + sprintf (szCmd, "del %s\ndel bstart.bat\nset DATESTR=", szDateFile); + + rt = fwrite (szCmd, strlen(szCmd), 1, fBatch); + if (rt != 1) + { + perror ("Unable to write bend file\n"); + exit (1); + } + + fclose (fBatch); + + return 0; +} diff --git a/ldap/admin/src/ns-newpwpolicy.pl b/ldap/admin/src/ns-newpwpolicy.pl new file mode 100644 index 00000000..5cc6a6ec --- /dev/null +++ b/ldap/admin/src/ns-newpwpolicy.pl @@ -0,0 +1,198 @@ +# perl script +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# Add new password policy specific entries + +############################################################################# +# enable the use of Perldap functions +require DynaLoader; + +use Getopt::Std; +use Mozilla::LDAP::Conn; +use Mozilla::LDAP::Entry; +use Mozilla::LDAP::Utils qw(:all); +use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API + +############################################################################# +# Default values of the variables + +$opt_D = "cn=directory manager"; +$opt_p = 389; +$opt_h = "localhost"; +$opt_v = 0; + +############################################################################# + +sub usage { + print (STDERR "ns-newpwpolicy.pl [-v] [-D rootdn] { -w password | -j filename } \n"); + print (STDERR " [-p port] [-h host] -U UserDN -S SuffixDN\n\n"); + + print (STDERR "Arguments:\n"); + print (STDERR " -? - help\n"); + print (STDERR " -v - verbose output\n"); + print (STDERR " -D rootdn - Directory Manager DN. Default= '$opt_D'\n"); + print (STDERR " -w rootpw - password for the Directory Manager DN\n"); + print (STDERR " -j filename - Read the Directory Manager's password from file\n"); + print (STDERR " -p port - port. Default= $opt_p\n"); + print (STDERR " -h host - host name. Default= '$opt_h'\n"); + print (STDERR " -U userDN - User entry DN\n"); + print (STDERR " -S suffixDN - Suffix entry DN\n"); + exit 100; +} + +# Process the command line arguments +{ + usage() if (!getopts('vD:w:j:p:h:U:S:')); + + if ($opt_j ne ""){ + die "Error, cannot open password file $opt_j\n" unless (open (RPASS, $opt_j)); + $opt_w = <RPASS>; + chomp($opt_w); + close(RPASS); + } + + usage() if( $opt_w eq "" ); + if ($opt_U eq "" && $opt_S eq "") { + print (STDERR "Please provide at least -S or -U option.\n\n"); + } + + # Now, check if the user/group exists + + if ($opt_S) { + my $norm_opt_S = normalizeDN($opt_S); + print (STDERR "host = $opt_h, port = $opt_p, suffixDN = $norm_opt_S\n\n") if $opt_v; + %ld = Mozilla::LDAP::Utils::ldapArgs(); + $ld->{"host"} = $opt_h; + $ld->{"port"} = $opt_p; + $ld->{"bind"} = $opt_D; + $ld->{"pswd"} = $opt_w; + $conn = new Mozilla::LDAP::Conn(\%ld); die "No LDAP connection" unless $conn; + + $entry_1 = new Mozilla::LDAP::Entry; + $dn1 = "cn=nsPwPolicyContainer, " . $norm_opt_S; + print (STDERR "adding $dn1\n\n") if $opt_v; + $entry_1->setDN("$dn1"); + $entry_1->setValues("objectclass", "top", "nsContainer"); + $conn->add($entry_1); + $error = $conn->getErrorCode(); + if ( ( $error ne 0 ) && ( $error ne 68 ) ) { + $conn->printError(); + exit (-1); + } + + $entry_2 = new Mozilla::LDAP::Entry; + $dn2 = "cn=\"cn=nsPwPolicyEntry,$norm_opt_S\",cn=nsPwPolicyContainer," . $norm_opt_S; + print (STDERR "adding $dn2\n\n") if $opt_v; + $entry_2->setDN("$dn2"); + $entry_2->setValues("objectclass", "top", "ldapsubentry", "passwordpolicy"); + $conn->add($entry_2); + $conn->printError() if $conn->getErrorCode(); + + $entry_3 = new Mozilla::LDAP::Entry; + $dn3 = "cn=\"cn=nsPwTemplateEntry,$norm_opt_S\",cn=nsPwPolicyContainer, " . $norm_opt_S; + print (STDERR "adding $dn3\n\n") if $opt_v; + $entry_3->setDN("$dn3"); + $entry_3->setValues("objectclass", "top", "extensibleObject", "costemplate", "ldapsubentry"); + $entry_3->setValues("cospriority", "1"); + $entry_3->setValues("pwdpolicysubentry", "$dn2"); + $conn->add($entry_3); + $conn->printError() if $conn->getErrorCode(); + + $entry_4 = new Mozilla::LDAP::Entry; + $dn4 = "cn=nsPwPolicy_cos, " . $norm_opt_S; + print (STDERR "adding $dn4\n\n") if $opt_v; + $entry_4->setDN("$dn4"); + $entry_4->setValues("objectclass", "top", "cosSuperDefinition", "cosPointerDefinition", "ldapsubentry"); + $entry_4->setValues("cosTemplateDn", "$dn3"); + $entry_4->setValues("cosAttribute", "pwdpolicysubentry default operational-default"); + $conn->add($entry_4); + $conn->printError() if $conn->getErrorCode(); + + $cfg_entry = $conn->search("cn=config", "base", "(objectclass=*)"); + $conn->printError() if $conn->getErrorCode(); + print (STDERR "modifying cn=config\n\n") if $opt_v; + $cfg_entry->setValues("nsslapd-pwpolicy-local", "on"); + $conn->update($cfg_entry); + $conn->printError() if $conn->getErrorCode(); + + $conn->close if $conn; + + } # end of $opt_S + + if ($opt_U) { + my $norm_opt_U = normalizeDN($opt_U); + print (STDERR "host = $opt_h, port = $opt_p, userDN = $norm_opt_U\n\n") if $opt_v; + %ld = Mozilla::LDAP::Utils::ldapArgs(); + $ld->{"host"} = $opt_h; + $ld->{"port"} = $opt_p; + $ld->{"bind"} = $opt_D; + $ld->{"pswd"} = $opt_w; + $conn = new Mozilla::LDAP::Conn(\%ld); die "No LDAP connection" unless $conn; + + $user_entry = $conn->search($norm_opt_U, "base", "(objectclass=*)"); + $conn->printError() if $conn->getErrorCode(); + if (! $user_entry) { + print (STDERR "The user entry $norm_opt_U does not exist. Exiting.\n"); + exit (-1); + } + + print (STDERR "the user entry $norm_opt_U found..\n\n") if $opt_v; + + # Now, get the parentDN + @rdns = ldap_explode_dn($norm_opt_U, 0); + shift @rdns; + $parentDN = join(',', @rdns); + + print (STDERR "parentDN is $parentDN\n\n") if $opt_v; + + # Now, check if the nsContainer entry exists at the parent level + $dn1 = "cn=nsPwPolicyContainer, " . $parentDN; + $entry = $conn->search($dn1, "base", "(objectclass=*)"); + my $error = $conn->getErrorCode(); + $conn->printError() + if (( $error ne 0 ) && ( $error ne 32 ) && ( $error ne 68 )); + + if (! $entry) { + print (STDERR "nsContainer doesn't exist. Creating one now..\n\n") if $opt_v; + + $entry_1 = new Mozilla::LDAP::Entry; + + print (STDERR "adding $dn1\n\n") if $opt_v; + $entry_1->setDN("$dn1"); + $entry_1->setValues("objectclass", "top", "nsContainer"); + $conn->add($entry_1); + $conn->printError() if $conn->getErrorCode(); + } else { + print (STDERR "nsContainer exists..\n\n") if $opt_v; + } + + $entry_2 = new Mozilla::LDAP::Entry; + $dn2 = "cn=\"cn=nsPwPolicyEntry,$norm_opt_U\",cn=nsPwPolicyContainer," . $parentDN; + print (STDERR "adding $dn2\n\n") if $opt_v; + $entry_2->setDN("$dn2"); + $entry_2->setValues("objectclass", "top", "ldapsubentry", "passwordpolicy"); + $conn->add($entry_2); + $conn->printError() if $conn->getErrorCode(); + + print (STDERR "modifying $norm_opt_U\n\n") if $opt_v; + $user_entry->setValues("pwdpolicysubentry", "$dn2"); + $conn->update($user_entry); + $conn->printError() if $conn->getErrorCode(); + + $cfg_entry = $conn->search("cn=config", "base", "(objectclass=*)"); + $conn->printError() if $conn->getErrorCode(); + print (STDERR "modifying cn=config\n\n") if $opt_v; + $cfg_entry->setValues("nsslapd-pwpolicy-local", "on"); + $conn->update($cfg_entry); + $conn->printError() if $conn->getErrorCode(); + + $conn->close if $conn; + + } # end of $opt_U +} diff --git a/ldap/admin/src/restart.c b/ldap/admin/src/restart.c new file mode 100644 index 00000000..44d80a49 --- /dev/null +++ b/ldap/admin/src/restart.c @@ -0,0 +1,46 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * restart.c: Stops and the starts up the server. + * + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "libadminutil/admutil.h" +#include "dsalib.h" +#include "init_ds_env.h" + +#ifdef XP_WIN32 + #define sleep(sec) Sleep(sec) +#endif + +int main(int argc, char *argv[]) +{ + int status = -1; + + fprintf(stdout, "Content-type: text/html\n\n"); + + if ( init_ds_env() ) + return 1; + + if (DS_SERVER_UP == ds_get_updown_status()) { + status = ds_bring_down_server(); + if(status != DS_SERVER_DOWN) { + rpt_err( status, "", NULL, NULL ); + return 1; + } + } + status = ds_bring_up_server(1); + if(status == DS_SERVER_UP) { + rpt_success("Success! The server has been restarted."); + return 0; + } else { + rpt_err( status, "", NULL, NULL ); + return 1; + } +} diff --git a/ldap/admin/src/script-gen.c b/ldap/admin/src/script-gen.c new file mode 100644 index 00000000..e2caab4c --- /dev/null +++ b/ldap/admin/src/script-gen.c @@ -0,0 +1,107 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * this is used for generating the (large) scripts during create_instance. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "portable.h" + + +/* reads the file on inpath, and rewrites it on outpath. + * 'table' is a list of string-pairs (terminated by a pair of NULLs) that + * indicate substitution pairs. for example, the pair: + * "SERVER-ROOT", "/export/home/slapd-bastille" + * means to substitute any occurance of "{{SERVER-ROOT}}" in the file with + * "/export/home/slapd-bastille". + * + * returns 0 on success, -1 if it had trouble opening or reading/writing + * the two files. + */ +#define GS_BUFLEN 256 +int generate_script(const char *inpath, const char *outpath, int mode, + const char *table[][2]) +{ + FILE *fin, *fout; + char buffer[GS_BUFLEN], save_buffer[GS_BUFLEN]; + char *p, *q; + int i; + + fin = fopen(inpath, "r"); + if (fin == NULL) { + return -1; + } + fout = fopen(outpath, "w"); + if (fout == NULL) { + fclose(fin); + return -1; + } + + while (!feof(fin)) { + fgets(buffer, GS_BUFLEN, fin); + if (feof(fin)) { + break; + } + buffer[GS_BUFLEN-1] = 0; + if (buffer[strlen(buffer)-1] == '\n') { + buffer[strlen(buffer)-1] = 0; + } + if (buffer[strlen(buffer)-1] == '\r') { + buffer[strlen(buffer)-1] = 0; + } + + p = buffer; + while ((p = strstr(p, "{{")) != NULL) { + q = strstr(p+2, "}}"); + if (q == NULL) { + /* skip this one then */ + p += 2; + continue; + } + + /* key between {{ }} is now in [p+2, q-1] */ + for (i = 0; table[i][0] != NULL; i++) { + if ((strlen(table[i][0]) == (q-(p+2))) && + (strncasecmp(table[i][0], p+2, q-(p+2)) == 0)) { + /* match! ...but is there room for the subtitution? */ + int extra = strlen(table[i][1]) - (q+2-p); + + if (strlen(buffer) + extra > GS_BUFLEN-1) { + /* not enough room, scratch it */ + continue; + } + strcpy(save_buffer, q+2); + strcpy(p, table[i][1]); + strcat(p, save_buffer); + q = p; + break; /* out of the for loop */ + } + } + + /* move on... */ + p = q; + } + + fprintf(fout, "%s\n", buffer); + } + +#if defined( XP_UNIX ) + fchmod(fileno(fout), mode); +#endif + + fclose(fin); + fclose(fout); + +#if defined( XP_WIN32 ) + chmod(outpath, mode); +#endif + + return 0; +} diff --git a/ldap/admin/src/scripts/template-bak2db.pl b/ldap/admin/src/scripts/template-bak2db.pl new file mode 100644 index 00000000..10cb99bc --- /dev/null +++ b/ldap/admin/src/scripts/template-bak2db.pl @@ -0,0 +1,89 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +sub usage { + print(STDERR "Usage: $0 [-v] -D rootdn { -w password | -w - | -j filename } \n"); + print(STDERR " : -a dirname [-t dbtype]\n"); + print(STDERR " Opts: -D rootdn - Directory Manager\n"); + print(STDERR " : -w password - Directory Manager's password\n"); + print(STDERR " : -w - - Prompt for Directory Manager's password\n"); + print(STDERR " : -j filename - Read Directory Manager's password from file\n"); + print(STDERR " : -a dirname - backup directory\n"); + print(STDERR " : -t dbtype - database type (default: ldbm database)\n"); + print(STDERR " : -v - verbose\n"); +} +$taskname = ""; +$archivedir = ""; +$dbtype = "ldbm database"; +$dsroot = "{{DS-ROOT}}"; +$mydsroot = "{{MY-DS-ROOT}}"; +$verbose = 0; +$rootdn = ""; +$passwd = ""; +$passwdfile = ""; +$i = 0; +while ($i <= $#ARGV) { + if ("$ARGV[$i]" eq "-a") { # backup directory + $i++; $archivedir = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-D") { # Directory Manager + $i++; $rootdn = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-w") { # Directory Manager's password + $i++; $passwd = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-j") { # Read Directory Manager's password from a file + $i++; $passwdfile = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-t") { # database type + $i++; $dbtype = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-v") { # verbose + $verbose = 1; + } else { + &usage; exit(1); + } + $i++; +} +if ($passwdfile ne ""){ +# Open file and get the password + unless (open (RPASS, $passwdfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $passwd = <RPASS>; + chomp($passwd); + close(RPASS); +} elsif ($passwd eq "-"){ +# Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; +# Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $passwd = ReadLine(0); +# chomp($passwd); +# ReadMode('normal'); +} +if ( $rootdn eq "" || $passwd eq "") { &usage; exit(1); } +($s, $m, $h, $dy, $mn, $yr, $wdy, $ydy, $r) = localtime(time); +$mn++; $yr += 1900; +$taskname = "restore_${yr}_${mn}_${dy}_${h}_${m}_${s}"; +if ($archivedir eq "") { + &usage; exit(1); +} +$dn = "dn: cn=$taskname, cn=restore, cn=tasks, cn=config\n"; +$misc = "changetype: add\nobjectclass: top\nobjectclass: extensibleObject\n"; +$cn = "cn: $taskname\n"; +$nsarchivedir = "nsArchiveDir: $archivedir\n"; +$nsdbtype = "nsDatabaseType: $dbtype\n"; +$entry = "${dn}${misc}${cn}${nsarchivedir}${nsdbtype}"; +$vstr = ""; +if ($verbose != 0) { $vstr = "-v"; } +chdir("$dsroot{{SEP}}shared{{SEP}}bin"); +open(FOO, "| $dsroot{{SEP}}shared{{SEP}}bin{{SEP}}ldapmodify $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" ); +print(FOO "$entry"); +close(FOO); diff --git a/ldap/admin/src/scripts/template-cl-dump.pl b/ldap/admin/src/scripts/template-cl-dump.pl new file mode 100755 index 00000000..fe89de2a --- /dev/null +++ b/ldap/admin/src/scripts/template-cl-dump.pl @@ -0,0 +1,307 @@ +#{{PERL-EXEC}} + +################################################################################ +# +# Copyright (C) 2002-2004 Netscape Communications Corporation. +# All rights reserved. +# +# FILE: cl-dump.pl +# +# SYNOPSIS: +# +# cl-dump.pl [-h host] [-p port] [-D bind-dn] -w bind-password | -P bind-cert\ +# [-r replica-roots] [-o output-file] [-c] [-v]\n"; +# +# cl-dump.pl -i changelog-ldif-file-with-base64encoding [-o output-file] [-c]\n"; +# +# DESCRIPTION: +# Dump and decode Netscape Directory Server replication change log +# +# OPTIONS: +# +# -c Dump and interpret CSN only. This option can be used with or +# without -i option. +# +# -D bind-dn +# Directory server's bind DN. Default to "cn=Directory Manager" if +# the option is omitted. +# +# -h host +# Directory server's host. Default to the server where the script +# is running. +# +# -i changelog-ldif-file-with-base64encoding +# If you already have a ldif-like changelog, but the changes +# in that file are encoded, you may use this option to +# decode that ldif-like changelog. +# +# -o output-file +# Path name for the final result. Default to STDOUT if omitted. +# +# -p port +# Directory server's port. Default to 389. +# +# -P bind-cert +# Pathname of binding certificate DB +# +# -r replica-roots +# Specify replica roots whose changelog you want to dump. The replica +# roots may be seperated by comma. All the replica roots would be +# dumped if the option is omitted. +# +# -v Print the version of this script. +# +# -w bind-password +# Password for the bind DN +# +# RESTRICTION: +# If you are not using -i option, the script should be run when the server +# is running, and from where the server's changelog directory is accessible. +# +# DIAGNOSIS: +# For environment variable issues, see script template-repl-monitor.pl under +# DSHOME/bin/slapd/admin/scripts +# +################################################################################ +$usage="Usage: $0 [-h host] [-p port] [-D bind-dn] [-w bind-password | -P bind-cert] [-r replica-roots] [-o output-file] [-c] [-v]\n\n $0 -i changelog-ldif-file-with-base64encoding [-o output-file] [-c]"; + +use Getopt::Std; # Parse command line arguments +use Mozilla::LDAP::Conn; # LDAP module for Perl +use Mozilla::LDAP::Utils; # LULU, utilities. +use Mozilla::LDAP::API; # Used to parse LDAP URL +use MIME::Base64; # Decode + +# Global variables + +$version = "Netscape Directory Server Changelog Dump - Version 1.0"; + +#main +{ + # Turn off buffered I/O + $| = 1; + + # Check for legal options + if (!getopts('h:p:D:w:P:r:o:cvi:')) { + print $usage; + exit -1; + } + + exit -1 if &validateArgs; + + if ($opt_v) { + print OUTPUT "$version\n"; + exit; + } + + if (!$opt_i) { + &cl_dump_and_decode; + } + elsif ($opt_c) { + &grep_csn ($opt_i); + } + else { + &cl_decode ($opt_i); + } + + close (OUTPUT); +} + +# Validate the parameters +sub validateArgs +{ + my ($rc) = 0; + + %ld = Mozilla::LDAP::Utils::ldapArgs(); + chop ($ld{host} = `hostname`) if !$opt_h; + $ld{bind} = "cn=Directory Manager" if !$opt_D; + @allreplicas = ($opt_r) if ($opt_r); + if ($opt_o && ! open (OUTPUT, ">$opt_o")) { + print "Can't create output file $opt_o\n"; + $rc = -1; + } + # Open STDOUT if option -o is missing + open (OUTPUT, ">-") if !$opt_o; + + return $rc; +} + +# Dump and decode changelog +# OUTPUT should have been opened before this call +sub cl_dump_and_decode +{ + # Open the connection + my ($conn) = new Mozilla::LDAP::Conn (\%ld); + if (!$conn) { + print OUTPUT qq/Can't connect to $ld{host}:$ld{port} as "$ld{bind}"\n/; + return -1; + } + + # Get the changelog dir + my ($changelogdir); + my ($entry) = $conn->search ("cn=changelog5,cn=config", "sub", "(objectClass=*)"); + while ($entry) { + $changelogdir = $entry->{"nsslapd-changelogdir"}[0]; + last if $changelogdir; + $entry = $conn->nextEntry (); + } + + # Get all the replicas on the server if -r option is not specified + if (!$opt_r) { + $entry = $conn->search ("cn=mapping tree,cn=config", "sub", + "(objectClass=nsDS5Replica)"); + while ($entry) { + push (@allreplicas, "$entry->{nsDS5ReplicaRoot}[0]"); + $entry = $conn->nextEntry (); + } + } + + # Dump the changelog for the replica + my (@ldifs); + my ($replica); + my ($gotldif); + my ($ldif); + foreach (@allreplicas) { + # Reset the script's start time + $^T = time; + + $replica = $_; + $gotldif = 0; + + # Can't move this line before entering the loop: + # no ldif file generated other than for the first + # replica. + $entry = $conn->newEntry(); + $entry->setDN ("cn=replica,cn=\"$_\",cn=mapping tree,cn=config"); + $entry->setValues('nsDS5Task', 'CL2LDIF'); + $conn->update ($entry); + + #Decode the dumped changelog + @ldifs = <$changelogdir/*.ldif>; + foreach (@ldifs) { + # Skip older ldif files + next if ($#ldifs > 0 && (-M $_ > 0)); + $ldif = $_; + $gotldif = 1; + &print_header ($replica, 0); + if ($opt_c) { + &grep_csn ($_); + } + else { + &cl_decode ($_); + } + # Test op -M doesn't work well so we use rename + # here to avoid reading the same ldif file more + # than once. + rename ($ldif, "$ldif.done"); + } + &print_header ($replica, "Not Found") if !$gotldif; + } + $conn->close; +} + +sub print_header +{ + my ($replica, $ldif) = @_; + print OUTPUT "\n# Replica Root: $replica" if $replica; + print OUTPUT "\n# LDIF File : $ldif\n" if $ldif; +} + +# Grep and interpret CSNs +# OUTPUT should have been opened before this call +sub grep_csn +{ + open (INPUT, "@_") || return; + &print_header (0, @_); + + my ($csn, $maxcsn, $modts); + while (<INPUT>) { + next if ($_ !~ /(csn:)|(ruv:)/i); + if (/ruv:\s*{.+}\s+(\w+)\s+(\w+)\s+(\w*)/i) { + # + # RUV with two CSNs and an optional lastModifiedTime + # + $csn = &csn_to_string($1); + $maxcsn = &csn_to_string($2); + $modts = $3; + if ( $modts =~ /^0+$/ ) { + $modts = ""; + } + else { + $modts = &csn_to_string($modts); + } + } + elsif (/csn:\s*(\w+)\s+/i || /ruv:\s*{.+}\s+(\w+)\s+/i) { + # + # Single CSN + # + $csn = &csn_to_string($1); + $maxcsn = ""; + $modts = ""; + } + else { + printf OUTPUT; + next; + } + chop; + printf OUTPUT "$_ ($csn"; + printf OUTPUT "; $maxcsn" if $maxcsn; + printf OUTPUT "; $modts" if $modts; + printf OUTPUT ")\n"; + } +} + +sub csn_to_string +{ + my ($csn, $tm, $seq, $masterid, $subseq); + my ($sec, $min, $hour, $mday, $mon, $year); + + $csn = "@_"; + return $csn if !$csn; + + ($tm, $seq, $masterid, $subseq) = unpack("a8 a4 a4 a4", $csn); + $tm = hex($tm); + $seq = hex($seq); + $masterid = hex($masterid); + $subseq = hex($subseq); + ($sec, $min, $hour, $mday, $mon, $year) = localtime ($tm); + $mon++; + $year += 1900; + foreach ($sec, $min, $hour, $mday, $mon) { + $_ = "0".$_ if ($_ < 10); + } + $csn = "$mon/$mday/$year $hour:$min:$sec"; + $csn .= " $seq $subseq" if ( $seq != 0 || $subseq != 0 ); + + return $csn; +} + +# Decode the changelog +# OUTPUT should have been opened before this call +sub cl_decode +{ + open (INPUT, "@_") || return; + &print_header (0, @_); + + my ($encoded); + undef $encoded; + while (<INPUT>) { + # Try to accomodate "changes" in 4.X and "change" in 6.X + if (/^changes?::\s*(\S*)/i) { + print OUTPUT "change::\n"; + $encoded = $1; + next; + } + if (!defined ($encoded)) { + print OUTPUT; + next; + } + if ($_ eq "\n") { + print OUTPUT MIME::Base64::decode($encoded); + print OUTPUT "\n"; + undef $encoded; + next; + } + /^\s*(\S+)\s*\n/; + $encoded .= $1; + } +} diff --git a/ldap/admin/src/scripts/template-db2bak.pl b/ldap/admin/src/scripts/template-db2bak.pl new file mode 100644 index 00000000..f9514997 --- /dev/null +++ b/ldap/admin/src/scripts/template-db2bak.pl @@ -0,0 +1,89 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +sub usage { + print(STDERR "Usage: $0 [-v] -D rootdn { -w password | -w - | -j filename } \n"); + print(STDERR " [-a dirname] [-t dbtype]\n"); + print(STDERR " Opts: -D rootdn - Directory Manager\n"); + print(STDERR " : -w password - Directory Manager's password\n"); + print(STDERR " : -w - - Prompt for Directory Manager's password\n"); + print(STDERR " : -j filename - Read Directory Manager's password from file\n"); + print(STDERR " : -a dirname - backup directory\n"); + print(STDERR " : -t dbtype - database type (default: ldbm database)\n"); + print(STDERR " : -v - verbose\n"); +} +$taskname = ""; +$archivedir = ""; +$dbtype = "ldbm database"; +$dsroot = "{{DS-ROOT}}"; +$mydsroot = "{{MY-DS-ROOT}}"; +$verbose = 0; +$rootdn = ""; +$passwd = ""; +$passwdfile = ""; +$i = 0; +while ($i <= $#ARGV) { + if ("$ARGV[$i]" eq "-a") { # backup directory + $i++; $archivedir = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-D") { # Directory Manager + $i++; $rootdn = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-w") { # Directory Manager's password + $i++; $passwd = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-j") { # Read Directory Manager's password from a file + $i++; $passwdfile = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-t") { # database type + $i++; $dbtype = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-v") { # verbose + $verbose = 1; + } else { + &usage; exit(1); + } + $i++; +} +if ($passwdfile ne ""){ +# Open file and get the password + unless (open (RPASS, $passwdfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $passwd = <RPASS>; + chomp($passwd); + close(RPASS); +} elsif ($passwd eq "-"){ +# Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; +# Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $passwd = ReadLine(0); +# chomp($passwd); +# ReadMode('normal'); +} +if ( $rootdn eq "" || $passwd eq "") { &usage; exit(1); } +($s, $m, $h, $dy, $mn, $yr, $wdy, $ydy, $r) = localtime(time); +$mn++; $yr += 1900; +$taskname = "backup_${yr}_${mn}_${dy}_${h}_${m}_${s}"; +if ($archivedir eq "") { + $archivedir = "${mydsroot}{{SEP}}bak{{SEP}}${yr}_${mn}_${dy}_${h}_${m}_${s}"; +} +$dn = "dn: cn=$taskname, cn=backup, cn=tasks, cn=config\n"; +$misc = "changetype: add\nobjectclass: top\nobjectclass: extensibleObject\n"; +$cn = "cn: $taskname\n"; +$nsarchivedir = "nsArchiveDir: $archivedir\n"; +$nsdbtype = "nsDatabaseType: $dbtype\n"; +$entry = "${dn}${misc}${cn}${nsarchivedir}${nsdbtype}"; +$vstr = ""; +if ($verbose != 0) { $vstr = "-v"; } +chdir("$dsroot{{SEP}}shared{{SEP}}bin"); +open(FOO, "| $dsroot{{SEP}}shared{{SEP}}bin{{SEP}}ldapmodify $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" ); +print(FOO "$entry"); +close(FOO); diff --git a/ldap/admin/src/scripts/template-db2index.pl b/ldap/admin/src/scripts/template-db2index.pl new file mode 100644 index 00000000..237cf952 --- /dev/null +++ b/ldap/admin/src/scripts/template-db2index.pl @@ -0,0 +1,195 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +sub usage { + print(STDERR "Usage: $0 [-v] -D rootdn { -w password | -w - | -j filename } \n"); + print(STDERR " -n instance [-t attributeName[:indextypes[:matchingrules]]]\n"); + print(STDERR " Opts: -D rootdn - Directory Manager\n"); + print(STDERR " : -w password - Directory Manager's password\n"); + print(STDERR " : -w - - Prompt for Directory Manager's password\n"); + print(STDERR " : -j filename - Read Directory Manager's password from file\n"); + print(STDERR " : -n instance - instance to be indexed\n"); + print(STDERR " : -t attributeName[:indextypes[:matchingrules]]\n"); + print(STDERR " - attribute: name of the attribute to be indexed\n"); + print(STDERR " If omitted, all the indexes defined \n"); + print(STDERR " for that instance are generated.\n"); + print(STDERR " - indextypes: comma separated index types\n"); + print(STDERR " - matchingrules: comma separated matrules\n"); + print(STDERR " Example: -t foo:eq,pres\n"); + print(STDERR " : -v - version\n"); +} + +$instance = ""; +$rootdn = ""; +$passwd = ""; +$passwdfile = ""; +$attribute_arg = ""; +$vlvattribute_arg = ""; +$verbose = 0; + +$dsroot = "{{DS-ROOT}}"; +$mydsroot = "{{MY-DS-ROOT}}"; + +$i = 0; +while ($i <= $#ARGV) +{ + if ("$ARGV[$i]" eq "-n") + { + # instance + $i++; $instance = $ARGV[$i]; + } + elsif ("$ARGV[$i]" eq "-D") + { + # Directory Manager + $i++; $rootdn = $ARGV[$i]; + } + elsif ("$ARGV[$i]" eq "-w") + { + # Directory Manager's password + $i++; $passwd = $ARGV[$i]; + } + elsif ("$ARGV[$i]" eq "-j") + { + # Read Directory Manager's password from a file + $i++; $passwdfile = $ARGV[$i]; + } + elsif ("$ARGV[$i]" eq "-t") + { + # Attribute to index + $i++; $attribute_arg = $ARGV[$i]; + } + elsif ("$ARGV[$i]" eq "-T") + { + # Vlvattribute to index + $i++; $vlvattribute_arg = $ARGV[$i]; + } + elsif ("$ARGV[$i]" eq "-v") + { + # verbose + $verbose = 1; + } + else + { + &usage; exit(1); + } + $i++; +} + +if ($passwdfile ne ""){ +# Open file and get the password + unless (open (RPASS, $passwdfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $passwd = <RPASS>; + chomp($passwd); + close(RPASS); +} elsif ($passwd eq "-"){ +# Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; +# Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $passwd = ReadLine(0); +# chomp($passwd); +# ReadMode('normal'); +} + +if ( $rootdn eq "" || $passwd eq "" ) +{ + &usage; + exit(1); +} + +$vstr = ""; +if ($verbose != 0) +{ + $vstr = "-v"; +} + +($s, $m, $h, $dy, $mn, $yr, $wdy, $ydy, $r) = localtime(time); +$mn++; $yr += 1900; +$taskname = "db2index_${yr}_${mn}_${dy}_${h}_${m}_${s}"; + +if ( $instance eq "" ) +{ + &usage; + exit(1); +} +else +{ + # No attribute name has been specified: let's get them from the configuration + $attribute=""; + $indexes_list=""; + $vlvattribute=""; + $vlvindexes_list=""; + if ( $attribute_arg eq "" && $vlvattribute_arg eq "" ) + { + # Get the list of indexes from the entry + $indexes_list="$dsroot{{SEP}}shared{{SEP}}bin{{SEP}}ldapsearch $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -s one " . + "-b \"cn=index,cn=\"$instance\", cn=ldbm database,cn=plugins,cn=config\" \"(&(objectclass=*)(nsSystemIndex=false))\" cn"; + + # build the values of the attribute nsIndexAttribute + open(LDAP1, "$indexes_list |"); + while (<LDAP1>) { + s/\n //g; + if (/^cn: (.*)\n/) { + $IndexAttribute="nsIndexAttribute"; + $attribute="$attribute$IndexAttribute: $1\n"; + } + } + close(LDAP1); + if ( $attribute eq "" ) + { + # No attribute to index, just exit + exit(0); + } + + # Get the list of indexes from the entry + $vlvindexes_list="$dsroot{{SEP}}shared{{SEP}}bin{{SEP}}ldapsearch $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -s sub -b \"cn=\"$instance\", cn=ldbm database,cn=plugins,cn=config\" \"objectclass=vlvIndex\" cn"; + + # build the values of the attribute nsIndexVlvAttribute + open(LDAP1, "$vlvindexes_list |"); + while (<LDAP1>) { + s/\n //g; + if (/^cn: (.*)\n/) { + $vlvIndexAttribute="nsIndexVlvAttribute"; + $vlvattribute="$vlvattribute$vlvIndexAttribute: $1\n"; + } + } + close(LDAP1); + } + else + { + if ( $attribute_arg ne "" ) + { + $attribute="nsIndexAttribute: $attribute_arg\n"; + } + if ( $vlvattribute_arg ne "" ) + { + $vlvattribute="nsIndexVlvAttribute: $vlvattribute_arg\n"; + } + } + + # Build the task entry to add + + $dn = "dn: cn=$taskname, cn=index, cn=tasks, cn=config\n"; + $misc = "changetype: add\nobjectclass: top\nobjectclass: extensibleObject\n"; + $cn = "cn: $taskname\n"; + $nsinstance = "nsInstance: ${instance}\n"; + + $entry = "${dn}${misc}${cn}${nsinstance}${attribute}${vlvattribute}"; +} +chdir("$dsroot{{SEP}}shared{{SEP}}bin"); +open(FOO, "| $dsroot{{SEP}}shared{{SEP}}bin{{SEP}}ldapmodify $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" ); +print(FOO "$entry"); +close(FOO); diff --git a/ldap/admin/src/scripts/template-db2ldif.pl b/ldap/admin/src/scripts/template-db2ldif.pl new file mode 100644 index 00000000..cd5b6065 --- /dev/null +++ b/ldap/admin/src/scripts/template-db2ldif.pl @@ -0,0 +1,215 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +sub usage { + print(STDERR "Usage: $0 [-v] -D rootdn { -w password | -w - | -j filename } \n"); + print(STDERR " {-n instance}* | {-s include}* [{-x exclude}*] \n"); + print(STDERR " [-m] [-M] [-u] [-C] [-N] [-U] [-a filename]\n"); + print(STDERR " Opts: -D rootdn - Directory Manager\n"); + print(STDERR " : -w password - Directory Manager's password\n"); + print(STDERR " : -w - - Prompt for Directory Manager's password\n"); + print(STDERR " : -j filename - Read Directory Manager's password from file\n"); + print(STDERR " : -n instance - instance to be exported\n"); + print(STDERR " : -a filename - output ldif file\n"); + print(STDERR " : -s include - included suffix(es)\n"); + print(STDERR " : -x exclude - excluded suffix(es)\n"); + print(STDERR " : -m - minimal base64 encoding\n"); + print(STDERR " : -M - output ldif is stored in multiple files\n"); + print(STDERR " these files are named : <instance>_<filename>\n"); + print(STDERR " by default, all instances are stored in <filename>\n"); + print(STDERR " : -r - export replica\n"); + print(STDERR " : -u - do not export unique id\n"); + print(STDERR " : -C - use main db file only\n"); + print(STDERR " : -N - suppress printing sequential number\n"); + print(STDERR " : -U - output ldif is not folded\n"); + print(STDERR " : -E - Decrypt encrypted data when exporting\n"); + print(STDERR " : -1 - do not print version line\n"); + print(STDERR " : -v - verbose\n"); +} + +@instances = ( + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "" +); +@included = ( + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "" +); +@excluded = ( + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "" +); +$maxidx = 50; +$nowrap = 0; +$nobase64 = 0; +$noversion = 0; +$nouniqueid = 0; +$useid2entry = 0; +$onefile = 1; +$printkey = 1; +$taskname = ""; +$ldiffile = ""; +$doreplica = 0; +$dsroot = "{{DS-ROOT}}"; +$mydsroot = "{{MY-DS-ROOT}}"; +$verbose = 0; +$rootdn = ""; +$passwd = ""; +$passwdfile = ""; +$i = 0; +$insti = 0; +$incli = 0; +$excli = 0; +$decrypt_on_export = 0; +while ($i <= $#ARGV) { + if ( "$ARGV[$i]" eq "-n" ) { # instances + $i++; + if ($insti < $maxidx) { + $instances[$insti] = $ARGV[$i]; $insti++; + } else { + &usage; exit(1); + } + } elsif ("$ARGV[$i]" eq "-s") { # included suffix + $i++; + if ($incli < $maxidx) { + $included[$incli] = $ARGV[$i]; $incli++; + } else { + &usage; exit(1); + } + } elsif ("$ARGV[$i]" eq "-x") { # excluded suffix + $i++; + if ($excli < $maxidx) { + $excluded[$excli] = $ARGV[$i]; $excli++; + } else { + &usage; exit(1); + } + } elsif ("$ARGV[$i]" eq "-a") { # ldif file + $i++; $ldiffile = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-D") { # Directory Manager + $i++; $rootdn = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-w") { # Directory Manager's password + $i++; $passwd = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-j") { # Read Directory Manager's password from a file + $i++; $passwdfile = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-M") { # multiple ldif file + $onefile = 0; + } elsif ("$ARGV[$i]" eq "-o") { # one ldif file + $onefile = 1; + } elsif ("$ARGV[$i]" eq "-u") { # no dump unique id + $nouniqueid = 1; + } elsif ("$ARGV[$i]" eq "-C") { # use id2entry + $useid2entry = 1; + } elsif ("$ARGV[$i]" eq "-N") { # does not print key + $printkey = 0; + } elsif ("$ARGV[$i]" eq "-r") { # export replica + $doreplica = 1; + } elsif ("$ARGV[$i]" eq "-m") { # no base64 + $nobase64 = 1; + } elsif ("$ARGV[$i]" eq "-U") { # no wrap + $nowrap = 1; + } elsif ("$ARGV[$i]" eq "-1") { # no version line + $noversion = 1; + } elsif ("$ARGV[$i]" eq "-E") { # decrypt + $decrypt_on_export = 1; + } elsif ("$ARGV[$i]" eq "-v") { # verbose + $verbose = 1; + } else { + &usage; exit(1); + } + $i++; +} +if ($passwdfile ne ""){ +# Open file and get the password + unless (open (RPASS, $passwdfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $passwd = <RPASS>; + chomp($passwd); + close(RPASS); +} elsif ($passwd eq "-"){ +# Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; +# Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $passwd = ReadLine(0); +# chomp($passwd); +# ReadMode('normal'); +} +if (($instances[0] eq "" && $included[0] eq "") || $rootdn eq "" || $passwd eq "") { &usage; exit(1); } +($s, $m, $h, $dy, $mn, $yr, $wdy, $ydy, $r) = localtime(time); +$mn++; $yr += 1900; +$taskname = "export_${yr}_${mn}_${dy}_${h}_${m}_${s}"; +if ($ldiffile eq "") { + $ldiffile = "${mydsroot}{{SEP}}ldif{{SEP}}${yr}_${mn}_${dy}_${h}_${m}_${s}.ldif"; +} +$dn = "dn: cn=$taskname, cn=export, cn=tasks, cn=config\n"; +$misc = "changetype: add\nobjectclass: top\nobjectclass: extensibleObject\n"; +$cn = "cn: $taskname\n"; +$i = 0; +$nsinstance = ""; +while ("" ne "$instances[$i]") { + $nsinstance = "${nsinstance}nsInstance: $instances[$i]\n"; + $i++; +} +$i = 0; +$nsincluded = ""; +while ("" ne "$included[$i]") { + $nsincluded = "${nsincluded}nsIncludeSuffix: $included[$i]\n"; + $i++; +} +$i = 0; +$nsexcluded = ""; +while ("" ne "$excluded[$i]") { + $nsexcluded = "${nsexcluded}nsExcludeSuffix: $excluded[$i]\n"; + $i++; +} +$nsreplica = ""; +if ($doreplica != 0) { $nsreplica = "nsExportReplica: true\n"; } +$nsnobase64 = ""; +if ($nobase64 != 0) { $nsnobase64 = "nsMinimalEncoding: true\n"; } +$nsnowrap = ""; +if ($nowrap != 0) { $nsnowrap = "nsNoWrap: true\n"; } +$nsnoversion = ""; +if ($noversion != 0) { $nsnoversion = "nsNoVersionLine: true\n"; } +$nsnouniqueid = ""; +if ($nouniqueid != 0) { $nsnouniqueid = "nsDumpUniqId: false\n"; } +$nsuseid2entry = ""; +if ($useid2entry != 0) { $nsuseid2entry = "nsUseId2Entry: true\n"; } +$nsonefile = ""; +if ($onefile != 0) { $nsonefile = "nsUseOneFile: true\n"; } +if ($onefile == 0) { $nsonefile = "nsUseOneFile: false\n"; } +$nsexportdecrypt = ""; +if ($decrypt_on_export != 0) { $nsexportdecrypt = "nsExportDecrypt: true\n"; } +$nsprintkey = ""; +if ($printkey == 0) { $nsprintkey = "nsPrintKey: false\n"; } +$nsldiffile = "nsFilename: ${ldiffile}\n"; +$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsreplica}${nsnobase64}${nsnowrap}${nsnoversion}${nsnouniqueid}${nsuseid2entry}${nsonefile}${nsexportdecrypt}${nsprintkey}${nsldiffile}"; +$vstr = ""; +if ($verbose != 0) { $vstr = "-v"; } +chdir("$dsroot{{SEP}}shared{{SEP}}bin"); +open(FOO, "| $dsroot{{SEP}}shared{{SEP}}bin{{SEP}}ldapmodify $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" ); +print(FOO "$entry"); +close(FOO); diff --git a/ldap/admin/src/scripts/template-dsml-activate.pl b/ldap/admin/src/scripts/template-dsml-activate.pl new file mode 100644 index 00000000..392e164f --- /dev/null +++ b/ldap/admin/src/scripts/template-dsml-activate.pl @@ -0,0 +1,198 @@ +#{{PERL-EXEC}} + +use Getopt::Std; +use File::Copy "cp"; +use warnings; +#use strict; + +sub usage { + print (STDERR "Arguments:\n"); + print (STDERR " -i - install\n"); + print (STDERR " -u - uninstall\n"); + print (STDERR " -p - optional dsml port, defaults to 8080\n\n"); + + exit 100; +} + +# Process the command line arguments +{ + usage() if (!getopts('uip:')); + + $DSMLPORT=8080; + $DSMLPORT=$opt_p if ($opt_p); + my $SERVERNAME = "{{SERVER-NAME}}"; + my $SERVERROOT = "{{DS-ROOT}}"; + my $PATH="{{SEP}}admin-serv{{SEP}}config{{SEP}}"; + my @FILES= ( "server.xml", "web-apps.xml", "obj.conf", "jvm12.conf" ); + + die "-i or -u required" if (!($opt_i || $opt_u)); + die "-i OR -u required" if ($opt_i && $opt_u); + + if ($opt_i) { + if (-e "$SERVERROOT{{SEP}}clients{{SEP}}dsmlgw{{SEP}}dsmlgw.cfg" ) { + print STDERR "leaving existing dsmlgw.cfg untouched.\n"; + } else { + open DSMLCFG, ">$SERVERROOT{{SEP}}clients{{SEP}}dsmlgw{{SEP}}dsmlgw.cfg"; + select DSMLCFG; + print "\#properties file for the Netscape DSMLGW\n\nServerHost=${SERVERNAME}\nServerPort={{SERVER-PORT}}\nBindDN=\nBindPW=\n\n"; + print "MinLoginPool=1\nMaxLoginPool=2\nMinPool=3\nMaxPool=15\n"; + close DSMLCFG; + } + + open WEB, ">$SERVERROOT{{SEP}}clients{{SEP}}dsmlgw{{SEP}}WEB-INF{{SEP}}web.xml"; + select WEB; + print <<EOF; +<?xml version="1.0" encoding="ISO-8859-1"?> + +<!DOCTYPE web-app SYSTEM "../web-app_2_3.dtd"> + +<web-app> + <display-name>Apache-Axis</display-name> + + <listener> + <listener-class>org.apache.axis.transport.http.AxisHTTPSessionListener</listener-class> + </listener> + + <servlet> + <servlet-name>AxisServlet</servlet-name> + <display-name>Apache-Axis Servlet</display-name> + <servlet-class> + org.apache.axis.transport.http.AxisServlet + </servlet-class> + </servlet> + + <servlet-mapping> + <servlet-name>AxisServlet</servlet-name> + <url-pattern>/services/*</url-pattern> + </servlet-mapping> + + <session-config> + <!-- Default to 5 minute session timeouts --> + <session-timeout>5</session-timeout> + </session-config> + + <mime-mapping> + <extension>wsdl</extension> + <mime-type>text/xml</mime-type> + </mime-mapping> + + + <mime-mapping> + <extension>xsd</extension> + <mime-type>text/xml</mime-type> + </mime-mapping> + + <welcome-file-list> + <welcome-file>index.html</welcome-file> + <welcome-file>index.jsp</welcome-file> + <welcome-file>index.jws</welcome-file> + </welcome-file-list> + +</web-app> + +EOF + + + close WEB; + } + + foreach $file (@FILES) { + + if ($opt_u) { + # restore from backups + print STDOUT "${file}.bak -> ${file}\n"; + rename("${SERVERROOT}${PATH}${file}.bak","${SERVERROOT}${PATH}${file}"); + } + if ($opt_i) { + # make backups + print STDOUT "${file} -> ${file}.bak\n"; + cp("${SERVERROOT}${PATH}${file}","${SERVERROOT}${PATH}${file}.bak"); + + if ( $file eq "server.xml") { + open SERVER, "${SERVERROOT}${PATH}${file}" || die("Could not open file!"); + @raw_data=<SERVER>; + close SERVER; + + $i=0; + + while ($line = $raw_data[$i++]) { + #if ($line =~ /CONNECTIONGROUP.*servername=\"([\w.?]+)\"/ ){ + #$SERVERNAME = $1; + #} + + if ($line =~ /\<\/LS/ ) { + splice @raw_data, $i++,0, + (" <LS id=\"dsml-listener\" ip=\"0.0.0.0\" port=\"${DSMLPORT}\" security=\"off\" acceptorthreads=\"1\" blocking=\"no\">\n", + " <CONNECTIONGROUP id=\"dsml_default\" matchingip=\"default\" servername=\"${SERVERNAME}\" defaultvs=\"dsml-serv\"/></LS>\n" ); + $i+=2; + } + + if ($line =~ /\<\/VSCLASS/ ) { + splice @raw_data, $i, 0, + (" <VSCLASS id=\"dsml\" objectfile=\"obj.conf\" rootobject=\"dsmlgw\" acceptlanguage=\"off\">\n" . + "<VARS nice=\"\" docroot=\"${SERVERROOT}{{SEP}}clients{{SEP}}dsmlgw\" webapps_file=\"web-apps.xml\" webapps_enable=\"on\" />\n" . + " <VS id=\"dsml-serv\" state=\"on\" connections=\"dsml_default\" urlhosts=\"${SERVERNAME}\" mime=\"mime1\" aclids=\"acl1\">\n" . + " <USERDB id=\"default\" database=\"default\"/>\n </VS>\n </VSCLASS>\n"); + $i++; + } + + + } + open SERVER, "> ${SERVERROOT}${PATH}${file}" || die("Could not open file!"); + select SERVER; + print @raw_data; + close SERVER; + } + + if ( $file eq "web-apps.xml" ) { + open WEBAPPS, "> ${SERVERROOT}${PATH}${file}"; + select WEBAPPS; + print STDERR "adding necessary entry to $file.\n"; + print <<EOF; +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE vs PUBLIC "-//Netscape Communications Corp.; Netscape//DTD Virtual Server Web Applications 6.1//EN" "http://developer.netscape.com/products/servers/enterprise/dtds/nes-webapps_6_1.dtd"> +<vs> + <web-app uri="/axis" dir="${SERVERROOT}{{SEP}}clients{{SEP}}dsmlgw" enable="true"/> +</vs> + +EOF + + close WEBAPPS; + + } + + if ( $file eq "obj.conf" ) { + open OBJ, ">> ${SERVERROOT}${PATH}${file}"; + select OBJ; + print STDERR "adding necessary entry to $file.\n"; + print <<EOF; +<Object name="dsmlgw"> +ObjectType fn=type-by-extension +ObjectType fn=force-type type=text/plain +Service fn="NSServletService" type="magnus-internal/servlet" +Service method=(GET|HEAD|POST) type=*~magnus-internal/* fn=send-file +Error fn="admin-error" reason="server error" +AddLog fn="admin40_flex_log" name="access" +NameTrans fn="NSServletNameTrans" name="servlet" +PathCheck fn=find-pathinfo +PathCheck fn=find-index index-names="index.html,home.html" +Service type="magnus-internal/jsp" fn="NSServletService" +</Object> + +EOF + + close OBJ; + + + } + + if ( $file eq "jvm12.conf" ) { + open JVM, ">> ${SERVERROOT}${PATH}${file}"; + select JVM; + print STDERR "adding necessary entry to $file.\n"; + print "jvm.option=-Duser.home=${SERVERROOT}{{SEP}}clients{{SEP}}dsmlgw"; + close JVM; + } + } + } +} diff --git a/ldap/admin/src/scripts/template-ldif2db.pl b/ldap/admin/src/scripts/template-ldif2db.pl new file mode 100644 index 00000000..c552af69 --- /dev/null +++ b/ldap/admin/src/scripts/template-ldif2db.pl @@ -0,0 +1,193 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +sub usage { + print(STDERR "Usage: $0 [-v] -D rootdn { -w password | -w - | -j filename } \n"); + print(STDERR " -n instance | {-s include}* [{-x exclude}*] [-O] [-c]\n"); + print(STDERR " [-g [string]] [-G namespace_id] {-i filename}*\n"); + print(STDERR " Opts: -D rootdn - Directory Manager\n"); + print(STDERR " : -w password - Directory Manager's password\n"); + print(STDERR " : -w - - Prompt for Directory Manager's password\n"); + print(STDERR " : -j filename - Read Directory Manager's password from file\n"); + print(STDERR " : -n instance - instance to be imported to\n"); + print(STDERR " : -i filename - input ldif file(s)\n"); + print(STDERR " : -s include - included suffix\n"); + print(STDERR " : -x exclude - excluded suffix(es)\n"); + print(STDERR " : -O - only create core db, no attr indexes\n"); + print(STDERR " : -c size - merge chunk size\n"); + print(STDERR " : -g [string] - string is \"none\" or \"deterministic\"\n"); + print(STDERR " : none - unique id is not generated\n"); + print(STDERR " : deterministic - generate name based unique id (-G name)\n"); + print(STDERR " : by default - generate time based unique id\n"); + print(STDERR " : -G name - namespace id for name based uniqueid (-g deterministic)\n"); + print(STDERR " : -E - Encrypt data when importing\n"); + print(STDERR " : -v - verbose\n"); +} + +@ldiffiles = ( + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "" +); +@included = ( + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "" +); +@excluded = ( + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "" +); +$maxidx = 50; +$instance = ""; +$noattrindexes = 0; +$mergechunksiz = 0; +$genuniqid = "time"; +$uniqidname = ""; +$taskname = ""; +$dsroot = "{{DS-ROOT}}"; +$mydsroot = "{{MY-DS-ROOT}}"; +$verbose = 0; +$rootdn = ""; +$passwd = ""; +$passwdfile = ""; +$i = 0; +$ldifi = 0; +$incli = 0; +$excli = 0; +$encrypt_on_import = 0; +while ($i <= $#ARGV) { + if ( "$ARGV[$i]" eq "-i" ) { # ldiffiles + $i++; + if ($ldifi < $maxidx) { + $ldiffiles[$ldifi] = $ARGV[$i]; $ldifi++; + } else { + &usage; exit(1); + } + } elsif ("$ARGV[$i]" eq "-s") { # included suffix + $i++; + if ($incli < $maxidx) { + $included[$incli] = $ARGV[$i]; $incli++; + } else { + &usage; exit(1); + } + } elsif ("$ARGV[$i]" eq "-x") { # excluded suffix + $i++; + if ($excli < $maxidx) { + $excluded[$excli] = $ARGV[$i]; $excli++; + } else { + &usage; exit(1); + } + } elsif ("$ARGV[$i]" eq "-n") { # instance + $i++; $instance = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-D") { # Directory Manager + $i++; $rootdn = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-w") { # Directory Manager's password + $i++; $passwd = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-j") { # Read Directory Manager's password from a file + $i++; $passwdfile = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-O") { # no attr indexes + $noattrindexes = 1; + } elsif ("$ARGV[$i]" eq "-c") { # merge chunk size + $i++; $mergechunksiz = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-g") { # generate uniqueid + if (("$ARGV[$i+1]" ne "") && !("$ARGV[$i+1]" =~ /^-/)) { + $i++; + if ("$ARGV[$i]" eq "none") { + $genuniqid = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "deterministic") { + $genuniqid = $ARGV[$i]; + } + } + } elsif ("$ARGV[$i]" eq "-G") { # namespace id + $i++; $uniqidname = $ARGV[$i]; + } elsif ("$ARGV[$i]" eq "-v") { # verbose + $verbose = 1; + } elsif ("$ARGV[$i]" eq "-E") { # encrypt on import + $encrypt_on_import = 1; + } else { + &usage; exit(1); + } + $i++; +} +if ($passwdfile ne ""){ +# Open file and get the password + unless (open (RPASS, $passwdfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $passwd = <RPASS>; + chomp($passwd); + close(RPASS); +} elsif ($passwd eq "-"){ +# Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; +# Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $passwd = ReadLine(0); +# chomp($passwd); +# ReadMode('normal'); +} +if (($instance eq "" && $included[0] eq "") || $ldiffiles[0] eq "" || $rootdn eq "" || $passwd eq "") { &usage; exit(1); } +($s, $m, $h, $dy, $mn, $yr, $wdy, $ydy, $r) = localtime(time); +$mn++; $yr += 1900; +$taskname = "import_${yr}_${mn}_${dy}_${h}_${m}_${s}"; +$dn = "dn: cn=$taskname, cn=import, cn=tasks, cn=config\n"; +$misc = "changetype: add\nobjectclass: top\nobjectclass: extensibleObject\n"; +$cn = "cn: $taskname\n"; +if ($instance ne "") { + $nsinstance = "nsInstance: ${instance}\n"; +} +$i = 0; +$nsldiffiles = ""; +while ("" ne "$ldiffiles[$i]") { + $nsldiffiles = "${nsldiffiles}nsFilename: $ldiffiles[$i]\n"; + $i++; +} +$i = 0; +$nsincluded = ""; +while ("" ne "$included[$i]") { + $nsincluded = "${nsincluded}nsIncludeSuffix: $included[$i]\n"; + $i++; +} +$i = 0; +$nsexcluded = ""; +while ("" ne "$excluded[$i]") { + $nsexcluded = "${nsexcluded}nsExcludeSuffix: $excluded[$i]\n"; + $i++; +} +$nsnoattrindexes = ""; +if ($noattrindexes != 0) { $nsnoattrindexes = "nsImportIndexAttrs: false\n"; } +$nsimportencrypt = ""; +if ($encrypt_on_import != 0) { $nsimportencrypt = "nsImportEncrypt: true\n"; } +$nsmergechunksiz = "nsImportChunkSize: ${mergechunksiz}\n"; +$nsgenuniqid = "nsUniqueIdGenerator: ${genuniqid}\n"; +$nsuniqidname = ""; +if ($uniqidname ne "") { $nsuniqidname = "nsUniqueIdGeneratorNamespace: ${uniqidname}\n"; } +$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsldiffiles}${nsnoattrindexes}${nsimportencrypt}${nsmergechunksiz}${nsgenuniqid}${nsuniqidname}"; +$vstr = ""; +if ($verbose != 0) { $vstr = "-v"; } +chdir("$dsroot{{SEP}}shared{{SEP}}bin"); +open(FOO, "| $dsroot{{SEP}}shared{{SEP}}bin{{SEP}}ldapmodify $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" ); +print(FOO "$entry"); +close(FOO); diff --git a/ldap/admin/src/scripts/template-migrate50to51 b/ldap/admin/src/scripts/template-migrate50to51 new file mode 100644 index 00000000..c9c32276 --- /dev/null +++ b/ldap/admin/src/scripts/template-migrate50to51 @@ -0,0 +1,2778 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# Migrate a 5.0 directory server to a 5.1 directory server + +####################################################################################################### +# enable the use of Perldap functions +require DynaLoader; + +use Getopt::Std; +use Mozilla::LDAP::Conn; +use Mozilla::LDAP::Entry; +use Mozilla::LDAP::LDIF; +use Mozilla::LDAP::Utils qw(:all); +use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API +use Time::localtime; +use File::Basename; +use Class::Struct ; + +####################################################################################################### + +sub usage { + print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n"); + print(STDERR " -o oldInstancePath -n newInstancePath [-t tracelevel] [-L logfile]\n"); + print(STDERR "************** parameters in brackets are optionals, others are required **************\n"); + print(STDERR " Opts: -D rootdn - new 5.x Directory Manager\n"); + print(STDERR " : -w password - new 5.x Directory Manager's password\n"); + print(STDERR " : -w - - Prompt for new 5.x Directory Manager's password\n"); + print(STDERR " : -j filename - Read new 5.x Directory Manager's password from file\n"); + print(STDERR " : -p port - new 5.x Directory Server port\n"); + print(STDERR " : -o oldInstancePath - Path of the old instance to migrate \n"); + print(STDERR " : -n newInstancePath - Path of the new 5.x instance\n"); + print(STDERR " : [-t tracelevel] - specify the level of trace (0..3)\n"); + print(STDERR " : [-L logfile] - specify the file to log the migration report \n"); + } +######################################################################################################## + +BEGIN { + + require 'uname.lib' ; + $isNT = -d '\\'; + $PATHSEP = $isNT ? "\\" : "/"; + ${SEP} = $isNT ? ";" : ":" ; + @INC = ( '.', '../../../admin/admin/bin'); + grep { s@/@\\@g } @INC if $isNT; + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + # NT needs quotes around some things unix doesn't + $quote = $isNT ? "\"" : ""; + + # If this variable is set, all file/directory creation will make sure the mode + # and ownership of the destination is the same as the source + $PRESERVE = 1 if (!$isNT); + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + if ($isNT) { + $os = "WINNT"; + } else { + $os = &uname("-s"); + } + if ($isNT) { + # we have to pass batch files directly to the NT command interpreter + $com_spec = $ENV{ComSpec}; + if (!$com_spec) { + $com_spec = $ENV{COMSPEC}; + } + if (!$com_spec || ! -f $com_spec) { + # find the first available command interpreter + foreach $drive (c..z) { + $com_spec = "$drive:\\winnt\\system32\\cmd.exe"; + last if (-f $com_spec); + $com_spec = undef; + } + if (! $com_spec) { + # punt and pray + $com_spec = 'c:\winnt\system32\cmd.exe'; + } + } + } + if ( $os eq "AIX" ) { + $dll_suffix = "_shr.a"; + } + elsif ( $os eq "HP-UX" ) { + $dll_suffix = ".sl"; + } + elsif ( $os eq "WINNT" ) { + $dll_suffix = ".dll"; + } + else { + $dll_suffix = ".so"; + } + $slapdExecName = $isNT ? 'slapd.exe' : 'ns-slapd'; + select STDERR; + $| = 1; + select STDOUT; + $| = 1; +} + +SWITCH: { + if ($os eq "AIX") { + $LIB_PATH = "LIBPATH" ; + last SWITCH ; + } + if ($os eq "HP-UX") { + $LIB_PATH = "SHLIB_PATH" ; + last SWITCH ; + } + if ($isNT) { + $LIB_PATH = "PATH" ; + last SWITCH ; + } + else { + $LIB_PATH = "LD_LIBRARY_PATH" ; + last SWITCH ; + } + } + + # old parameters + ${oldDir} = "" ; + ${oldname} = "" ; + ${oldHome} = "" ; + ${oldConfDir} = "" ; + ${oldlocaluser} ; + ${olduid} ; + ${oldgid} ; + + # new parameters + ${root} = "{{DS-ROOT}}" ; + ${type} = "" ; + ${newname} = "" ; + ${newport} = "" ; + ${rootDN} = "" ; + ${rootpwd} = "" ; + ${localhost} = "" ; + ${LogFileReport} = "" ; + ${newuid} ; + ${localuser} ; + ${newgid} ; + $NO_INPUT_USER = 0 ; # by default user can give inputs during the migration process + ${curdir} = getCwd(); + ${slapdExecDir} = "${root}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + # in 5.1 the replica Id is setup to a static value + $replicaIdvalue = 65535; + + # specify the level of trace + $TRACELEVEL=1; + + $LDAP_SERVER_UNREACHABLE = 81; + + # get input users + &getParameters() ; + ${oldDir} = &normalizeDir("${oldDir}"); + ${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ; + ${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ; + ${oldSchemaDir} = "${oldConfDir}schema${PATHSEP}"; + ${oldDSEldif} = "${oldConfDir}dse.ldif"; + ${serverHome} = "${root}${PATHSEP}$type-$newname" ; + ${schemaDir} = "$serverHome${PATHSEP}config${PATHSEP}schema${PATHSEP}"; + ${DSEldif} = "$serverHome${PATHSEP}config${PATHSEP}dse.ldif"; + ${ldif_rep} = "${oldConfDir}${PATHSEP}ldif${PATHSEP}" ; + ${oldSlapdExecDir} = "${oldDir}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + + open(LOGFILE, ">> $LogFileReport"); + + printTrace("\noldDir: $oldDir, oldHome: $oldHome, \noldConfDir: $oldConfDir, \nldif_rep: $ldif_rep, \nrootDN: $rootDN, \nPort: $newport, \nNewname: $newname\n",3); + printTrace("\nLIB_PATH: $LIB_PATH",4); + + if (!(-d $serverHome)) { + printMsg("\n$serverHome doesn't exist\n"); + exit(1); + } + if (!(-d $oldHome)) { + printMsg("\n$oldHome doesn't exist\n"); + exit(1); + } + + +%HashParametersName = (); + +# The following hash displays only general server parameters to migrate under cn=config +%GeneralSrvParamToMigrate = ( + 'nsslapd-accesscontrol'=> '\n', + 'nsslapd-errorlog-logging-enabled'=> '\n', + 'nsslapd-accesslog-logging-enabled'=> '\n', + 'nsslapd-auditlog-logging-enabled'=> '\n', + 'nsslapd-accesslog-level'=> '\n', + 'nsslapd-accesslog-logbuffering'=> '\n', + 'nsslapd-accesslog-logexpirationtime'=> '\n', + 'nsslapd-accesslog-logexpirationtimeunit'=> '\n', + 'nsslapd-accesslog-logmaxdiskspace'=> '\n', + 'nsslapd-accesslog-logminfreediskspace'=> '\n', + 'nsslapd-accesslog-logrotationtime'=> '\n', + 'nsslapd-accesslog-logrotationtimeunit'=> '\n', + 'nsslapd-accesslog-maxlogsize'=> '\n', + 'nsslapd-accesslog-maxLogsPerDir'=> '\n', + 'nsslapd-attribute-name-exceptions'=> '\n', + 'nsslapd-auditlog-logexpirationtime'=> '\n', + 'nsslapd-auditlog-logexpirationtimeunit'=> '\n', + 'nsslapd-auditlog-logmaxdiskspace'=> '\n', + 'nsslapd-auditlog-logminfreediskspace'=> '\n', + 'nsslapd-auditlog-logrotationtime'=> '\n', + 'nsslapd-auditlog-logrotationtimeunit'=> '\n', + 'nsslapd-auditlog-maxlogsize'=> '\n', + 'nsslapd-auditlog-maxLogsPerDir'=> '\n', + 'nsslapd-certmap-basedn'=> '\n', + 'nsslapd-ds4-compatible-schema'=> '\n', + 'nsslapd-enquote-sup-oc'=> '\n', + 'nsslapd-errorlog-level'=> '\n', + 'nsslapd-errorlog-logexpirationtime'=> '\n', + 'nsslapd-errorlog-logexpirationtimeunit'=> '\n', + 'nsslapd-errorlog-logmaxdiskspace'=> '\n', + 'nsslapd-errorlog-logminfreediskspace'=> '\n', + 'nsslapd-errorlog-logrotationtime'=> '\n', + 'nsslapd-errorlog-logrotationtimeunit'=> '\n', + 'nsslapd-errorlog-maxlogsize'=> '\n', + 'nsslapd-errorlog-maxlogsperdir'=> '\n', + 'nsslapd-groupevalnestlevel'=> '\n', + 'nsslapd-idletimeout'=> '\n', + 'nsslapd-ioblocktimeout'=> '\n', + 'nsslapd-lastmod'=> '\n', + 'nsslapd-listenhost'=> '\n', + 'nsslapd-maxdescriptors'=> '\n', + 'nsslapd-nagle'=> '\n', + 'nsslapd-readonly'=> '\n', + 'nsslapd-referralmode'=> '\n', + 'nsslapd-plugin-depends-on-name'=> '\n', + 'nsslapd-plugin-depends-on-type'=> '\n', + 'nsslapd-referral'=> '\n', + 'nsslapd-reservedescriptors'=> '\n', + 'nsslapd-rootpwstoragescheme'=> '\n', + 'nsslapd-schemacheck'=> '\n', + 'nsslapd-secureport'=> '\n', + 'nsslapd-security'=> '\n', + 'nsslapd-sizelimit'=> '\n', + 'nsslapd-ssl3ciphers'=> '\n', + 'nsslapd-timelimit'=> '\n', + 'passwordchange'=> '\n', + 'passwordchecksyntax'=> '\n', + 'passwordexp'=> '\n', + 'passwordhistory'=> '\n', + 'passwordinhistory'=> '\n', + 'passwordlockout'=> '\n', + 'passwordlockoutduration'=> '\n', + 'passwordmaxage'=> '\n', + 'passwordmaxfailure'=> '\n', + 'passwordminage'=> '\n', + 'passwordminlength'=> '\n', + 'passwordmustchange'=> '\n', + 'passwordresetfailurecount' => '\n', + 'passwordstoragescheme' => '\n', + 'passwordunlock' => '\n', + 'passwordwarning' => '\n' +); + +# the following hash displays global parameters related to database stored under cn=config,cn=ldbm database,cn=plugins,cn=config +%GlobalConfigLDBMparamToMigrate = ( + 'nsslapd-allidsthreshold' => '\n', + 'nsslapd-lookthroughlimit' => '\n', + 'nsslapd-mode' => '\n', + 'nsslapd-dbcachesize' => '\n', + 'nsslapd-cache-autosize' => '\n', + 'nsslapd-cache-autosize-split' => '\n', + 'nsslapd-db-transaction-logging' => '\n', + 'nsslapd-import-cachesize' => '\n' +); + +# the following hash displays specific parameters to each backends and stored under cn=DBname,cn=ldbm database,cn=plugins,cn=config +%LDBMparamToMigrate = ( + 'nsslapd-cachesize' => '\n', + 'nsslapd-cachememsize' => '\n', + 'nsslapd-readonly' => '\n', + 'nsslapd-require-index' => '\n' +); + + +%ChainingConfigParams = ( + 'nsactivechainingcomponents' => '\n', + 'nstransmittedcontrols' => '\n' + ); + +%ChainingDefaultInstanceConfigParams = ( + 'nsabandonedsearchcheckinterval' => '\n', + 'nsbindconnectionslimit' => '\n', + 'nsbindtimeout' => '\n', + 'nsbindretrylimit' => '\n', + 'nshoplimit' => '\n', + 'nsmaxresponsedelay' => '\n', + 'nsmaxtestresponsedelay' => '\n', + 'nschecklocalaci' => '\n', + 'nsconcurrentbindlimit' => '\n', + 'nsconcurrentoperationslimit' => '\n', + 'nsconnectionlife' => '\n', + 'nsoperationconnectionslimit' => '\n', + 'nsproxiedauthorization' => '\n', + 'nsreferralonscopedsearch' => '\n', + 'nsslapd-sizelimit' => '\n', + 'nsslapd-timelimit' => '\n' +); + +%changelog5params = ( + 'nsslapd-changelogmaxage' => '\n', + 'nsslapd-changelogmaxentries' => '\n' + ); + +@SNMPparams = ( + 'nssnmpenabled', + 'nssnmporganization', + 'nssnmplocation', + 'nssnmpcontact', + 'nssnmpdescription', + 'nssnmpmasterhost', + 'nssnmpmasterport', + 'nssnmpenabled', + 'aci' + ); + +%stdIncludes = ( + "." => "\n", + ".." => "\n", + "30ns-common.ldif " => "\n", + "50ns-mail.ldif " => "\n", + "50ns-news.ldif" => "\n", + "50iplanet-servicemgt.ldif"=> "\n", + "50ns-mcd-browser.ldif" => "\n", + "50ns-proxy.ldif" => "\n", + "00core.ldif" => "\n", + "50ns-admin.ldif" => "\n", + "50ns-mcd-config.ldif " => "\n", + "50ns-value.ldif" => "\n", + "05rfc2247.ldif" => "\n", + "50ns-calendar.ldif" => "\n", + "50ns-mcd-li.ldif" => "\n", + "50ns-wcal.ldif" => "\n", + "05rfc2927.ldif" => "\n", + "50ns-certificate.ldif" => "\n", + "50ns-mcd-mail.ldif" => "\n", + "50ns-web.ldif" => "\n", + "10rfc2307.ldif" => "\n", + "50ns-compass.ldif" => "\n", + "50ns-media.ldif" => "\n", + "20subscriber.ldif" => "\n", + "50ns-delegated-admin.ldif"=> "\n", + "50ns-mlm.ldif" => "\n", + "25java-object.ldif" => "\n", + "50ns-directory.ldif" => "\n", + "50ns-msg.ldif" => "\n", + "28pilot.ldif" => "\n", + "50ns-legacy.ldif" => "\n", + "50ns-netshare.ldif" => "\n" +); + + +# Backends migrated (Backend CN attribute value) +@BACKENDS = () ; +# All pairs of suffix-backend are registered in this hashtable +%oldBackends = () ; + +#store the backend instances to migrate +@LDBM_backend_instances = (); + +#store the mapping tree +@Mapping_tree_entries = (); + +#store the suffix and the associated chaining backend +%oldChainingBackends = (); + +#store the multiplexor bind entries to migrate +%MultiplexorBindDNEntriesToMigrate = (); + +#store the Replica bind DN entries to migrate +%ReplicaBindDNEntriesToMigrate = (); + +# list of standard plugin's in version 4 +%stdPlugins = ( + "7-bit check" => "\n", + "acl plugin" => "\n", + "acl preoperation" => "\n", + "binary syntax" => "\n", + "case exact string syntax" => "\n", + "case ignore string syntax" => "\n", + "chaining database" => "\n", + "class of service" => "\n", + "country string syntax" => "\n", + "distinguished name syntax" => "\n", + "generalized time syntax" => "\n", + "integer syntax" => "\n", + "internationalization plugin" => "\n", + "ldbm database" => "\n", + "legacy replication plugin" => "\n", + "multimaster replication plugin" => "\n", + "octet string syntax" => "\n", + "clear" => "\n", + "crypt" => "\n", + "ns-mta-md5" => "\n", + "sha" => "\n", + "ssha" => "\n", + "postal address syntax" => "\n", + "referential integrity postoperation" => "\n", + "retro changelog plugin" => "\n", + "roles plugin" => "\n", + "telephone syntax" => "\n", + "uid uniqueness" => "\n", + "uri syntax" => "\n" + ); + +# list of indexes that have disappeared from the 5.1 schema compared to 5.0 +%deniedIndexes = ( + 'dncomp' => "\n" +); + +@default_indexes = (); +@indexes = (); + +# list of user added Plugin's. In 5.x, they 'll need to be recompiled +@badPlugins = () ; + +@pluginAttrs = ( + "objectclass", + "cn", + "nsslapd-pluginpath", + "nsslapd-plugininitfunc", + "nsslapd-plugintype", + "nsslapd-pluginenabled", + "nsslapd-plugin-depends-on-type", + "nsslapd-pluginid", + "nsslapd-pluginversion", + "nsslapd-pluginvendor" + ); + +@nsds5replicaAttrs = ( + 'objectclass', + 'nsDS5ReplicaRoot', + 'nsDS5ReplicaType', + 'nsDS5ReplicaLegacyConsumer', + 'nsDS5flags', + 'nsDS5ReplicaId', + 'nsDS5ReplicaPurgeDelay', + 'nsDS5ReplicaBinddn', + 'cn', + 'nsDS5ReplicaReferral' + ); + +# array of replicas to migrate +@new51replicas = (); + +# array of replication agreements to migrate +@replicationAgreements = (); + +# Shutdown the legacy Directory instance +printTrace("\nShutdown the legacy Directory Server instance: ${oldHome}",0); +&stopServer($oldDir, 'slapd-'.$oldname); + +# compare LDIF standard config files with standard ones +CompareStdConfigFiles() ; +die "\n\n The version of product you want to migrate is not a 5.x iPlanet Directory Server\n" unless ($oldVersion == 5) ; + +# get the hostname of the new LDAP server +my $LDAPservername = &getLDAPservername(); + +# get the uid and gid of the 5.1 slapd user +($localuser, $newuid, $newgid) = getuid_gid(); +# get the uid and gid of the 5.0 slapd user +($oldlocaluser, $olduid, $oldgid) = getolduid_gid(); +printTrace("\n5.1 localuser: $localuser, uid: $newuid, gid: $newgid",2); +printTrace("\n5.0 localuser: $oldlocaluser, uid: $olduid, gid: $oldgid",2); + +# backup 5.1 configuration files in <root_server51>/slapd-instancename/config +printTrace("\nBackup $serverHome${PATHSEP}config on $serverHome${PATHSEP}config_backup ...",0); +&backupConfigFiles(); + +# migrate the schema (need to stop and start the 5.1 server) +printTrace("\nMigrate the schema...",0); +MigrateSchema(); + +# start the server unless it is already started +&startServer() unless (isDirectoryAlive()); + +############### Connect to the 5.1 LDAP Directory Server ###################### +$ENV{"$LIB_PATH"} = "$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"} ; + +die "\n Migration aborted. Check your 5.0 and 5.1 iPlanet Directory Server are installed on the same machine \n" if ( $LDAPservername == -1 ); +$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + +# Cconnection to 5.1 LDAP server is successful ! +printTrace("\nConnected to $Version.$Minor LDAP server",0) ; + +# Parse the main configuration file: dse.ldif +printTrace("\n\nParse the old DSE ldif file: $oldDSEldif *****",0, 1); +printTrace("\nThis may take a while ...\n",0); +&MigrateDSEldif(); + +#migrate LDBM backend instances +printTrace("\n\nMigrate LDBM backend instances...",0,1); +&migrateLDBM_backend_instances(); + +#migrate mapping tree entries +printTrace("\n\nMigrate mapping tree...",0,1); +&migrateMappingTree(); + +#migrate default indexes +printTrace("\n\nMigrate default indexes...",0,1); +migrateDefaultIndexes(); + +#migrate indexes +printTrace("\n\nMigrate indexes...",0,1); +migrateIndexes(); + +#migrate replicas +printTrace("\n\nMigrate replicas...",0,1); +&MigrateNSDS5_replica(); + +#migrate replication agreements +printTrace("\n\nMigrate replication agreements...",0,1); +&MigrateNSDS_replication_agreement(); + +#migrate key/cert databases +printTrace("\n\nMigrate key/cert databases...",0,1); +&MigrateSSL(); + +# migrate certmap.conf +printTrace("\n\nMigrate Certmap.conf...",0,1); +&MigrateCertmap() ; + +################## Close the connection to 5.1 LDAP Server ##################### +printTrace("\n\n***** Close the LDAP connection to the 5.1 Directory Server instance ***** ",0); +$conn->close; + + +################## stop the 5.x instance and Export/Import the data, restart the server ################## +if (@BACKENDS) { + &stopServer($root,'slapd-'.$newname); + printTrace("\nData processing...\n",0,1) ; + # migrate data for each backend: 5.0 -> LDIF files + &manydb2Ldif($ldif_rep); + + # migrate LDIF data to the 5.1 database: LDIF -> 5.1 + &manyLdif2db($ldif_rep); + printTrace("\n***** Migrate ReplicaBindDN entries...\n",0,1); + &importReplicaBindDNEntries(); + printTrace("\n***** Migrate MultiplexorBindDN entries...\n",0,1); + &importMultiplexorBindDNEntries(); + &startServer() unless (isDirectoryAlive()); +} +else { + printTrace("\nINFORMATION - There are no 5.0 non-standard or non-already existing suffixes to migrate\n",0); + printTrace("\n***** Migrate ReplicaBindDN entries...\n",0,1); + &importReplicaBindDNEntries(); + printTrace("\n***** Migrate MultiplexorBindDN entries...\n",0,1); + &importMultiplexorBindDNEntries(); +} + +printMsg("\n\n ****** End of migration ******\n\n"); + +close(LOGFILE); + + +########################################################################################### +# get input users +sub getParameters { + my $exit = 0 ; + my $i = 0; + my $pwdfile= ""; + + while ($i <= $#ARGV) { + if ( "$ARGV[$i]" eq "-D" ) { # directory manager + if (! $rootDN) { + $rootDN = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-w") { # password + if (! $rootpwd) { + $rootpwd = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-j") { # password file + if (! $pwdfile) { + $pwdfile = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-o") { # 4.x instance path + if (! $oldHome ) { + $oldHome = $ARGV[++$i] ; + grep { s@\\@/@g } $oldHome if $isNT ; + if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; } + if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) { + $oldDir = $1 ; + $type = $2 ; + $oldname = $3 ; + if ($isNT) { + $oldDir = lc($oldDir) ; + $type = lc($type) ; + $oldname = lc($oldname) ; + $oldHome = lc($oldHome) ; + grep { s@/@\\@g } $oldDir ; + grep { s@/@\\@g } $oldHome ; + } + } + else { + print("\nThe old instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-n") { # 5.x instance path + if (! $serverHome ) { + $serverHome = $ARGV[++$i] ; + grep { s@\\@/@g } $root if $isNT ; + grep { s@\\@/@g } $serverHome if $isNT ; + if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; } + if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) { + $root = $1 if ($1); + $type = $2 ; + $newname = $3 ; + if ($isNT) { + $root = lc($root) ; + $type = lc($type) ; + $newname = lc($newname) ; + $serverHome = lc($serverHome) ; + grep { s@/@\\@g } $root ; + grep { s@/@\\@g } $serverHome ; + } + } + else { + print("\nThe 5.x instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-p") { # 5.x DS port + if (! $newport ) { + $newport = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL + my $value = $ARGV[++$i] ; + if ($value =~ /[0-3]/) { + $TRACELEVEL = $value ; + } + else { + print("\nThe tracelevel must belong to 0..3 interval"); + &usage(); + exit(); + } + } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing + $NO_INPUT_USER = 1 ; + } elsif ("$ARGV[$i]" eq "-L") { # migration logfile + $LogFileReport = $ARGV[++$i] ; + } + else { + print("\nThe option $ARGV[$i] is not recognized"); + &usage() ; + exit(1); + } + $i++; + } + if (! $rootDN) { + print("\nThe rootDN is missing"); + $exit = 1; + } + if ($pwdfile ne "") { + # Open file and get the password + unless (open (RPASS, $pwfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $rootpwd = <RPASS>; + chomp($rootpwd); + close(RPASS); + } elsif ($rootpwd eq "-"){ + # Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; + # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $rootpwd = ReadLine(0); +# chomp($rootpwd); +# ReadMode('normal'); + } + if (! $rootpwd) { + print("\nThe rootpwd is missing"); + $exit = 1 ; + } + if (! $newport) { + print("\nThe port is missing"); + $exit = 1; + } + if (! $serverHome) { + print("\nThe new instance path is missing"); + $exit = 1; + } + if (! $oldHome) { + print("\nThe old instance path is missing"); + $exit = 1; + } + if ((! $LogFileReport) && $serverHome) { + ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime(); + $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log"; + } + if ($exit) { + &usage() ; + exit(1); + } + +} + +################################################################################################### + +sub MigrateSchema{ + my $FilesChanged = ""; + my $AllDiffs = ""; + my $NoChanges = "" ; + my $lineToBegin = 0 ; + opendir(SCHEMADIR, $oldSchemaDir) or + die "Error: could not open migrated config dir $oldSchemaDir: $!"; + + foreach $file (readdir(SCHEMADIR)) { + if (! exists($stdIncludes{lc($file)})) { + my $new51file = $schemaDir . $file; + if (-f $new51file ) { + # The ldif file already exists. Make a diff and warn the user if different. + if (diff($new51file, $oldSchemaDir.$file)) { + &stopServer($root,'slapd-'.$newname) if (isDirectoryAlive()); + $AllDiffs .= "\n$file"; + copyBinFile("$oldSchemaDir$file", $new51file); + } + } + else { + &stopServer($root,'slapd-'.$newname) if (isDirectoryAlive()); + $AllDiffs .= "\n$file"; + copyBinFile("$oldSchemaDir$file", $new51file); + } + } + } + closedir(SCHEMADIR); + if ($AllDiffs) { + printMsg("\n\n***********************************************************************"); + printMsg("\nThe following LDIF files have been migrated:"); + printMsg("$AllDiffs"); + printMsg("\n*************************************************************************\n\n"); + } + &startServer() if (! isDirectoryAlive()); +} + + +################################################################################################### +# This subroutine is used to parse the dse.ldif file and call specific routines to act with entries +sub MigrateDSEldif { + printTrace("\nMigrate DSE entries...",1); + my $tempoAlreadyDone = 0; + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + $typeOfEntry = getTypeOfEntry($entry); + SWITCH: { + if ($typeOfEntry eq "LDBM_BACKEND_INSTANCE"){ + parseLDBM_backend_instance($entry); + last SWITCH; + } + if ($typeOfEntry eq "MAPPING_TREE"){ + parseMapping_tree($entry); + last SWITCH; + } + if ($typeOfEntry eq "DEFAULT_INDEX"){ + parseDefaultIndex($entry); + last SWITCH; + } + if ($typeOfEntry eq "INDEX"){ + parseIndex($entry); + last SWITCH; + } + if ($typeOfEntry eq "STANDARD_PLUGIN"){ + migrateStdPlugin($entry); + last SWITCH; + } + if ($typeOfEntry eq "CONFIG_NODE"){ + migrateConfig_Node($entry); + last SWITCH; + } + if ($typeOfEntry eq "CONFIG_LDBM_DATABASE"){ + migrateConfig_LDBM_database($entry); + last SWITCH; + } + if ($typeOfEntry eq "CHAINING_BACKEND_CONFIG"){ + migrateChainingBE_config($entry); + last SWITCH; + } + if ($typeOfEntry eq "CHAINING_BACKEND_INSTANCE"){ + migrateChainingBE_instance($entry); + last SWITCH; + } + if ($typeOfEntry eq "NSDS5_REPLICA"){ + parseNSDS5_replica($entry); + last SWITCH; + } + if ($typeOfEntry eq "NSDS_REPLICATION_AGREEMENT"){ + parseNSDS_replication_agreement($entry); + last SWITCH; + } + if ($typeOfEntry eq "CHANGELOG5"){ + migrateChangelog5($entry); + last SWITCH; + } + if ($typeOfEntry eq "REPLICATION"){ + migrateReplication($entry); + last SWITCH; + } + if ($typeOfEntry eq "SECURITY"){ + migrateSecurity($entry); + last SWITCH; + } + if ($typeOfEntry eq "SNMP"){ + migrateSNMP($entry); + last SWITCH; + } + } + + } + close(DSELDIF); +} + +############################################################################# +# returns the "type of an entry". If the entry is not to be migrated its type is "NOT_MIGRATED_TYPE" + +sub getTypeOfEntry{ + my $entry = shift; + my $DN = $entry->getDN(1) ; # 1 is to normalize the returned DN + if (($DN =~ /cn=ldbm database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsBackendInstance"))) { + return "LDBM_BACKEND_INSTANCE"; + } + if (($DN =~ /cn=mapping tree,cn=config$/i) && (isObjectclass($entry,"nsMappingTree"))) { + return "MAPPING_TREE"; + } + if (($DN =~ /cn=default indexes,cn=config,cn=ldbm database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsIndex"))) { + return "DEFAULT_INDEX"; + } + if (isObjectclass($entry,"nsIndex")) { + return "INDEX"; + } + if ((isObjectclass($entry,"nsSlapdPlugin")) && (isStdPlugin($entry))) { + return "STANDARD_PLUGIN"; + } + if ($DN =~ /^cn=config$/i) { + return "CONFIG_NODE"; + } + if ($DN =~ /^cn=config,cn=ldbm database,cn=plugins,cn=config$/i) { + return "CONFIG_LDBM_DATABASE"; + } + if (($DN =~ /^cn=config,cn=chaining database,cn=plugins,cn=config$/i) || ($DN =~ /^cn=default instance config,cn=chaining database,cn=plugins,cn=config$/i)){ + return "CHAINING_BACKEND_CONFIG"; + } + if (($DN =~ /cn=chaining database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsBackendInstance"))) { + return "CHAINING_BACKEND_INSTANCE"; + } + if (isObjectclass($entry,"nsDS5Replica")) { + return "NSDS5_REPLICA"; + } + if (isObjectclass($entry,"nsDS5ReplicationAgreement")) { + return "NSDS_REPLICATION_AGREEMENT"; + } + if ($DN =~ /^cn=changelog5,cn=config$/i) { + return "CHANGELOG5"; + } + if (($DN =~ /cn=replication,cn=config$/i) && ($DN !~ /^cn=replication,cn=config$/i)) { + return "REPLICATION"; + } + if ($DN =~ /cn=encryption,cn=config$/i) { + return "SECURITY"; + } + if ($DN =~ /^cn=SNMP,cn=config$/i) { + return "SNMP"; + } + return "NOT_MIGRATED_TYPE"; +} + +############################################################################# + + + +############################################################################# +# returns 1 if the objectclass given in parameter is present in the objectclasses values of the entry +# given in parameter, 0 else + +sub isObjectclass { + my $entry = shift; + my $objectclass = shift; + return ($entry->hasValue("objectclass",$objectclass,1)); +} + +############################################################################# + +sub isStdPlugin { + my $entry = shift; + my $CN = $entry->{cn}[0]; + if (isObjectclass($entry,"nsSlapdPlugin")) { + return 1 if ($stdPlugins{lc($CN)}); + } + return 0; +} + + +############################################################################# + +sub alreadyExistsIn51{ + my $entry = shift; + my $mustExist = shift; + my $DN = $entry->getDN(1); # 1 to normalize the DN + return searchEntry($DN, $mustExist); +} + +############################################################################# +sub searchEntry { + my $DN = shift; + my $mustExist = shift; + my $res = $conn->search($DN, "base", "objectclass=*"); + my $cpt = 5; + if ($res) { + return $res; + } + else { + my $errorCode = $conn->getErrorCode(); + while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) { + printMsg("\ntry to reconnect to search $DN"); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + $res = $conn->search($DN, "base", "objectclass=*"); + $errorCode = $conn->getErrorCode(); + $cpt--; + } + if ($res){ + return $res ; + } + elsif (($errorCode eq $LDAP_SERVER_UNREACHABLE) || ($mustExist)) { + my $msg = $conn->getErrorString(); + printMsg("\n\n*** Failed to search: $DN"); + printMsg("\n*** Error Msg: $msg, Error code: $errorCode"); + } + return 0; + } +} + + +############################################################################# + +sub addEntryTo51{ + my $entry = shift; + my $typeOfEntry = shift; + my $trace = shift; + my $res = $conn->add($entry); + my $DN = $entry->getDN(1); + my $cpt = 5; + if ($res) { + printTrace("\n$typeOfEntry - Add successfull: $DN",$trace); + return 1; + } + else { + my $errorCode = $conn->getErrorCode(); + while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) { + printMsg("\ntry to reconnect to add $DN"); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + $res = $conn->add($entry); + $errorCode = $conn->getErrorCode(); + $cpt--; + } + if ($res){ + printTrace("\n$typeOfEntry - Add successfull: $DN",$trace); + return 1; + } + else { + my $msg = $conn->getErrorString(); + printMsg("\n\n*** $typeOfEntry: Add Failed: $DN"); + printMsg("\n*** Error Msg: $msg, Error code: $errorCode"); + return 0; + } + } +} + +############################################################################# + +sub updateEntry{ + my $entry = shift; + my $typeOfEntry = shift; + my $CHECK = shift; + my $trace = shift; + my $cpt = 5; + if ($CHECK) { + if (! hasChanged($entry, $typeOfEntry)) { + return 1; + } + } + my $res = $conn->update($entry); + my $DN = $entry->getDN(1); + if ($res) { + printTrace("\n$typeOfEntry - Update successfull: $DN",$trace); + return 1 ; + } + else { + my $errorCode = $conn->getErrorCode(); + while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) { + printMsg("\ntry to reconnect to update $DN"); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + $res = $conn->update($entry); + $errorCode = $conn->getErrorCode(); + $cpt--; + } + if ($res){ + printTrace("\n$typeOfEntry - Update successfull: $DN",$trace); + return 1; + } + else { + my $msg = $conn->getErrorString(); + printMsg("\n\n*** $typeOfEntry - Update Failed: $DN"); + printMsg("\n*** Error Msg: $msg, Error code: $errorCode"); + return 0; + } + } +} + + +############################################################################# +# returns 1 if the entry to migrate and the current entry are different one another + +sub hasChanged { + my $entry = shift; + my $typeOfEntry = shift; + my $DN = $entry->getDN(1); + my $new51entry = searchEntry($DN,1); + return 1 if (! $new51entry); # we shoudn't be in that case ... + # do the stuff to check wether the entry has changed or not given its type + if (($typeOfEntry eq "DEFAULT_INDEX") || ($typeOfEntry eq "INDEX")){ + my @indexTypes = $entry->getValues("nsIndexType"); + my @new51indexTypes = $new51entry->getValues("nsIndexType"); + my @nsmatchingrules = $entry->getValues("nsmatchingrule"); + my @new51nsmatchingrules = $new51entry->getValues("nsmatchingrule"); + return 1 if (Diffs(\@indexTypes, \@new51indexTypes)); + return 1 if (Diffs(\@nsmatchingrules,\@new51nsmatchingrules)); + return 0; + } + if ($typeOfEntry eq "CHANGELOG5"){ + printTrace("\nCheck wether changelog has changed or not",3); + my @params = keys(%changelog5params); + foreach $param (@params){ + my @values = $entry->getValues($param); + my @new51values = $new51entry->getValues($param); + return 1 if (Diffs(\@values,\@new51values)); + } + return 0; + } + if ($typeOfEntry eq "SNMP"){ + foreach $param (@SNMPparams){ + my @values = $entry->getValues($param); + my @new51values = $new51entry->getValues($param); + return 1 if (Diffs(\@values,\@new51values)); + } + return 0; + } + # we don't know how to compare such type of entry => just return 1 + return 1 ; +} + +sub isAsystemIndex { + my $index = shift; + return ($index->hasValue("nsSystemIndex","true",1)); +} + + +sub updatePathInPluginArgs { + my $plugin = shift; + my $argNum = 0; + my $argPrefix = "nsslapd-pluginarg"; + my $cont = 1; + my $Unix_oldDir = ${oldDir} ; + my $Unix_root = ${root} ; + grep { s@\\@/@g } $Unix_oldDir if $isNT; + grep { s@\\@/@g } $Unix_root if $isNT; + while ($cont) { + my $arg = $argPrefix . $argNum ; + if ($plugin->exists($arg)) { + $_ = $plugin->{$arg}[0] ; + s@$Unix_oldDir@$Unix_root@ig ; + s/$type-$oldname/$type-$newname/ig ; + $plugin->setValues($arg, $_) ; + } + else { + $cont = 0 ; + } + $argNum++; + } + return $plugin; +} + + +sub Diffs { + my $valuesToMigrate = shift; + my $currentValues = shift; + return 1 if (getDiff(\@{$valuesToMigrate},\@{$currentValues})); + return 1 if (getDiff(\@{$currentValues},\@{$valuesToMigrate})); + return 0 ; +} + +sub getDiff { + # we get references to arrays + my $elements = shift ; + my $existing_elements = shift ; + my %count = () ; + my %countEE = () ; + @diff = () ; + foreach $e (@{$elements}, @{$existing_elements}) { $count{$e}++ ;} + foreach $e (@{existing_elements}) { $countEE{$e}++ ;} + foreach $e (@{$elements}) { + # if $e is only present in @$elements, we push it to the diff array + if (($count{$e} == 1) && ($countEE{$e} == 0)) { + push @diff, $e ; + } + } + return @diff ; +} + +sub registerSuffix_Backend { + my $ldbmDatabase = shift; + my $CN = $ldbmDatabase->{cn}[0]; + my $suffixArg = "nsslapd-suffix"; + my $suffix = $ldbmDatabase->{$suffixArg}[0]; + $oldBackends{$suffix} = $CN; +} + + +############################################################################# +# # +# # +# # +############################################################################# +sub migrateLDBM_backend_instances { + foreach $entry (@LDBM_backend_instances) { + my $DN = $entry->getDN(1); # 1 is to normalize the DN + my $CN = $entry->{cn}[0]; + if ($DN =~/cn=netscaperoot,cn=ldbm database/i){ + printTrace("\n\n*** INFORMATION - NetscapeRoot is NOT migrated",0); + } + else { + if(alreadyExistsIn51($entry)){ + printMsg("\n\n*** LDBM_BACKEND_INSTANCE - $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + printTrace("\nWe should add the backend instance $DN",3); + my $suffixarg = "nsslapd-suffix" ; + my $suffixname= $entry->{$suffixarg}[0] ; + my $new51entry = $conn->newEntry() ; + $new51entry->setDN($DN); + $new51entry->setValues("objectclass", "top", "extensibleObject", "nsBackendInstance" ); + $new51entry->setValues("cn", $CN ); + $new51entry->setValues($suffixarg, $suffixname); + my @params = keys(%LDBMparamToMigrate); + foreach $param (@params) { + my @values = $entry->getValues($param); + $new51entry->setValues($param, @values) if (@values); + } + if (addEntryTo51($new51entry, "LDBM_BACKEND_INSTANCE",1)) { + push @BACKENDS, $CN; + } + } + } + } +} + +sub parseLDBM_backend_instance { + my $entry = shift; + ®isterSuffix_Backend($entry); + push @LDBM_backend_instances, $entry; +} + +############################################################################# +sub migrateMappingTree { + foreach $entry (@Mapping_tree_entries) { + my $DN = $entry->getDN(1); # 1 si to normalize the DN + if ($DN =~/cn=\"o=netscaperoot\",cn=mapping tree,cn=config/i){ + # DO NOTHING + } + else { + if(alreadyExistsIn51($entry)){ + printMsg("\n\n*** MAPPING_TREE - $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + addEntryTo51($entry, "MAPPING_TREE",1); + } + } + } +} + + +sub parseMapping_tree{ + my $entry = shift; + push @Mapping_tree_entries, $entry; +} + +############################################################################# +sub migrateDefaultIndexes { + foreach $index (@default_indexes) { + my $CN = $index->{cn}[0]; + my $new51index ; + if ((! isAsystemIndex($index)) && (! $deniedIndexes{lc($CN)})) { + if ($new51index = alreadyExistsIn51($index)) { + if (! isAsystemIndex($new51index)) { + updateEntry($index, "DEFAULT_INDEX", 1, 2); + } + } + else { + addEntryTo51($index, "DEFAULT_INDEX", 2); + } + } + } +} + + +sub parseDefaultIndex{ + my $index = shift; + push @default_indexes, $index; +} + +############################################################################# + +sub migrateIndexes { + foreach $index (@indexes) { + my $CN = $index->{cn}[0]; + my $new51index; + if ((! isAsystemIndex($index)) && (! $deniedIndexes{lc($CN)}) && (DN !~ /cn=netscaperoot,cn=index/i)){ + if ($new51index = alreadyExistsIn51($index)) { + if (! isAsystemIndex($new51index)) { + updateEntry($index, "INDEX", 1, 2); + } + } + else { + addEntryTo51($index, "INDEX", 2); + } + } + } +} + +sub parseIndex{ + my $index = shift; + push @indexes, $index; +} + +############################################################################# + +sub newLDIFplugin { + my $current51plugin = shift; + my $DN = $current51plugin->getDN(1); + my $new51plugin = $conn->newEntry() ; + $new51plugin->setDN($DN); + foreach $Attr (@pluginAttrs) { + my @values = $current51plugin->getValues($Attr); + $new51plugin->setValues($Attr, @values) if (@values); + } + return $new51plugin; +} + +sub migrateStdPlugin{ + my $plugin = shift; + my $DN = $plugin->getDN(1); + my $pluginEnable = "nsslapd-pluginEnabled"; + my $argNum = 0; + my $argPrefix = "nsslapd-pluginarg"; + my $current51plugin ; + if ($current51plugin = alreadyExistsIn51($plugin, 1)) { + $plugin = updatePathInPluginArgs($plugin); + my $pluginEnableValue = $plugin->{$pluginEnable}[0]; + my $cont = 1; + my $pluginHasChanged = 0; + my $new51plugin = &newLDIFplugin($current51plugin); + if (! $current51plugin->hasValue($pluginEnable,$pluginEnableValue,1)){ + $new51plugin->setValues($pluginEnable, $pluginEnableValue); + $pluginHasChanged = 1 unless ($pluginHasChanged); + } + while($cont){ + my $arg = $argPrefix . $argNum ; + if ($plugin->exists($arg)) { + my @values = $plugin->getValues($arg); + my $value = $values[0] ; + $new51plugin->setValues($arg, $value) if (@values); + if ($current51plugin->exists($arg)) { + if (! $current51plugin->hasValue($arg,$value,1)) { + $pluginHasChanged = 1 unless ($pluginHasChanged); + } + } + else { + $pluginHasChanged = 1 unless ($pluginHasChanged); + } + } + else { + if ($current51plugin->exists($arg)) { + # Just Warn the user. Do nothing. + printTrace("\nCompared to 5.0, the current 5.1 plugin $DN belongs this attribute: $arg",2); + } + else { + $cont = 0 ; + } + } + $argNum++; + } + updateEntry($new51plugin, "STANDARD_PLUGIN", 0, 1) if ($pluginHasChanged); + } +} + +############################################################################# + +sub migrateConfig_Node{ + my $config_node = shift; + my @params = keys(%GeneralSrvParamToMigrate); + my $hasChanged = 0; + my $new51config_node; + if ($new51config_node = alreadyExistsIn51($config_node, 1)){ + foreach $param (@params) { + if ($config_node->exists($param)){ + my @valuesToMigrate = $config_node->getValues($param); + if (@valuesToMigrate){ + if ($new51config_node->exists($param)){ + my @currentValues = $new51config_node->getValues($param); + if (Diffs(\@valuesToMigrate, \@currentValues)) { + $new51config_node->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + printTrace("\nParam to update: $param with value @valuesToMigrate",3); + } + } + else { + $new51config_node->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + printTrace("\nParam to update: $param with value @valuesToMigrate",3); + } + } + } + } + updateEntry($new51config_node, "CONFIG_NODE", 0, 1) if ($hasChanged); + } +} + +############################################################################# + +sub migrateConfig_LDBM_database{ + my $config_ldbm = shift; + my @params = keys(%GlobalConfigLDBMparamToMigrate); + my $hasChanged = 0; + my $new51config_ldbm ; + if ($new51config_ldbm = alreadyExistsIn51($config_ldbm, 1)) { + foreach $param (@params) { + if ($config_ldbm->exists($param)){ + my @valuesToMigrate = $config_ldbm->getValues($param); + if (@valuesToMigrate){ + if ($new51config_ldbm->exists($param)){ + my @currentValues = $new51config_ldbm->getValues($param); + if (Diffs(\@valuesToMigrate, \@currentValues)) { + $new51config_ldbm->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + } + } + else { + $new51config_ldbm->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + } + } + } + } + updateEntry($new51config_ldbm, "CONFIG_LDBM_DATABASE", 0, 1) if ($hasChanged); + } +} + +############################################################################# + +sub migrateChainingBE_config{ + my $chaining_config = shift; + my $DN = $chaining_config->getDN(1); + my @params = (); + my $hasChanged = 0; + my $new51chaining_config; + if ($DN =~ /^cn=config,cn=chaining database,cn=plugins,cn=config$/i){ + $new51chaining_config = searchEntry("cn=config,cn=chaining database,cn=plugins,cn=config"); + @params = keys(%ChainingConfigParams); + } + if ($DN =~ /^cn=default instance config,cn=chaining database,cn=plugins,cn=config$/i){ + $new51chaining_config = searchEntry("cn=default instance config,cn=chaining database,cn=plugins,cn=config"); + @params = keys(%ChainingDefaultInstanceConfigParams); + } + foreach $param (@params) { + if ($chaining_config->exists($param)){ + my @valuesToMigrate = $chaining_config->getValues($param); + if (@valuesToMigrate){ + printTrace("\nParam: $param values To migrate: @valuesToMigrate",3); + if ($new51chaining_config->exists($param)){ + my @currentValues = $new51chaining_config->getValues($param); + printTrace("\nParam: $param 51 current values: @currentValues",3); + if (Diffs(\@valuesToMigrate, \@currentValues)) { + $new51chaining_config->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + } + } + else { + $new51chaining_config->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + } + } + } + } + updateEntry($new51chaining_config, "CHAINING_BACKEND_CONFIG", 0, 1) if ($hasChanged); +} + +############################################################################# + +sub registerSuffix_ChainingBE { + my $ldbmDatabase = shift; + my $CN = $ldbmDatabase->{cn}[0]; + my $suffixArg = "nsslapd-suffix"; + my $suffix = $ldbmDatabase->{$suffixArg}[0]; + $oldChainingBackends{$suffix} = $CN; +} + +sub storeMultiplexorBindDN { + my $chaining_instance = shift; + my $DN = $chaining_instance->getDN(1); + if ($chaining_instance->exists("nsMultiplexorBindDN")){ + my $bindDN = $chaining_instance->{nsMultiplexorBindDN}[0]; + my $new51bindDN = searchEntry($bindDN); + if (! $new51bindDN){ + # the bindDN entry doesn't yet exist in 5.1 => it will have to be migrated + $MultiplexorBindDNEntriesToMigrate{$bindDN}="\n" ; + printTrace("\nThe bindDN: $bindDN need to be migrated",3); + } + else { + # do nothing as the entry already exists in 5.1 + } + } + +} + +sub importMultiplexorBindDNEntries { + # import all entries present in @MultiplexorBindDNEntriesToMigrate in 5.1 + my @MultiplexorBindDNs = keys (%MultiplexorBindDNEntriesToMigrate); + my $ldif_dir = $ldif_rep; + foreach $bindDN (@MultiplexorBindDNs) { + printTrace("\nimportMultiplexorBindDNEntries: bindDN to migrate: $bindDN",3); + # get the backend in which is stored the bind DN entry + my $backendtoExportFrom = getBackendtoExportFrom($bindDN); + printTrace("\nbackendtoExportFrom is: $backendtoExportFrom",3); + # check wether the backend has been imported in 5.1 or not + if (! alreadyMigrated($backendtoExportFrom)) { + if ($backendtoExportFrom ne $NULL) { + # if not imported => we need to import the binf DN entry + &startServer() unless (isDirectoryAlive()); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + &ExportAndAddEntry($bindDN, $backendtoExportFrom, $ldif_dir); + } + else { + # do nothing + } + } + } + # remove the empty ldif directory + rmdir($ldif_dir) if (-d $ldif_dir); + # close the LDAP connection to 5.1 + $conn->close if ($conn); +} + +sub migrateChainingBE_instance{ + my $chaining_instance = shift; + my $DN = $chaining_instance->getDN(1); + ®isterSuffix_ChainingBE($chaining_instance); + if (alreadyExistsIn51($chaining_instance)) { + # already exists + printMsg("\n\n*** CHAINING_BACKEND_INSTANCE - $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + &migrate_credential($chaining_instance, "nsmultiplexorcredentials"); + addEntryTo51($chaining_instance, "CHAINING_BACKEND_INSTANCE", 1); + storeMultiplexorBindDN($chaining_instance); + } +} + +############################################################################# + +# create a new LDIF representation of a 5.1 replica consumer +sub newLDIFreplica { + my $replica = shift; + my $DN = $replica->getDN(1); + my $new51replica = $conn->newEntry() ; + my $MASTER_OR_MULTIMASTER = "3" ; + $new51replica->setDN($DN); + foreach $Attr (@nsds5replicaAttrs) { + my @values = $replica->getValues($Attr); + $new51replica->setValues($Attr, @values) if (@values); + } + my $replicaType = $replica->{nsDS5ReplicaType}[0]; + if ($replicaType eq $MASTER_OR_MULTIMASTER) { + my @nsState = $replica->getValues("nsState"); + $new51replica->setValues("nsState", @nsState); + } + else { + $new51replica->setValues("nsDS5ReplicaId", $replicaIdvalue); + } + return $new51replica; +} + +sub MigrateNSDS5_replica{ + foreach $replica (@new51replicas) { + my $DN = $replica->getDN(1); + my $new51replica; + if (alreadyExistsIn51($replica)) { + # replica already exists + printMsg("\n\n*** NSDS5_REPLICA - $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + $new51replica = &newLDIFreplica($replica); + addEntryTo51($new51replica, "NSDS5_REPLICA", 1); + storeReplicaBindDN($replica); + } + } +} + +sub parseNSDS5_replica{ + my $replica = shift; + push @new51replicas, $replica; +} + +sub storeReplicaBindDN { + my $replica = shift; + my $DN = $replica->getDN(1); + if ($replica->exists("nsDS5ReplicaBindDN")){ + my $bindDN = $replica->{nsDS5ReplicaBindDN}[0]; + my $new51bindDN = searchEntry($bindDN); + if (! $new51bindDN){ + # the bindDN entry doesn't yet exist in 5.1 => it will have to be migrated + $ReplicaBindDNEntriesToMigrate{$bindDN}="\n" ; + printTrace("\nThe bindDN: $bindDN need to be migrated",3); + } + else { + # do nothing as the entry already exists in 5.1 + } + } +} + + +sub importReplicaBindDNEntries { + # import all entries present in @ReplicaBindDNEntriesToMigrate in 5.1 + my @ReplicaBindDNs = keys (%ReplicaBindDNEntriesToMigrate); + my $ldif_dir = $ldif_rep; + foreach $bindDN (@ReplicaBindDNs) { + printTrace("\nimportReplicaBindDNEntries: bindDN to migrate: $bindDN",3); + # get the backend in which is stored the bind DN entry + my $backendtoExportFrom = getBackendtoExportFrom($bindDN); + printTrace("\nbackendtoExportFrom is: $backendtoExportFrom",3); + # check wether the backend has been imported in 5.1 or not + if (! alreadyMigrated($backendtoExportFrom)) { + if ($backendtoExportFrom ne $NULL) { + # if not imported => we need to import the binf DN entry + &startServer() unless (isDirectoryAlive()); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + &ExportAndAddEntry($bindDN, $backendtoExportFrom, $ldif_dir); + } + else { + # do nothing + } + } + } + # remove the empty ldif directory + rmdir($ldif_dir) if (-d $ldif_dir); + # close the LDAP connection to 5.1 + $conn->close if ($conn); +} + +sub alreadyMigrated { + my $backendToCheck = shift; + foreach $backend (@BACKENDS) { + return 1 if ($backend eq $backendToCheck); + } + return 0 ; +} + +sub belongsSuffix { + my $suffix = shift; + my $bindDN = shift; + return ($bindDN =~ /$suffix\s*$/i); +} + +sub length { + my $suffix = shift; + my $count = 0; + while ($suffix =~ /./g) { + $count++; + } + return $count ; +} + +sub getBackendtoExportFrom { + my $bindDN = shift ; + my $sizeOfSuffix = 0 ; + my $NULL = ""; + my @oldSuffixes = keys(%oldBackends); + my @oldChainingSuffixes = keys(%oldChainingBackends); + my $bindDN_backend = $NULL; + foreach $suffix (@oldSuffixes){ + printTrace("\ngetBackendtoExportFrom: suffix to compare with is: $suffix",3); + if ((belongsSuffix($suffix,$bindDN)) && (length($suffix) > $sizeOfSuffix)) { + $sizeOfSuffix = length($suffix); + $bindDN_backend = $oldBackends{$suffix}; + printTrace("\ngetBackendtoExportFrom: bindDN_backend: $bindDN_backend, sizeOfSuffix: $sizeOfSuffix",3); + } + } + foreach $suffix (@oldChainingSuffixes){ + printTrace("\ngetBackendtoExportFrom: suffix to compare with is a chained suffix: $suffix",3); + if ((belongsSuffix($suffix,$bindDN)) && (length($suffix) > $sizeOfSuffix)) { + printMsg("\n\n*** Entry stored on a remote backend - $bindDN"); + printMsg("\n*** We don't migrate it"); + return $NULL; + } + } + return $bindDN_backend ; +} + + +sub getBackendtoImportTo { + my $bindDN = shift; + my $sizeOfSuffix = 0; + my $NULL = ""; + my $suffixArg = "nsslapd-suffix"; + my $bindDN_backend = $NULL; + open( DSELDIF, "< $DSEldif" ) || die "Can't open $DSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + $typeOfEntry = getTypeOfEntry($entry); + if ($typeOfEntry eq "LDBM_BACKEND_INSTANCE"){ + my $suffix = $entry->{$suffixArg}[0]; + if ((belongsSuffix($suffix,$bindDN)) && (length($suffix) > $sizeOfSuffix)) { + $sizeOfSuffix = length($suffix); + $bindDN_backend = $entry->{cn}[0]; + } + } + } + close(DSELDIF); + return $bindDN_backend ; +} + + +sub ExportAndAddEntry { + my $DN = shift; + my $backendtoExportFrom = shift; + my $ldif_dir = shift; + my $ldif = "$ldif_dir${PATHSEP}$backendtoExportFrom.ldif" ; + # first: export entry pointed out by the $DN to $ldif file + $ENV{"$LIB_PATH"}="$oldDir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + if (! $ldif_dir) { $ldif_dir = $ldif_rep ;} + if (!(-d $ldif_dir)) { + mkdir($ldif_dir,0777) or die "\ncan't create $ldif_dir to store temporary ldif files\n"; + } + chdir($oldSlapdExecDir) or die "\nCould not change directory to $oldSlapdExecDir: $!\n"; + &db2Ldif($ldif, $backendtoExportFrom, $DN); + chdir($curdir) or die "\nCould not change directory to $curdir: $!\n"; + + # then: Add it to 5.1 + if (! $conn) { + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + } + open( BINDDNLDIF, "< $ldif" ) || die "\nCan't open $ldif: $!: \n"; + my $in = new Mozilla::LDAP::LDIF(*BINDDNLDIF) ; + while ($entry = readOneEntry $in) { + my $entryDN = $entry->getDN(1); + if ($DN eq $entryDN) { + addEntryTo51($entry, "nsds5ReplicaBindDN", 0); + } + } + close(BINDDNLDIF); + # remove the ldif file after the import + unlink($ldif) ; +} + +############################################################################# +sub MigrateNSDS_replication_agreement { + foreach $replicationAgreement (@replicationAgreements) { + my $DN = $replicationAgreement->getDN(1); + if (alreadyExistsIn51($replicationAgreement)){ + # replication agreement already exists + printMsg("\n\n*** NSDS_REPLICATION_AGREEMENT - $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + &migrate_credential($replicationAgreement, "nsDS5ReplicaCredentials"); + addEntryTo51($replicationAgreement, "NSDS_REPLICATION_AGREEMENT", 1); + } + } +} + + +sub parseNSDS_replication_agreement{ + my $replicationAgreement = shift; + push @replicationAgreements, $replicationAgreement ; +} + +############################################################################# + +sub migrateChangelog5{ + my $changelog = shift; + my $DN = $changelog->getDN(1); + my $changelogdir = "nsslapd-changelogdir"; + if (alreadyExistsIn51($changelog)){ + # cn=changelog5,cn=config already exists in 5.1 + my $new51changelog = searchEntry($DN); + my @new51changelodir = $new51changelog->getValues($changelogdir); + $changelog->setValues($changelogdir, @new51changelogdir); + updateEntry($changelog, "CHANGELOG5", 0, 1); + } + else { + # cn=changelog5,cn=config need to be created in 5.1. + # the changelogdir value must be setup to <root_server51>/slapd-instance/changelogdb + $changelog->setValues($changelogdir,"${serverHome}${PATHSEP}changelogdb"); + addEntryTo51($changelog, "CHANGELOG5", 1); + } +} + +############################################################################# + +sub migrateReplication{ + my $replication = shift; + my $DN = $replication->getDN(1); + if (alreadyExistsIn51($replication)){ + # replication agreement already exists + printMsg("\n\n*** $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + addEntryTo51($replication, "REPLICATION", 1); + } +} + +############################################################################# + +sub migrateSecurity{ + my $security = shift; + if (alreadyExistsIn51($security)){ + # already exists in 5.1 + updateEntry($security, "SECURITY", 0, 1); + } + else { + addEntryTo51($security, "SECURITY", 1); + } +} + +############################################################################# + +sub migrateSNMP{ + my $snmp = shift; + if (alreadyExistsIn51($snmp)){ + # already exists in 5.1 + updateEntry($snmp, "SNMP", 0, 1); + } + else { + addEntryTo51($snmp, "SNMP", 1); + } +} + +############################################################################# +# printMsg print message to the user standard output. + +sub printMsg { + + my $TypeMsg = shift ; + my $Msg = shift ; + my $LineNb = shift ; + if ($LineNb) { + printTrace("Line: $LineNb, $TypeMsg, $Msg"); + } + else { + printTrace("$TypeMsg $Msg"); + } +} + +############################################################################# +# print message error to the user standard output. + +sub printTrace { + + my $Msg = shift ; + my $level = shift ; + my $sep = shift ; + + if ($sep) { + print "\n-------------------------------------------------------------------------"; + print LOGFILE "\n-------------------------------------------------------------------------"; + } + + if ($level <= $TRACELEVEL) { + print($Msg); + print LOGFILE $Msg ; + } +} + +############################################################################# +# this subroutine implements a very stupid version of diff + +sub diff { + my $f1 = shift; + my $f2 = shift; + my $lineToBeginWith = shift; + my $NULL = "" ; + my $diff_f1 = $NULL ; + my $diff_f2 = $NULL ; + my $retval = $NULL ; + my $ret; + open(F1, "$f1") or die "Could not open file $f1"; + open(F2, "$f2") or close(F1), die "Could not open file $f2"; + + while (defined($l1 = <F1>)) { + if ($lineToBeginWith){ + $lineToBeginWith -- ; + next ; + } + next if ($l1 =~ /^\#/); + $ret = defined($l2 = <F2>); + if ($ret) { + $ret = defined($l2 = <F2>) while ($ret && ($l2 =~ /^\#/)) ; + if ($ret) { + if (!($l1 eq $l2)) { + + # ignore whitespace + $l1_clean = $l1 ; + $l2_clean = $l2 ; + $l1_clean =~ s/\s//g; + $l2_clean =~ s/\s//g; + + if (!($l1_clean eq $l2_clean)) { + $diff_f1 .= "${l1}" unless ($l1_clean eq $NULL); + $diff_f2 .= "${l2}" unless ($l2_clean eq $NULL); + } + } + } + else { + next if ($l1 =~ /^\s*$/) ; + $diff_f1 .= "${l1}"; + } + } + else { + next if ($l1 =~ /^\s*$/) ; + $diff_f1 .= "${l1}"; + } + } + + while (defined($l2 = <F2>)) { + if (($l2 =~ /^\#/) || ($l2 =~ /^\s*$/)) { + next ; + } + else { + $diff_f2 .= "${l2}" ; + } + } + + close(F1); + close(F2); + + $retval .= "- differences present in your config file but not in standard file:\n\n". "$diff_f1\n" if ($diff_f1) ; + $retval .= "- differences present in standard file but not in your config file:\n\n" . "$diff_f2" if ($diff_f2) ; + return $retval ; +} + +sub CompareStdConfigFiles { + # Compare each configuration file against its default version. If it has changed, + # notify the user that the file has changed and will need to be checked by the + # user. This should be safe to do because there should be no path information + # stored in these conf files, which are just schema stuff. + # printTrace("\nCheck if standard configuration files have changed",3); + + # get the version of the DS to migrate + ($oldVersion, $oldMinor) = &getVersion($oldDir); + # get the version of the new DS + ($Version, $Minor) = &getVersion($root); + + my $origFilePath = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}install${PATHSEP}schema${PATHSEP}" ; + my $FilesChanged = ""; + my $AllDiffs = "***********************************************************************"; + my $NoChanges = "" ; + my $lineToBegin = 0 ; + opendir(CONFDIR, $oldSchemaDir) or + die "Error: could not open migrated config dir $oldConfDir: $!"; + + foreach $file (readdir(CONFDIR)) { + $origFile = $origFilePath . $file ; + $configFile = $oldSchemaDir . $file ; + if (( exists($stdIncludes{lc($file)})) && (-f $origFile)) { + $diffs = &diff($configFile, $origFile, $lineToBegin); + $lineToBegin = 0 if $lineToBegin ; + if ($diffs) { + $FilesChanged .= "\n$configFile"; + $AllDiffs .= "\n$configFile is different than the standard configuration file" ; + $AllDiffs .= "\nYou will need to check this file and make sure its changes are compatible "; + $AllDiffs .= "with the new directory server\nHere are the differences:\n"; + $AllDiffs .= "$diffs \n\n"; + $AllDiffs .= "***********************************************************************"; + } + else { + $NoChanges .= "\n$configFile"; + } + } + } + closedir(CONFDIR); + +if ($FilesChanged) { + printTrace("\nNo changes to old configuration files:$NoChanges",3) ; + printTrace("\n***********************************************************************",3) ; + printMsg("\nThe following standard files have been modified: $FilesChanged"); + if ($NO_INPUT_USER) { + # do nothing + } + else { + printMsg("\nDo you want to see the differences Yes/No [No] ?") ; + my $answer = <STDIN> ; + if ($answer =~ /y|yes/i) { + printMsg("$AllDiffs"); + } + printMsg("\nDo you want to continue the migration Yes/No [No] ?"); + $answer = <STDIN> ; + if (! ($answer =~ /y|yes/i)) { + exit(1); + } + } + } +} + + + +############################################################################# + +# this is used to run the system() call, capture exit and signal codes, +# and die() upon badness; the first argument is a directory to change +# dir to, if any, and the rest are passed to system() +sub mySystem { + my $rc = &mySystemNoDie(@_); + my ($dir, @args) = @_; + if ($rc == 0) { +# success + } elsif ($rc == 0xff00) { + die "Error executing @args: error code $rc: $!"; + } elsif ($rc > 0x80) { + $rc >>= 8; + die "Error executing @args: error code $rc: $!"; + } else { + if ($rc & 0x80) { + $rc &= ~0x80; + } + die "Error executing @args: received signal $rc: $!"; + } + + # usually won't get return value + return $rc; +} + +# This version does not die but just returns the error code +sub mySystemNoDie { + my ($dir, @args) = @_; + if ($dir && ($dir ne "")) { + chdir($dir) or die "Could not change directory to $dir: $!"; + } + my $cmd = $args[0]; + # the system {$cmd} avoids some NT shell quoting problems if the $cmd + # needs to be quoted e.g. contains spaces; the map puts double quotes + # around the arguments on NT which are stripped by the command + # interpreter cmd.exe; but don't quote things which are already quoted + my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @args; + my $rc = 0; + if ($cmd =~ /[.](bat|cmd)$/) { + # we have to pass batch files directly to the NT command interpreter + $cmd = $com_spec; +# print "system $cmd /c \"@fixargs\"\n"; + $rc = 0xffff & system {$cmd} '/c', "\"@fixargs\""; + } else { +# print "system $cmd @fixargs\n"; + $rc = 0xffff & system {$cmd} @fixargs; + } + chdir(${curdir}) or die "Could not change directory to $curdir: $!"; + return $rc; +} + +########################################################################################### +# # +# Export/Import of the backends in @BACKENDS # +# # +########################################################################################### + +sub manydb2Ldif { + my $ldif_dir = shift; + $ENV{"$LIB_PATH"}="$oldDir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + if (! $ldif_dir) { $ldif_dir = $ldif_rep ;} + if (!(-d $ldif_dir)) { + mkdir($ldif_dir,0777) or die "can't create $ldif_dir to store temporary ldif files"; + } + chdir($oldSlapdExecDir) or die "Could not change directory to $oldSlapdExecDir: $!"; + foreach $backend (@BACKENDS) { + my $ldif = "${ldif_dir}$backend.ldif" ; + &db2Ldif($ldif, $backend); + } + print " Done.\n"; + chdir($curdir) or die "Could not change directory to $curdir: $!"; +} + +sub db2Ldif { + my $ldif = shift ; + my $backend = shift ; + my $include_suffix = shift ; + my $db2ldif_param ; + if ($include_suffix) { + $db2ldif_param = "db2ldif -D $oldHome -n $backend -a $ldif -s \"$include_suffix\""; + } + else { + $db2ldif_param = "db2ldif -D $oldHome -n $backend -a $ldif"; + } + open(DB2LDIF, "${quote}${quote}$slapdExecName${quote} $db2ldif_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n"; + sleep(1); # allow some data to accumulate in the pipe + my $ii = 0; + while (<DB2LDIF>) { + ++$ii; + if (($ii % 250) == 0) { + printMsg(" Processing...\n"); + } + printMsg($_); + } + close(DB2LDIF); + # set the ownership of the ldif file; should be the same as the 5.x slapd user id + if ((! $isNt) && ($oldlocaluser ne $localuser)) { + if (-f $ldif) { + chown( $newuid, $newgid, $ldif) or printMsg("\nUnable to change the ownership of $ldif to $localuser") ; + } + } +} + +sub manyLdif2db { + my $ldif_dir = shift; + $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + chdir($slapdExecDir) or die "Could not change directory to $slapdExecDir: $!"; + foreach $backend (@BACKENDS) { + my $ldif = "${ldif_dir}$backend.ldif" ; + &Ldif2db($ldif, $backend); + } + # remove the empty ldif directory + rmdir($ldif_dir); + chdir($curdir) or die "Could not change directory to $curdir: $!"; +} + + +sub Ldif2db { + my $ldif = shift ; + my $backend = shift ; + my $ldif2db_param = "ldif2db -D $serverHome -n $backend -i $ldif"; + open(LDIF2DB, "${quote}${quote}$slapdExecName${quote} $ldif2db_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n"; + sleep(1); # allow some data to accumulate in the pipe + while (<LDIF2DB>) { + printMsg($_); + } + close(LDIF2DB); + # remove the ldif file after the import + unlink($ldif) ; +} + + +########################################################################################### +# # +# Running/Stopping the Server # +# # +########################################################################################### + + + +sub isDirectoryAlive { + die "\n Migration aborted. Check your 5.0 and 5.1 iPlanet Directory Server are installed on the same machine \n" if ( $LDAPservername == -1 ); + my $test_conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd); + if ($test_conn) { + $test_conn->close(); + return 1; + } + else { + return 0 ; + } +} + + +sub startServer { + my $instanceDir = ${serverHome} ; + my $errLog = $instanceDir . $PATHSEP . 'logs' . $PATHSEP . 'errors'; + # emulate tail -f + # if the last line we see does not contain "slapd started", try again + my $done = 0; + my $started = 0; + my $code = 0; + my $lastLine = ""; + my $timeout = time + 240; # 4 minutes + $ENV{"$LIB_PATH"}="${root}${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + + my $startCmd = $instanceDir . $PATHSEP . 'start' . $script_suffix; + if (! -f $startCmd) { + $startCmd = $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix; + } + $code = &mySystem($instanceDir,$startCmd); + open(IN, $errLog) or die "Could not open error log $errLog: $!"; + my $pos = tell(IN); + while (($done == 0) && (time < $timeout)) { + for (; ($done == 0) && ($_ = <IN>); $pos = tell(IN)) { + $lastLine = $_; + # print; + # the server has already been started and shutdown once . . . + if (/slapd started\./) { + $started++; + if ($started == 2) { + $done = 1; + } + # sometimes the server will fail to come up; in that case, restart it + } elsif (/Initialization Failed/) { + # print "Server failed to start: $_"; + $code = &mySystem($instanceDir, $startCmd); + # sometimes the server will fail to come up; in that case, restart it + } elsif (/exiting\./) { + # print "Server failed to start: $_"; + #$code = &mySystem($startCmd); + $code = &mySystem($instanceDir, $startCmd); + } + } + if ($lastLine =~ /PR_Bind/) { + # server port conflicts with another one, just report and punt + print $lastLine; + print "This server cannot be started until the other server on this\n"; + print "port is shutdown.\n"; + $done = 1; + } + if ($done == 0) { + # rest a bit, then . . . + sleep(2); + # . . . reset the EOF status of the file desc + seek(IN, $pos, 0); + } + } + close(IN); + + sleep(5); + die "\nUnable to start the $Version.$Minor iPlanet Directory Server\n" unless (isDirectoryAlive()); + + return 0; +} + +sub stopServer { + my $root = shift; + my $name = shift; + $maxStopIterations = 5; + print "\nShutting down server $name . . .\n"; + $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop' . $script_suffix . $quote; + if (! -f $stopCmd) { + $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop-slapd' . $script_suffix . $quote; + } + + if (! -f $stopCmd) { + # no stop command, probably a 1.X system; for NT, we'll try net stop + # for unix, we'll get the pid and kill it + if ($isNT) { + $stopCmd = 'net stop ' . $name; + } else { + # see if there is a pid file + $pidfile = $root . $PATHSEP . $name . $PATHSEP . 'logs' . + $PATHSEP . 'pid'; + if (open(PIDFILE, $pidfile)) { + chomp($pid = <PIDFILE>); + close(PIDFILE); + while ($maxStopIterations-- && !$exitCode) { + $exitCode = kill(15, $pid); + } + $stopCmd = undef; + } + } + } + + # keep looping until the stop cmd returns an error code, which usually + # means that what ever we want to stop is stopped, or some other error + # occurred e.g. permission, or no such service + $exitCode = &runAndIgnoreOutput($stopCmd); +# print "stopServer: exitCode=$exitCode\n"; + while ($stopCmd && $maxStopIterations-- && $exitCode) { + $exitCode = &runAndIgnoreOutput($stopCmd); +# print "stopServer: exitCode=$exitCode\n"; + } + + if (!$maxStopIterations) { + print "Warning: could not shutdown the server: $!\n"; + } + sleep(10) ; + $exitCode = 0; +} + + +sub runAndIgnoreOutput { + my $cmd = shift; + printMsg("."); + open(RUNCMD, "${quote}$cmd${quote} 2>&1 |") or die "Error: could not run $cmd: $!"; + printMsg("."); + sleep(1); # allow pipe to fill with data + printMsg("."); + while (<RUNCMD>) { +# print; + } + my $code = close(RUNCMD); +# print "runAndIgnore: code=$code status=$?\n"; + return $?; +} + +############################################################################# +# migrate SSL info + +sub MigrateSSL { + my $secPwd = 'bidon' ; + # copy the SSL directory + ©Dir("$oldHome${PATHSEP}ssl","$serverHome${PATHSEP}ssl") if (-d "$oldHome${PATHSEP}ssl"); + # copy the cert db and key files + if ( -d "$oldDir${PATHSEP}alias") { + $aliasDir = "$root${PATHSEP}alias"; + if (! -d $aliasDir) { + mkdir($aliasDir, 0750); + } + my $keydb = "$aliasDir${PATHSEP}slapd-$newname-key3.db" ; + my $certdb = "$aliasDir${PATHSEP}slapd-$newname-cert7.db" ; + my $old_keydb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-key3.db" ; + my $old_certdb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-cert7.db"; + my $keydb_backup = "$aliasDir${PATHSEP}slapd-$newname-key3.db_backup" ; + my $certdb_backup = "$aliasDir${PATHSEP}slapd-$newname-cert7.db_backup" ; + if (-f $old_keydb) { + if (-f $keydb) { + if ($NO_INPUT_USER) { + printMsg("\n$keydb already exists. backup in $keydb_backup ..."); + ©BinFile($keydb,$keydb_backup); + ©BinFile($old_keydb,$keydb); + } + else { + print("\n\n$keydb already exists. Do you want to overwrite it ? [no]: "); + my $answer = <STDIN> ; + if ($answer =~ /^y|yes$/i) { + ©BinFile($old_keydb,$keydb); + } + } + } + else { + ©BinFile($old_keydb,$keydb); + } + } + if (-f $old_certdb) { + if (-f $certdb) { + if ($NO_INPUT_USER) { + printMsg("\n$certdb already exists. backup in $certdb_backup ..."); + ©BinFile($certdb,$certdb_backup); + ©BinFile($old_certdb,$certdb); + } + else { + print("\n\n$certdb already exists. Do you want to overwrite it ? [no]: "); + my $answer = <STDIN> ; + if ($answer =~ /^y|yes$/i) { + ©BinFile($old_certdb,$certdb); + } + } + } + else { + ©BinFile($old_certdb,$certdb); + } + } + # copy the old password file + if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") { + ©BinFile( + "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt", + "$aliasDir${PATHSEP}$type-$newname-pin.txt" + ); + } + } + +} + +sub DisableSSL { + my $entry = $conn->search("cn=config","base","objectclass=*"); + my $LDAPparam = "nsslapd-security" ; + my $Value = "off" ; + if ($entry->{$LDAPparam}[0] ne $Value) { + printTrace("\nDisable SSL...",1); + $entry->setValues($LDAPparam, $Value); + } + my $res = $conn->update($entry); + if ($res) { + printTrace("\nSSL disabled",2); + } + else { + printMsg("\nCan't disabled SSL. The server may have problems to start"); + } +} + +# enable the migration of client authentication informations +sub MigrateCertmap { + # backup the old certmap.conf and replace it with the new one + my $oldCertmap = "$oldDir${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf"; + my $newCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf" ; + my $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ; + if (-f $oldCertmap) { + if ($NO_INPUT_USER) { + printMsg("\n$newCertmap has been backup in $backupCertmap"); + ©BinFile($newCertmap,$backupCertmap); + ©BinFile($oldCertmap,$newCertmap); + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\n\nWhere do you want to back up the file $newCertmap [$backupCertmap] ?") ; + my $Answer = <STDIN> ; + $backupCertmap = $Answer if ($Answer ne "\n"); + chomp($backupCertmap); + printTrace("\nDest: .$backupCertmap.",4); + if (-e $backupCertmap) { + printMsg("\n\n$backupCertmap already exists. Do you want to overwrite it Yes/No [No] ?") ; + if (<STDIN> =~ /yes|y/i) { + $Ask = 0 ; + } + else { + $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ; + } + } + else { + $Ask = 0 ; + } + } + printTrace("\nBackup file: $newCertmap in $backupCertmap",4); + ©BinFile($newCertmap,$backupCertmap); + ©BinFile($oldCertmap,$newCertmap); + } + } + else { + } +} + +sub hasChangedoldCertmap { + my $certmapfile = shift ; + my @reference = ("certmap default default", + "default:DNComps", + "default:FilterComps e") ; + my $cpt = 0 ; + printTrace("\nhasChangedoldCertmap",3); + open(CERTMAP,"< $certmapfile"); + while (<CERTMAP>) { + if ((! /^\s*#/) && (! /^\s*$/)) { + my $ref = $reference[$cpt] ; + printTrace("\nValue: $_, ref: $ref",4); + if (! /^\s*$ref\s*$/) { + return 1 ; + } + else { + $cpt++ ; + } + } + } + close (CERTMAP); + printTrace("\ncpt: $cpt",4); + if ($cpt < $#reference) { + return 1 ; + } + else { + return 0 ; + } +} + + +########################################################################################### +# # +# Copy directory and files functions # +# # +########################################################################################### + + +sub copyDir { + my $src = shift; + my $dest = shift; + my $exclude = shift; + + opendir( SRC, $src ) or die "Can't open directory $src: $!: "; + my $mode; + my $uid; + my $gid; + mkdir ( $dest , 0755 ) or die "\nCan't create directory $dest. \nPlease check you have enough rights to create it and/or check that your parent directory exists.\n" if !( -e $dest ); + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + local ( @files ) = readdir ( SRC ); + closedir( SRC ); + for ( @files ) { + if ( $_ eq "." || $_ eq ".." ) { + next; + } elsif ( $exclude && /$exclude/ ) { + next; + } elsif( -d "$src${PATHSEP}$_") { + ©Dir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" ); + } else { + ©BinFile ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_"); + } + } +} + +sub copyBinFile { + my $src = shift; + my $dest = shift; + my $buf = ""; + my $bufsize = 8192; + + open( SRC, $src ) || die "Can't open $src: $!\n"; + # if we are given a directory destination instead of a file, extract the + # filename portion of the source to use as the destination filename + if (-d $dest) { + $dest = $dest . $PATHSEP . &basename($src); + } + open( DEST, ">$dest" ) || die "Can't create $dest: $!\n"; + binmode SRC; + binmode DEST; + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + while (read(SRC, $buf, $bufsize)) { + print DEST $buf; + } + close( SRC ); + close( DEST ); +} + +############################################################################################################# +# backup 5.x configuration files # +# backup the directory <root_server5>/slapd-instance/config dans <root_server5>/slapd-instance/BackupConfig # # +# # +############################################################################################################# + + +sub backupConfigFiles { + # backup the 5.x config files + my $src = "$serverHome${PATHSEP}config" ; + my $dest = "$serverHome${PATHSEP}config_backup" ; + if ($NO_INPUT_USER) { + printMsg("\n$src has been backup in $dest"); + ©Dir($src,$dest); + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\n\nWhere do you want to back up your configuration directory [$dest] ?") ; + my $Answer = <STDIN> ; + $dest = $Answer if ($Answer ne "\n"); + chomp($dest); + printTrace("\nDest: .$dest.",4); + if (-e $dest) { + printMsg("\n\n$dest already exists. Do you want to overwrite it Yes/No [No] ?") ; + if (<STDIN> =~ /yes|y/i) { + $Ask = 0 ; + } + else { + $dest = "$serverHome${PATHSEP}config_backup" ; + } + } + else { + $Ask = 0 ; + } + } + printTrace("\nBackup Directory: $src in $dest",4); + ©Dir($src,$dest); + } +} +############################################################################# + +sub getLDAPservername { + my $oldLDAPservername; + my $LDAPservername; + my $localhost = "nsslapd-localhost"; + open(OLDDSELDIF, "< $oldDSEldif") or die "\nError: could not open old config file $oldDSEldif \n"; + my $in = new Mozilla::LDAP::LDIF(*OLDDSELDIF) ; + while ($entry = readOneEntry $in) { + my $DN = $entry->getDN(1) ; + if ($DN =~ /^cn=config$/i) { + my @values = $entry->getValues($localhost); + if ($entry->size($localhost)) { + $oldLDAPservername = $values[0]; + printTrace("\nName of the old LDAP server: $oldLDAPservername",3); + } + break; + } + } + close(OLDSELDIF); + + open( DSELDIF, "< $DSEldif" ) || die "\nCan't open $DSEldif \n"; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + my $DN = $entry->getDN(1) ; + if ($DN =~ /^cn=config$/i) { + my @values = $entry->getValues($localhost); + if ($entry->size($localhost)) { + $LDAPservername = $values[0]; + printTrace("\nName of the new LDAP server: $LDAPservername",3); + } + break; + } + } + close(DSELDIF); + # check ol and new Directory Instance are installed on the same physical machine. + if (lc($oldLDAPservername) ne lc($LDAPservername)) { + # warn the user he tries to migrate a 4.x server installed on a different machine from the 5.x one + printMsg("\n\nYour old instance is on $oldLDAPservername, whereas your new instance is on $LDAPservername. Migration on different machines is not supported. Do you want to continue ? Yes/No [No]:") ; + if (! (<STDIN> =~ /yes|y/i)) { + return -1; + } + } + return $LDAPservername ; +} + +############################################################################# + +sub getVersion { + my $dir = shift; + my $version = 0; + my $minor = 0; + my $buildNumber = 0; + my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}"; + + # find the slapd executable + $prog = $dir . $progDir . $slapdExecName; + if (! -f $prog) { + $prog = $dir . $progDir2 . $slapdExecName; + if (-f $prog && $isNT) { + # if slapd is in bin/slapd and we're on NT, just assume version 1; + # apparently, slapd.exe doesn't like the -v argument . . . + return ( '1', $minor ); + } + else{ + die "Could not run slapd program $prog: $!"; + } + } + else { + chdir($dir . $progDir) or die "Could not change directory to $dir$progDir: $!";; + } + $ENV{"$LIB_PATH"}="$dir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + # read the old version from the old slapd program + + open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or + die "Could not run slapd program $prog: $!"; + sleep(1); # allow some data to accumulate in the pipe +# print "Output from $prog -v:\n"; + while (<F>) { + #print; + if (/^Netscape-Directory\/(\d+)\.(\d+)\s+(\S+)/) { + $version = $1; + $minor = $2; + $buildNumber = $3; + last; + } + elsif (/^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ... + $version = $1; + $minor = $2; + $buildNumber = $3; + last; + } + elsif (/^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) { + $version = $1; + $minor = $2; + $buildNumber = $3; + last; + } + } + $code = close(F); +# print "$prog returned code=$code status=$?\n"; + $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + + if ($version == 0) { + die "\nCould not determine version of the directory server in $dir: \n"; + } + + # distinguish the 4.1 and the 4.11 thanks to the buildNumber + if (($version == 4) && ($minor == 1)){ + if (! ($buildNumber =~ /^B99\.16/)) { + # it's not a 4.1 Netscape Directory Server => it's a 4.11 + $minor = 11 ; + } + } + chdir($curdir) or die "Could not change directory to $curdir: $!" ; + return ( $version, $minor ); +} + + +############################################################################################### +sub normalizeDir { + my $dir = shift ; + my $dir_prec = "" ; + while ($dir_prec ne $dir) { + $dir_prec = $dir ; + if ($isNT) { + grep { s@\\\\@\\@g } $dir ; + } + else { + grep { s@//@/@g } $dir ; + } + } + return $dir ; +} + + +############################################################################################### + +sub GetTime { + my $tm = localtime; + (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900); + $sec = "0$sec" unless $sec > 9 ; + $min = "0$min" unless $min > 9 ; + $hour = "0$hour" unless $hour > 9 ; + $dd = "0$dd" unless $dd > 9 ; + $mm = "0$mm" unless $mm > 9 ; + return ($sec, $min, $hour, $dd, $mm, $yy); +} + +############################################################################################### +# get uid and group id of the 5.x slapd server. +# The uid is done through the nsslapd-localuser attribute + +sub getuid_gid { + my $newuid ; + my $newgid ; + my $localuser ; + my $localuser_attr = "nsslapd-localuser" ; + if (! $isNT) { + &startServer() unless (isDirectoryAlive()); + my $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n"; + my $entry = $conn->search("cn=config ", "base","objectclass=*", 0, ($localuser_attr)) ; + # Tests wether we succeed to get the entry cn=config + die "\nCan't get the entry cn=config \n" unless ($entry); + my @values = $entry->getValues($localuser_attr); + $conn->close(); + if ($#values == -1 || ($values[0] eq "") ) { # tests wether the nsslapd-localuser attribute has a value + printMsg("\nNo localuser has been found in the configuration of the directory. "); + if ($NO_INPUT_USER) { + printMsg("\nWe considered nobody as the localuser"); + $localuser = "nobody" ; + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\nUnder what user does your $Version.$Minor directory server run [nobody] ? ") ; + $localuser = <STDIN> ; + chomp($localuser); + $localuser = "nobody" if ($localuser eq ""); + ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ; + if ($newuid) { + $Ask = 0 ; + } + else { + printMsg("\nError: $localuser is unknown from the system "); + } + } + } + } + else { + $localuser = $values[0]; # returns the first value (we should only have one localuser) + my $size = $#values ; + } + ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ; + return ($localuser, $newuid, $newgid) ; + } + else { + return () ; + } +} + +sub getolduid_gid { + my $oldlocaluser ; + my $localuserAttr = "nsslapd-localuser"; + my $entry ; + if (! $isNT) { + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + $typeOfEntry = getTypeOfEntry($entry); + if ($typeOfEntry eq "CONFIG_NODE") { + $oldlocaluser = $entry->{$localuserAttr}[0] if ($entry->exists($localuserAttr)); + break ; + } + } + close(DSE); + ($olduid, $oldgid) = (getpwnam("$oldlocaluser"))[2..3] ; + return ($oldlocaluser, $olduid, $oldgid) ; + } + else { + return (); + } +} +############################################################################################### +# get current directory + +sub getCwd { + my $command = $isNT ? "cd" : "/bin/pwd"; + open(PWDCMD, "$command 2>&1 |") or + die "Error: could not execute $command: $!"; + # without the following sleep, reading from the pipe will + # return nothing; I guess it gives the pwd command time + # to get some data to read . . . + sleep(1); + my $currentdir; + while (<PWDCMD>) { + if (!$currentdir) { + chomp($currentdir = $_); + } + } + my $code = close(PWDCMD); +# if ($code || $?) { +# print "$command returned code=$code status=$? dir=$curdir\n"; +# } +# print "getCwd curdir=\[$curdir\]\n"; + return $currentdir; +} + +################################ +# Need to migrate the credential. +# If the credential can not be migrated, leave it at it is +################################ +sub migrate_credential{ + my $entry_to_modify = shift; + my $credentials_attr = shift; + my @old_value = $entry_to_modify->getValues($credentials_attr); + my $migratecredExecName = 'migratecred'; + + my @new_cred = `${quote}${quote}$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}admin${PATHSEP}bin${PATHSEP}$migratecredExecName${quote} -o $oldHome -n $serverHome -c @old_value`; + + if ( $? == 0 ) + { + $entry_to_modify->setValues($credentials_attr, @new_cred); + } +} + diff --git a/ldap/admin/src/scripts/template-migrate5to6 b/ldap/admin/src/scripts/template-migrate5to6 new file mode 100644 index 00000000..3cc5bd58 --- /dev/null +++ b/ldap/admin/src/scripts/template-migrate5to6 @@ -0,0 +1,3043 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# Migrate a 5.x directory server to a 6.2 directory server + +####################################################################################################### +# enable the use of Perldap functions +require DynaLoader; + +use Getopt::Std; +use Mozilla::LDAP::Conn; +use Mozilla::LDAP::Entry; +use Mozilla::LDAP::LDIF; +use Mozilla::LDAP::Utils qw(:all); +use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API +use Time::localtime; +use File::Basename; +use Class::Struct ; + +####################################################################################################### + +sub usage { + print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n"); + print(STDERR " -o oldInstancePath -n newInstancePath [-t tracelevel] [-L logfile]\n"); + print(STDERR "************** parameters in brackets are optionals, others are required **************\n"); + print(STDERR " Opts: -D rootdn - new 6.2 Directory Manager\n"); + print(STDERR " : -w password - new 6.2 Directory Manager's password\n"); + print(STDERR " : -w - - Prompt for new 6.2 Directory Manager's password\n"); + print(STDERR " : -j filename - Read new 6.2 Directory Manager's password from file\n"); + print(STDERR " : -p port - new 6.2 Directory Server port\n"); + print(STDERR " : -o oldInstancePath - Path of the old instance to migrate \n"); + print(STDERR " : -n newInstancePath - Path of the new 6.2 instance\n"); + print(STDERR " : [-d dataPath] - Path to directory containing data files to import into new instance\n"); + print(STDERR " : [-v oldVersion] - Version of old instance (obtained by running $slapdExecName -v\n"); + print(STDERR " : [-t tracelevel] - (optional) specify the level of trace (0..3)\n"); + print(STDERR " : [-L logfile] - (optional) specify the file to log the migration report \n"); + } +######################################################################################################## + +BEGIN { + + require 'uname.lib' ; + $isNT = -d '\\'; + $PATHSEP = $isNT ? "\\" : "/"; + ${SEP} = $isNT ? ";" : ":" ; + @INC = ( '.', '../../../admin/admin/bin'); + grep { s@/@\\@g } @INC if $isNT; + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + # NT needs quotes around some things unix doesn't + $quote = $isNT ? "\"" : ""; + + # If this variable is set, all file/directory creation will make sure the mode + # and ownership of the destination is the same as the source + $PRESERVE = 1 if (!$isNT); + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + if ($isNT) { + $os = "WINNT"; + } else { + $os = &uname("-s"); + } + if ($isNT) { + # we have to pass batch files directly to the NT command interpreter + $com_spec = $ENV{ComSpec}; + if (!$com_spec) { + $com_spec = $ENV{COMSPEC}; + } + if (!$com_spec || ! -f $com_spec) { + # find the first available command interpreter + foreach $drive (c..z) { + $com_spec = "$drive:\\winnt\\system32\\cmd.exe"; + last if (-f $com_spec); + $com_spec = undef; + } + if (! $com_spec) { + # punt and pray + $com_spec = 'c:\winnt\system32\cmd.exe'; + } + } + } + if ( $os eq "AIX" ) { + $dll_suffix = "_shr.a"; + } + elsif ( $os eq "HP-UX" ) { + $dll_suffix = ".sl"; + } + elsif ( $os eq "WINNT" ) { + $dll_suffix = ".dll"; + } + else { + $dll_suffix = ".so"; + } + $slapdExecName = $isNT ? 'slapd.exe' : './ns-slapd'; + select STDERR; + $| = 1; + select STDOUT; + $| = 1; +} + +SWITCH: { + if ($os eq "AIX") { + $LIB_PATH = "LIBPATH" ; + last SWITCH ; + } + if ($os eq "HP-UX") { + $LIB_PATH = "SHLIB_PATH" ; + last SWITCH ; + } + if ($isNT) { + $LIB_PATH = "PATH" ; + last SWITCH ; + } + else { + $LIB_PATH = "LD_LIBRARY_PATH" ; + last SWITCH ; + } + } + + # old parameters + ${oldDir} = "" ; + ${oldname} = "" ; + ${oldHome} = "" ; + ${oldConfDir} = "" ; + ${oldlocaluser} ; + ${olduid} ; + ${oldgid} ; + + # new parameters + ${root} = "{{DS-ROOT}}" ; + ${type} = "" ; + ${newname} = "" ; + ${newport} = "" ; + ${rootDN} = "" ; + ${rootpwd} = "" ; + ${localhost} = "" ; + ${LogFileReport} = "" ; + ${newuid} ; + ${localuser} ; + ${newgid} ; + $NO_INPUT_USER = 0 ; # by default user can give inputs during the migration process + ${curdir} = getCwd(); + ${slapdExecDir} = "${root}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + # in 6.2 the replica Id is setup to a static value + $replicaIdvalue = 65535; + + # specify the level of trace + $TRACELEVEL=1; + + $LDAP_SERVER_UNREACHABLE = 81; + + # get input users + &getParameters() ; + ${oldDir} = &normalizeDir("${oldDir}"); + ${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ; + ${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ; + ${oldSchemaDir} = "${oldConfDir}schema${PATHSEP}"; + ${oldDSEldif} = "${oldConfDir}dse.ldif"; + ${serverHome} = "${root}${PATHSEP}$type-$newname" ; + ${schemaDir} = "$serverHome${PATHSEP}config${PATHSEP}schema${PATHSEP}"; + ${DSEldif} = "$serverHome${PATHSEP}config${PATHSEP}dse.ldif"; + ${ldif_rep} = "${oldConfDir}ldif${PATHSEP}" ; + ${oldSlapdExecDir} = "${oldDir}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + + open(LOGFILE, ">> $LogFileReport"); + + printTrace("\noldDir: $oldDir, oldHome: $oldHome, \noldConfDir: $oldConfDir, \nldif_rep: $ldif_rep, \nrootDN: $rootDN, \nPort: $newport, \nNewname: $newname\n",3); + printTrace("\nLIB_PATH: $LIB_PATH",4); + + if (!(-d $serverHome)) { + printMsg("\n$serverHome doesn't exist\n"); + exit(1); + } + if (!(-d $oldHome)) { + printMsg("\n$oldHome doesn't exist\n"); + exit(1); + } + + if ($olddatadir && !(-d $olddatadir)) { + print("\n$olddatadir doesn't exist\n"); + exit(1); + } + + +%HashParametersName = (); + +# The following hash displays only general server parameters to migrate under cn=config +%GeneralSrvParamToMigrate = ( + 'nsslapd-accesscontrol'=> '\n', + 'nsslapd-errorlog-logging-enabled'=> '\n', + 'nsslapd-accesslog-logging-enabled'=> '\n', + 'nsslapd-auditlog-logging-enabled'=> '\n', + 'nsslapd-accesslog-level'=> '\n', + 'nsslapd-accesslog-logbuffering'=> '\n', + 'nsslapd-accesslog-logexpirationtime'=> '\n', + 'nsslapd-accesslog-logexpirationtimeunit'=> '\n', + 'nsslapd-accesslog-logmaxdiskspace'=> '\n', + 'nsslapd-accesslog-logminfreediskspace'=> '\n', + 'nsslapd-accesslog-logrotationtime'=> '\n', + 'nsslapd-accesslog-logrotationtimeunit'=> '\n', + 'nsslapd-accesslog-maxlogsize'=> '\n', + 'nsslapd-accesslog-maxLogsPerDir'=> '\n', + 'nsslapd-attribute-name-exceptions'=> '\n', + 'nsslapd-auditlog-logexpirationtime'=> '\n', + 'nsslapd-auditlog-logexpirationtimeunit'=> '\n', + 'nsslapd-auditlog-logmaxdiskspace'=> '\n', + 'nsslapd-auditlog-logminfreediskspace'=> '\n', + 'nsslapd-auditlog-logrotationtime'=> '\n', + 'nsslapd-auditlog-logrotationtimeunit'=> '\n', + 'nsslapd-auditlog-maxlogsize'=> '\n', + 'nsslapd-auditlog-maxLogsPerDir'=> '\n', + 'nsslapd-certmap-basedn'=> '\n', + 'nsslapd-ds4-compatible-schema'=> '\n', + 'nsslapd-enquote-sup-oc'=> '\n', + 'nsslapd-errorlog-level'=> '\n', + 'nsslapd-errorlog-logexpirationtime'=> '\n', + 'nsslapd-errorlog-logexpirationtimeunit'=> '\n', + 'nsslapd-errorlog-logmaxdiskspace'=> '\n', + 'nsslapd-errorlog-logminfreediskspace'=> '\n', + 'nsslapd-errorlog-logrotationtime'=> '\n', + 'nsslapd-errorlog-logrotationtimeunit'=> '\n', + 'nsslapd-errorlog-maxlogsize'=> '\n', + 'nsslapd-errorlog-maxlogsperdir'=> '\n', + 'nsslapd-groupevalnestlevel'=> '\n', + 'nsslapd-idletimeout'=> '\n', + 'nsslapd-ioblocktimeout'=> '\n', + 'nsslapd-lastmod'=> '\n', + 'nsslapd-listenhost'=> '\n', + 'nsslapd-maxdescriptors'=> '\n', + 'nsslapd-nagle'=> '\n', + 'nsslapd-readonly'=> '\n', + 'nsslapd-referralmode'=> '\n', + 'nsslapd-plugin-depends-on-name'=> '\n', + 'nsslapd-plugin-depends-on-type'=> '\n', + 'nsslapd-referral'=> '\n', + 'nsslapd-reservedescriptors'=> '\n', + 'nsslapd-rootpwstoragescheme'=> '\n', + 'nsslapd-schemacheck'=> '\n', + 'nsslapd-secureport'=> '\n', + 'nsslapd-security'=> '\n', + 'nsslapd-sizelimit'=> '\n', + 'nsslapd-ssl3ciphers'=> '\n', + 'nsslapd-timelimit'=> '\n', + 'passwordchange'=> '\n', + 'passwordchecksyntax'=> '\n', + 'passwordexp'=> '\n', + 'passwordhistory'=> '\n', + 'passwordinhistory'=> '\n', + 'passwordlockout'=> '\n', + 'passwordlockoutduration'=> '\n', + 'passwordmaxage'=> '\n', + 'passwordmaxfailure'=> '\n', + 'passwordminage'=> '\n', + 'passwordminlength'=> '\n', + 'passwordmustchange'=> '\n', + 'passwordresetfailurecount' => '\n', + 'passwordstoragescheme' => '\n', + 'passwordunlock' => '\n', + 'passwordwarning' => '\n' +); + +# the following hash displays global parameters related to database stored under cn=config,cn=ldbm database,cn=plugins,cn=config +%GlobalConfigLDBMparamToMigrate = ( + 'nsslapd-allidsthreshold' => '\n', + 'nsslapd-lookthroughlimit' => '\n', + 'nsslapd-mode' => '\n', + 'nsslapd-dbcachesize' => '\n', + 'nsslapd-cache-autosize' => '\n', + 'nsslapd-cache-autosize-split' => '\n', + 'nsslapd-db-transaction-logging' => '\n', + 'nsslapd-import-cachesize' => '\n' +); + +# the following hash displays specific parameters to each backends and stored under cn=DBname,cn=ldbm database,cn=plugins,cn=config +%LDBMparamToMigrate = ( + 'nsslapd-cachesize' => '\n', + 'nsslapd-cachememsize' => '\n', + 'nsslapd-readonly' => '\n', + 'nsslapd-require-index' => '\n' +); + + +%ChainingConfigParams = ( + 'nsactivechainingcomponents' => '\n', + 'nstransmittedcontrols' => '\n' + ); + +%ChainingDefaultInstanceConfigParams = ( + 'nsabandonedsearchcheckinterval' => '\n', + 'nsbindconnectionslimit' => '\n', + 'nsbindtimeout' => '\n', + 'nsbindretrylimit' => '\n', + 'nshoplimit' => '\n', + 'nsmaxresponsedelay' => '\n', + 'nsmaxtestresponsedelay' => '\n', + 'nschecklocalaci' => '\n', + 'nsconcurrentbindlimit' => '\n', + 'nsconcurrentoperationslimit' => '\n', + 'nsconnectionlife' => '\n', + 'nsoperationconnectionslimit' => '\n', + 'nsproxiedauthorization' => '\n', + 'nsreferralonscopedsearch' => '\n', + 'nsslapd-sizelimit' => '\n', + 'nsslapd-timelimit' => '\n' +); + +%changelog5params = ( + 'nsslapd-changelogmaxage' => '\n', + 'nsslapd-changelogmaxentries' => '\n' + ); + +@SNMPparams = ( + 'nssnmpenabled', + 'nssnmporganization', + 'nssnmplocation', + 'nssnmpcontact', + 'nssnmpdescription', + 'nssnmpmasterhost', + 'nssnmpmasterport', + 'nssnmpenabled', + 'aci' + ); + +%stdIncludes = ( + "." => "\n", + ".." => "\n", + "30ns-common.ldif " => "\n", + "50ns-mail.ldif " => "\n", + "50ns-news.ldif" => "\n", + "50iplanet-servicemgt.ldif"=> "\n", + "50netscape-servicemgt.ldif"=> "\n", + "50ns-mcd-browser.ldif" => "\n", + "50ns-proxy.ldif" => "\n", + "00core.ldif" => "\n", + "50ns-admin.ldif" => "\n", + "50ns-mcd-config.ldif " => "\n", + "50ns-value.ldif" => "\n", + "05rfc2247.ldif" => "\n", + "50ns-calendar.ldif" => "\n", + "50ns-mcd-li.ldif" => "\n", + "50ns-wcal.ldif" => "\n", + "05rfc2927.ldif" => "\n", + "50ns-certificate.ldif" => "\n", + "50ns-mcd-mail.ldif" => "\n", + "50ns-web.ldif" => "\n", + "10rfc2307.ldif" => "\n", + "50ns-compass.ldif" => "\n", + "50ns-media.ldif" => "\n", + "20subscriber.ldif" => "\n", + "50ns-delegated-admin.ldif"=> "\n", + "50ns-mlm.ldif" => "\n", + "25java-object.ldif" => "\n", + "50ns-directory.ldif" => "\n", + "50ns-msg.ldif" => "\n", + "28pilot.ldif" => "\n", + "50ns-legacy.ldif" => "\n", + "50ns-netshare.ldif" => "\n" +); + + +# Backends migrated (Backend CN attribute value) +@BACKENDS = () ; +# All pairs of suffix-backend are registered in this hashtable +%oldBackends = () ; + +#store the backend instances to migrate +@LDBM_backend_instances = (); + +#store the mapping tree +@Mapping_tree_entries = (); + +#store the suffix and the associated chaining backend +%oldChainingBackends = (); + +#store the multiplexor bind entries to migrate +%MultiplexorBindDNEntriesToMigrate = (); + +#store the Replica bind DN entries to migrate +%ReplicaBindDNEntriesToMigrate = (); + +# list of standard plugins +%stdPlugins = ( + "7-bit check" => "\n", + "acl plugin" => "\n", + "acl preoperation" => "\n", + "binary syntax" => "\n", + "case exact string syntax" => "\n", + "case ignore string syntax" => "\n", + "chaining database" => "\n", + "class of service" => "\n", + "country string syntax" => "\n", + "distinguished name syntax" => "\n", + "generalized time syntax" => "\n", + "integer syntax" => "\n", + "internationalization plugin" => "\n", + "ldbm database" => "\n", + "legacy replication plugin" => "\n", + "multimaster replication plugin" => "\n", + "octet string syntax" => "\n", + "clear" => "\n", + "crypt" => "\n", + "ns-mta-md5" => "\n", + "sha" => "\n", + "ssha" => "\n", + "postal address syntax" => "\n", + "referential integrity postoperation" => "\n", + "retro changelog plugin" => "\n", + "roles plugin" => "\n", + "telephone syntax" => "\n", + "uid uniqueness" => "\n", + "uri syntax" => "\n" + ); + +# list of indexes that have disappeared from the new schema compared to 5.0 +%deniedIndexes = ( + 'dncomp' => "\n" +); + +@default_indexes = (); +@indexes = (); + +# list of user added Plugin's. In 6.2, they 'll need to be recompiled +@badPlugins = () ; + +@pluginAttrs = ( + "objectclass", + "cn", + "nsslapd-pluginpath", + "nsslapd-plugininitfunc", + "nsslapd-plugintype", + "nsslapd-pluginenabled", + "nsslapd-plugin-depends-on-type", + "nsslapd-pluginid", + "nsslapd-pluginversion", + "nsslapd-pluginvendor" + ); + +@nsds5replicaAttrs = ( + 'objectclass', + 'nsDS5ReplicaRoot', + 'nsDS5ReplicaType', + 'nsDS5ReplicaLegacyConsumer', + 'nsDS5flags', + 'nsDS5ReplicaId', + 'nsDS5ReplicaPurgeDelay', + 'nsDS5ReplicaBinddn', + 'cn', + 'nsDS5ReplicaReferral' + ); + +# array of replicas to migrate +@new6replicas = (); + +# array of replication agreements to migrate +@replicationAgreements = (); + +# compare LDIF standard config files with standard ones +CompareStdConfigFiles() ; +die "\n\n The version of product you want to migrate is not a 5.x Directory Server\n" unless ($oldVersion == 5) ; + +# Shutdown the legacy Directory instance +printTrace("\nShutdown the legacy Directory Server instance: ${oldHome}",0); +&stopServer($oldDir, 'slapd-'.$oldname); + +# get the hostname of the new LDAP server +my $LDAPservername = &getLDAPservername(); + +# get the uid and gid of the 6.2 slapd user +($localuser, $newuid, $newgid) = getuid_gid(); +# get the uid and gid of the 5.x slapd user +($oldlocaluser, $olduid, $oldgid) = getolduid_gid(); +printTrace("\n6.2 localuser: $localuser, uid: $newuid, gid: $newgid",2); +printTrace("\n5.x localuser: $oldlocaluser, uid: $olduid, gid: $oldgid",2); + +# backup 6.2 configuration files in <6server_root>/slapd-instancename/config +printTrace("\nBackup $serverHome${PATHSEP}config on $serverHome${PATHSEP}config_backup ...",0); +&backupConfigFiles(); + +# migrate the schema (need to stop and start the 6.2 server) +printTrace("\nMigrate the schema...",0); +MigrateSchema(); + +# start the server unless it is already started +&startServer() unless (isDirectoryAlive()); + +############### Connect to the 6.2 LDAP Directory Server ###################### +$ENV{"$LIB_PATH"} = $new_libpath; + +die "\n Migration aborted. Make sure your old and new Directory Server are installed on the same machine \n" if ( $LDAPservername == -1 ); +$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + +# Cconnection to 6.2 LDAP server is successful ! +printTrace("\nConnected to $Version.$Minor LDAP server",0) ; + +# Parse the main configuration file: dse.ldif +printTrace("\n\nParse the old DSE ldif file: $oldDSEldif *****",0, 1); +printTrace("\nThis may take a while ...\n",0); +&MigrateDSEldif(); + +#migrate LDBM backend instances +printTrace("\n\nMigrate LDBM backend instances...",0,1); +&migrateLDBM_backend_instances(); + +#migrate mapping tree entries +printTrace("\n\nMigrate mapping tree...",0,1); +&migrateMappingTree(); + +#migrate default indexes +printTrace("\n\nMigrate default indexes...",0,1); +migrateDefaultIndexes(); + +#migrate indexes +printTrace("\n\nMigrate indexes...",0,1); +migrateIndexes(); + +#migrate replicas +printTrace("\n\nMigrate replicas...",0,1); +&MigrateNSDS5_replica(); + +#migrate replication agreements +printTrace("\n\nMigrate replication agreements...",0,1); +&MigrateNSDS_replication_agreement(); + +#migrate key/cert databases +printTrace("\n\nMigrate key/cert databases...",0,1); +&MigrateSSL(); + +# migrate certmap.conf +printTrace("\n\nMigrate Certmap.conf...",0,1); +&MigrateCertmap() ; + +################## Close the connection to 6.2 LDAP Server ##################### +printTrace("\n\n***** Close the LDAP connection to the new Directory Server instance ***** ",0); +$conn->close; + + +################## stop the new instance and Export/Import the data, restart the server ################## +if (@BACKENDS) { + &stopServer($root,'slapd-'.$newname); + if ($olddatadir) { + printTrace("\nData already contained in $olddatadir...\n",0,1) ; + $ldif_rep = "$olddatadir${PATHSEP}"; + } else { + printTrace("\nData processing...\n",0,1) ; + # migrate data for each backend: 5.x -> LDIF files + &manydb2Ldif($ldif_rep); + } + + # migrate LDIF data to the new database: LDIF -> New + &manyLdif2db($ldif_rep); + &migrateChangelog(); + printTrace("\n***** Migrate ReplicaBindDN entries...\n",0,1); + &importReplicaBindDNEntries(); + printTrace("\n***** Migrate MultiplexorBindDN entries...\n",0,1); + &importMultiplexorBindDNEntries(); + &startServer() unless (isDirectoryAlive()); +} +else { + printTrace("\nINFORMATION - There are no non-standard or non-already existing suffixes to migrate\n",0); + &migrateChangelog(); + printTrace("\n***** Migrate ReplicaBindDN entries...\n",0,1); + &importReplicaBindDNEntries(); + printTrace("\n***** Migrate MultiplexorBindDN entries...\n",0,1); + &importMultiplexorBindDNEntries(); +} + +printMsg("\n\n ****** End of migration ******\n\n"); + +close(LOGFILE); + + +########################################################################################### +# get input users +sub getParameters { + my $exit = 0 ; + my $i = 0; + my $pwdfile= ""; + + while ($i <= $#ARGV) { + if ( "$ARGV[$i]" eq "-D" ) { # directory manager + if (! $rootDN) { + $rootDN = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-w") { # password + if (! $rootpwd) { + $rootpwd = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-j") { # password file + if (! $pwdfile) { + $pwdfile = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-o") { # old instance path + if (! $oldHome ) { + $oldHome = $ARGV[++$i] ; + grep { s@\\@/@g } $oldHome if $isNT ; + if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; } + if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) { + $oldDir = $1 ; + $type = $2 ; + $oldname = $3 ; + if ($isNT) { + $oldDir = lc($oldDir) ; + $type = lc($type) ; + $oldname = lc($oldname) ; + $oldHome = lc($oldHome) ; + grep { s@/@\\@g } $oldDir ; + grep { s@/@\\@g } $oldHome ; + } + } + else { + print("\nThe old instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-n") { # new instance path + if (! $serverHome ) { + $serverHome = $ARGV[++$i] ; + grep { s@\\@/@g } $root if $isNT ; + grep { s@\\@/@g } $serverHome if $isNT ; + if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; } + if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) { + $root = $1 if ($1); + $type = $2 ; + $newname = $3 ; + if ($isNT) { + $root = lc($root) ; + $type = lc($type) ; + $newname = lc($newname) ; + $serverHome = lc($serverHome) ; + grep { s@/@\\@g } $root ; + grep { s@/@\\@g } $serverHome ; + } + } + else { + print("\nThe new instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-p") { # new DS port + if (! $newport ) { + $newport = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-d") { # old instance LDIF data dir + if (! $olddatadir ) { + $olddatadir = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-v") { # old version + if (! $oldversionstr ) { + $oldversionstr = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL + my $value = $ARGV[++$i] ; + if ($value =~ /[0-3]/) { + $TRACELEVEL = $value ; + } + else { + print("\nThe tracelevel must belong to 0..3 interval"); + &usage(); + exit(); + } + } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing + $NO_INPUT_USER = 1 ; + } elsif ("$ARGV[$i]" eq "-L") { # migration logfile + $LogFileReport = $ARGV[++$i] ; + } + else { + print("\nThe option $ARGV[$i] is not recognized"); + &usage() ; + exit(1); + } + $i++; + } + if (! $rootDN) { + print("\nThe rootDN is missing"); + $exit = 1; + } + if ($pwdfile ne "") { + # Open file and get the password + unless (open (RPASS, $pwfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $rootpwd = <RPASS>; + chomp($rootpwd); + close(RPASS); + } elsif ($rootpwd eq "-"){ + # Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; + # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $rootpwd = ReadLine(0); +# chomp($rootpwd); +# ReadMode('normal'); + } + if (! $rootpwd) { + print("\nThe rootpwd is missing"); + $exit = 1 ; + } + if (! $newport) { + print("\nThe port is missing"); + $exit = 1; + } + if (! $serverHome) { + print("\nThe new instance path is missing"); + $exit = 1; + } + if (! $oldHome) { + print("\nThe old instance path is missing"); + $exit = 1; + } + if ((! $LogFileReport) && $serverHome) { + ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime(); + $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log"; + } + if ($exit) { + &usage() ; + exit(1); + } + +} + +################################################################################################### + +sub MigrateSchema{ + my $FilesChanged = ""; + my $AllDiffs = ""; + my $NoChanges = "" ; + my $lineToBegin = 0 ; + opendir(SCHEMADIR, $oldSchemaDir) or + die "Error: could not open migrated config dir $oldSchemaDir: $!"; + + foreach $file (readdir(SCHEMADIR)) { + if (! exists($stdIncludes{lc($file)})) { + my $newSchemaFile = $schemaDir . $file; + if (-f $newSchemaFile ) { + # The ldif file already exists. Make a diff and warn the user if different. + if (diff($newSchemaFile, $oldSchemaDir.$file)) { + &stopServer($root,'slapd-'.$newname) if (isDirectoryAlive()); + $AllDiffs .= "\n$file"; + copyBinFile("$oldSchemaDir$file", $newSchemaFile); + } + } + else { + &stopServer($root,'slapd-'.$newname) if (isDirectoryAlive()); + $AllDiffs .= "\n$file"; + copyBinFile("$oldSchemaDir$file", $newSchemaFile); + } + } + } + closedir(SCHEMADIR); + if ($AllDiffs) { + printMsg("\n\n***********************************************************************"); + printMsg("\nThe following LDIF files have been migrated:"); + printMsg("$AllDiffs"); + printMsg("\n*************************************************************************\n\n"); + } + &startServer() if (! isDirectoryAlive()); +} + + +################################################################################################### +# This subroutine is used to parse the dse.ldif file and call specific routines to act with entries +sub MigrateDSEldif { + printTrace("\nMigrate DSE entries...",1); + my $tempoAlreadyDone = 0; + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + $typeOfEntry = getTypeOfEntry($entry); + SWITCH: { + if ($typeOfEntry eq "LDBM_BACKEND_INSTANCE"){ + parseLDBM_backend_instance($entry); + last SWITCH; + } + if ($typeOfEntry eq "MAPPING_TREE"){ + parseMapping_tree($entry); + last SWITCH; + } + if ($typeOfEntry eq "DEFAULT_INDEX"){ + parseDefaultIndex($entry); + last SWITCH; + } + if ($typeOfEntry eq "INDEX"){ + parseIndex($entry); + last SWITCH; + } + if ($typeOfEntry eq "STANDARD_PLUGIN"){ + migrateStdPlugin($entry); + last SWITCH; + } + if ($typeOfEntry eq "CONFIG_NODE"){ + migrateConfig_Node($entry); + last SWITCH; + } + if ($typeOfEntry eq "CONFIG_LDBM_DATABASE"){ + migrateConfig_LDBM_database($entry); + last SWITCH; + } + if ($typeOfEntry eq "CHAINING_BACKEND_CONFIG"){ + migrateChainingBE_config($entry); + last SWITCH; + } + if ($typeOfEntry eq "CHAINING_BACKEND_INSTANCE"){ + migrateChainingBE_instance($entry); + last SWITCH; + } + if ($typeOfEntry eq "NSDS5_REPLICA"){ + parseNSDS5_replica($entry); + last SWITCH; + } + if ($typeOfEntry eq "NSDS_REPLICATION_AGREEMENT"){ + parseNSDS_replication_agreement($entry); + last SWITCH; + } + if ($typeOfEntry eq "CHANGELOG5"){ + migrateChangelog5($entry); + last SWITCH; + } + if ($typeOfEntry eq "REPLICATION"){ + migrateReplication($entry); + last SWITCH; + } + if ($typeOfEntry eq "SECURITY"){ + migrateSecurity($entry); + last SWITCH; + } + if ($typeOfEntry eq "SNMP"){ + migrateSNMP($entry); + last SWITCH; + } + } + + } + close(DSELDIF); +} + +############################################################################# +# returns the "type of an entry". If the entry is not to be migrated its type is "NOT_MIGRATED_TYPE" + +sub getTypeOfEntry{ + my $entry = shift; + my $DN = $entry->getDN(1) ; # 1 is to normalize the returned DN + if (($DN =~ /cn=ldbm database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsBackendInstance"))) { + return "LDBM_BACKEND_INSTANCE"; + } + if (($DN =~ /cn=mapping tree,cn=config$/i) && (isObjectclass($entry,"nsMappingTree"))) { + return "MAPPING_TREE"; + } + if (($DN =~ /cn=default indexes,cn=config,cn=ldbm database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsIndex"))) { + return "DEFAULT_INDEX"; + } + if (isObjectclass($entry,"nsIndex")) { + return "INDEX"; + } + if ((isObjectclass($entry,"nsSlapdPlugin")) && (isStdPlugin($entry))) { + return "STANDARD_PLUGIN"; + } + if ($DN =~ /^cn=config$/i) { + return "CONFIG_NODE"; + } + if ($DN =~ /^cn=config,cn=ldbm database,cn=plugins,cn=config$/i) { + return "CONFIG_LDBM_DATABASE"; + } + if (($DN =~ /^cn=config,cn=chaining database,cn=plugins,cn=config$/i) || ($DN =~ /^cn=default instance config,cn=chaining database,cn=plugins,cn=config$/i)){ + return "CHAINING_BACKEND_CONFIG"; + } + if (($DN =~ /cn=chaining database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsBackendInstance"))) { + return "CHAINING_BACKEND_INSTANCE"; + } + if (isObjectclass($entry,"nsDS5Replica")) { + return "NSDS5_REPLICA"; + } + if (isObjectclass($entry,"nsDS5ReplicationAgreement")) { + return "NSDS_REPLICATION_AGREEMENT"; + } + if ($DN =~ /^cn=changelog5,cn=config$/i) { + return "CHANGELOG5"; + } + if (($DN =~ /cn=replication,cn=config$/i) && ($DN !~ /^cn=replication,cn=config$/i)) { + return "REPLICATION"; + } + if ($DN =~ /cn=encryption,cn=config$/i) { + return "SECURITY"; + } + if ($DN =~ /^cn=SNMP,cn=config$/i) { + return "SNMP"; + } + return "NOT_MIGRATED_TYPE"; +} + +############################################################################# + + + +############################################################################# +# returns 1 if the objectclass given in parameter is present in the objectclasses values of the entry +# given in parameter, 0 else + +sub isObjectclass { + my $entry = shift; + my $objectclass = shift; + return ($entry->hasValue("objectclass",$objectclass,1)); +} + +############################################################################# + +sub isStdPlugin { + my $entry = shift; + my $CN = $entry->{cn}[0]; + if (isObjectclass($entry,"nsSlapdPlugin")) { + return 1 if ($stdPlugins{lc($CN)}); + } + return 0; +} + + +############################################################################# + +sub alreadyExistsInNew{ + my $entry = shift; + my $mustExist = shift; + my $DN = $entry->getDN(1); # 1 to normalize the DN + # We have a name change of "uid uniqueness" plugin in DS6.x + # to "attribute uniqueness" + $DN =~ s/uid\ uniqueness/attribute\ uniqueness/ if ($DN =~ /uid\ uniqueness/); + return searchEntry($DN, $mustExist); +} + +############################################################################# +sub searchEntry { + my $DN = shift; + my $mustExist = shift; + my $res = $conn->search($DN, "base", "objectclass=*"); + my $cpt = 5; + if ($res) { + return $res; + } + else { + my $errorCode = $conn->getErrorCode(); + while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) { + printMsg("\ntry to reconnect to search $DN"); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + $res = $conn->search($DN, "base", "objectclass=*"); + $errorCode = $conn->getErrorCode(); + $cpt--; + } + if ($res){ + return $res ; + } + elsif (($errorCode eq $LDAP_SERVER_UNREACHABLE) || ($mustExist)) { + my $msg = $conn->getErrorString(); + printMsg("\n\n*** Failed to search: $DN"); + printMsg("\n*** Error Msg: $msg, Error code: $errorCode"); + } + return 0; + } +} + + +############################################################################# + +sub addEntryToNew{ + my $entry = shift; + my $typeOfEntry = shift; + my $trace = shift; + my $res = $conn->add($entry); + my $DN = $entry->getDN(1); + my $cpt = 5; + if ($res) { + printTrace("\n$typeOfEntry - Add successfull: $DN",$trace); + return 1; + } + else { + my $errorCode = $conn->getErrorCode(); + while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) { + printMsg("\ntry to reconnect to add $DN"); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + $res = $conn->add($entry); + $errorCode = $conn->getErrorCode(); + $cpt--; + } + if ($res){ + printTrace("\n$typeOfEntry - Add successfull: $DN",$trace); + return 1; + } + else { + my $msg = $conn->getErrorString(); + printMsg("\n\n*** $typeOfEntry: Add Failed: $DN"); + printMsg("\n*** Error Msg: $msg, Error code: $errorCode"); + return 0; + } + } +} + +############################################################################# + +sub updateEntry{ + my $entry = shift; + my $typeOfEntry = shift; + my $CHECK = shift; + my $trace = shift; + my $cpt = 5; + if ($CHECK) { + if (! hasChanged($entry, $typeOfEntry)) { + return 1; + } + } + my $res = $conn->update($entry); + my $DN = $entry->getDN(1); + if ($res) { + printTrace("\n$typeOfEntry - Update successfull: $DN",$trace); + return 1 ; + } + else { + my $errorCode = $conn->getErrorCode(); + while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) { + printMsg("\ntry to reconnect to update $DN"); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + $res = $conn->update($entry); + $errorCode = $conn->getErrorCode(); + $cpt--; + } + if ($res){ + printTrace("\n$typeOfEntry - Update successfull: $DN",$trace); + return 1; + } + else { + my $msg = $conn->getErrorString(); + printMsg("\n\n*** $typeOfEntry - Update Failed: $DN"); + printMsg("\n*** Error Msg: $msg, Error code: $errorCode"); + return 0; + } + } +} + + +############################################################################# +# returns 1 if the entry to migrate and the current entry are different one another + +sub hasChanged { + my $entry = shift; + my $typeOfEntry = shift; + my $DN = $entry->getDN(1); + my $newEntry = searchEntry($DN,1); + return 1 if (! $newEntry); # we shoudn't be in that case ... + # do the stuff to check wether the entry has changed or not given its type + if (($typeOfEntry eq "DEFAULT_INDEX") || ($typeOfEntry eq "INDEX")){ + my @indexTypes = $entry->getValues("nsIndexType"); + my @newIndexTypes = $newEntry->getValues("nsIndexType"); + my @nsmatchingrules = $entry->getValues("nsmatchingrule"); + my @newMatchingRules = $newEntry->getValues("nsmatchingrule"); + return 1 if (Diffs(\@indexTypes, \@newIndexTypes)); + return 1 if (Diffs(\@nsmatchingrules,\@newMatchingRules)); + return 0; + } + if ($typeOfEntry eq "CHANGELOG5"){ + printTrace("\nCheck wether changelog has changed or not",3); + my @params = keys(%changelog5params); + foreach $param (@params){ + my @values = $entry->getValues($param); + my @newValues = $newEntry->getValues($param); + return 1 if (Diffs(\@values,\@newValues)); + } + return 0; + } + if ($typeOfEntry eq "SNMP"){ + foreach $param (@SNMPparams){ + my @values = $entry->getValues($param); + my @newValues = $newEntry->getValues($param); + return 1 if (Diffs(\@values,\@newValues)); + } + return 0; + } + # we don't know how to compare such type of entry => just return 1 + return 1 ; +} + +sub isAsystemIndex { + my $index = shift; + return ($index->hasValue("nsSystemIndex","true",1)); +} + + +sub updatePathInPluginArgs { + my $plugin = shift; + my $argNum = 0; + my $argPrefix = "nsslapd-pluginarg"; + my $cont = 1; + my $Unix_oldDir = ${oldDir} ; + my $Unix_root = ${root} ; + grep { s@\\@/@g } $Unix_oldDir if $isNT; + grep { s@\\@/@g } $Unix_root if $isNT; + while ($cont) { + my $arg = $argPrefix . $argNum ; + if ($plugin->exists($arg)) { + $_ = $plugin->{$arg}[0] ; + s@$Unix_oldDir@$Unix_root@ig ; + s/$type-$oldname/$type-$newname/ig ; + $plugin->setValues($arg, $_) ; + } + else { + $cont = 0 ; + } + $argNum++; + } + return $plugin; +} + + +sub Diffs { + my $valuesToMigrate = shift; + my $currentValues = shift; + return 1 if (getDiff(\@{$valuesToMigrate},\@{$currentValues})); + return 1 if (getDiff(\@{$currentValues},\@{$valuesToMigrate})); + return 0 ; +} + +sub getDiff { + # we get references to arrays + my $elements = shift ; + my $existing_elements = shift ; + my %count = () ; + my %countEE = () ; + @diff = () ; + foreach $e (@{$elements}, @{$existing_elements}) { $count{$e}++ ;} + foreach $e (@{existing_elements}) { $countEE{$e}++ ;} + foreach $e (@{$elements}) { + # if $e is only present in @$elements, we push it to the diff array + if (($count{$e} == 1) && ($countEE{$e} == 0)) { + push @diff, $e ; + } + } + return @diff ; +} + +sub registerSuffix_Backend { + my $ldbmDatabase = shift; + my $CN = $ldbmDatabase->{cn}[0]; + my $suffixArg = "nsslapd-suffix"; + my $suffix = $ldbmDatabase->{$suffixArg}[0]; + $oldBackends{$suffix} = $CN; +} + + +############################################################################# +# # +# # +# # +############################################################################# +sub migrateLDBM_backend_instances { + foreach $entry (@LDBM_backend_instances) { + my $DN = $entry->getDN(1); # 1 is to normalize the DN + my $CN = $entry->{cn}[0]; + my $expLdif; + my $confirm = "No"; + my $dest = "$serverHome${PATHSEP}db_backup" ; + my $newSlapdExecDir = "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server"; + + if ($DN =~/cn=netscaperoot,cn=ldbm database/i){ + printTrace("\n\n*** INFORMATION - NetscapeRoot is NOT migrated",0); + } + else { + if(alreadyExistsInNew($entry)){ + printMsg("\n\n*** LDBM_BACKEND_INSTANCE - $DN already exists"); + printMsg("\n*** Migration will overwrite existing database"); + printMsg("\nDo you want to continue Yes/No [No] ?") ; + my $answer = <STDIN> ; + if ($answer =~ /y|yes/i) { + printMsg("Do you want to export the existing data Yes/No [Yes] ?"); + my $answer = <STDIN> ; + if (!($answer =~ /n|no/i)) { + mkdir $dest, 0700 unless (-d $dest); + $expLdif = "$dest${PATHSEP}$CN.ldif"; + while (!($confirm =~ /y|yes/i)) { + printMsg("\nEnter the full pathname of the file [$expLdif]:") ; + $answer = <STDIN> ; + chomp($expLdif = $answer) unless ($answer eq "\n"); + printMsg("\nExisting data will be exported under $expLdif"); + printMsg("\nContinue Yes/No [No] ?"); + $confirm = <STDIN>; + } + $ENV{"$LIB_PATH"}=$new_libpath; + chdir($newSlapdExecDir) or die "\nCould not change directory to $newSlapdExecDir: $!\n"; + printTrace("\nNow backing up database $CN in $expLdif\n",0); + &stopServer($root,'slapd-'.$newname); + &db2Ldif($expLdif, $CN, $serverHome); + &startServer() unless (isDirectoryAlive()); + } + push @BACKENDS, $CN; + } else { + printMsg("\n*** Migration will not update it"); + break; + } + } else { + printTrace("\nWe should add the backend instance $DN",3); + my $suffixarg = "nsslapd-suffix" ; + my $suffixname= $entry->{$suffixarg}[0] ; + my $newEntry = $conn->newEntry() ; + $newEntry->setDN($DN); + $newEntry->setValues("objectclass", "top", "extensibleObject", "nsBackendInstance" ); + $newEntry->setValues("cn", $CN ); + $newEntry->setValues($suffixarg, $suffixname); + my @params = keys(%LDBMparamToMigrate); + foreach $param (@params) { + my @values = $entry->getValues($param); + $newEntry->setValues($param, @values) if (@values); + } + if (addEntryToNew($newEntry, "LDBM_BACKEND_INSTANCE",1)) { + push @BACKENDS, $CN; + } + } + } + } +} + +sub parseLDBM_backend_instance { + my $entry = shift; + ®isterSuffix_Backend($entry); + push @LDBM_backend_instances, $entry; +} + +############################################################################# +sub migrateMappingTree { + foreach $entry (@Mapping_tree_entries) { + my $DN = $entry->getDN(1); # 1 si to normalize the DN + if ($DN =~/cn=\"o=netscaperoot\",cn=mapping tree,cn=config/i){ + # DO NOTHING + } + else { + if(alreadyExistsInNew($entry)){ + printMsg("\n\n*** MAPPING_TREE - $DN already exists"); + printMsg("\n*** Migration will not add the suffix"); + } + else { + addEntryToNew($entry, "MAPPING_TREE",1); + } + } + } +} + + +sub parseMapping_tree{ + my $entry = shift; + push @Mapping_tree_entries, $entry; +} + +############################################################################# +sub migrateDefaultIndexes { + foreach $index (@default_indexes) { + my $CN = $index->{cn}[0]; + my $newIndex ; + if ((! isAsystemIndex($index)) && (! $deniedIndexes{lc($CN)})) { + if ($newIndex = alreadyExistsInNew($index)) { + if (! isAsystemIndex($newIndex)) { + updateEntry($index, "DEFAULT_INDEX", 1, 2); + } + } + else { + addEntryToNew($index, "DEFAULT_INDEX", 2); + } + } + } +} + + +sub parseDefaultIndex{ + my $index = shift; + push @default_indexes, $index; +} + +############################################################################# + +sub migrateIndexes { + foreach $index (@indexes) { + my $CN = $index->{cn}[0]; + my $newIndex; + if ((! isAsystemIndex($index)) && (! $deniedIndexes{lc($CN)}) && (DN !~ /cn=netscaperoot,cn=index/i)){ + if ($newIndex = alreadyExistsInNew($index)) { + if (! isAsystemIndex($newIndex)) { + updateEntry($index, "INDEX", 1, 2); + } + } + else { + addEntryToNew($index, "INDEX", 2); + } + } + } +} + +sub parseIndex{ + my $index = shift; + push @indexes, $index; +} + +############################################################################# + +sub newLDIFplugin { + my $currentPlugin = shift; + my $DN = $currentPlugin->getDN(1); + my $newPlugin = $conn->newEntry() ; + $newPlugin->setDN($DN); + foreach $Attr (@pluginAttrs) { + my @values = $currentPlugin->getValues($Attr); + $newPlugin->setValues($Attr, @values) if (@values); + } + return $newPlugin; +} + +sub migrateStdPlugin{ + my $plugin = shift; + my $DN = $plugin->getDN(1); + my $pluginEnable = "nsslapd-pluginEnabled"; + my $argNum = 0; + my $argPrefix = "nsslapd-pluginarg"; + my $currentPlugin ; + if ($currentPlugin = alreadyExistsInNew($plugin, 1)) { + $plugin = updatePathInPluginArgs($plugin); + my $pluginEnableValue = $plugin->{$pluginEnable}[0]; + my $cont = 1; + my $pluginHasChanged = 0; + my $newPlugin = &newLDIFplugin($currentPlugin); + if (! $currentPlugin->hasValue($pluginEnable,$pluginEnableValue,1)){ + $newPlugin->setValues($pluginEnable, $pluginEnableValue); + $pluginHasChanged = 1 unless ($pluginHasChanged); + } + while($cont){ + my $arg = $argPrefix . $argNum ; + if ($plugin->exists($arg)) { + my @values = $plugin->getValues($arg); + my $value = $values[0] ; + $newPlugin->setValues($arg, $value) if (@values); + if ($currentPlugin->exists($arg)) { + if (! $currentPlugin->hasValue($arg,$value,1)) { + $pluginHasChanged = 1 unless ($pluginHasChanged); + } + } + else { + $pluginHasChanged = 1 unless ($pluginHasChanged); + } + } + else { + if ($currentPlugin->exists($arg)) { + # Just Warn the user. Do nothing. + printTrace("\nCompared to the old instance, the current new plugin $DN belongs this attribute: $arg",2); + } + else { + $cont = 0 ; + } + } + $argNum++; + } + updateEntry($newPlugin, "STANDARD_PLUGIN", 0, 1) if ($pluginHasChanged); + } +} + +############################################################################# + +sub migrateConfig_Node{ + my $config_node = shift; + my @params = keys(%GeneralSrvParamToMigrate); + my $hasChanged = 0; + my $newConfigNode; + if ($newConfigNode = alreadyExistsInNew($config_node, 1)){ + foreach $param (@params) { + if ($config_node->exists($param)){ + my @valuesToMigrate = $config_node->getValues($param); + if (@valuesToMigrate){ + if ($newConfigNode->exists($param)){ + my @currentValues = $newConfigNode->getValues($param); + if (Diffs(\@valuesToMigrate, \@currentValues)) { + $newConfigNode->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + printTrace("\nParam to update: $param with value @valuesToMigrate",3); + } + } + else { + $newConfigNode->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + printTrace("\nParam to update: $param with value @valuesToMigrate",3); + } + } + } + } + updateEntry($newConfigNode, "CONFIG_NODE", 0, 1) if ($hasChanged); + } +} + +############################################################################# + +sub migrateConfig_LDBM_database{ + my $config_ldbm = shift; + my @params = keys(%GlobalConfigLDBMparamToMigrate); + my $hasChanged = 0; + my $newConfigLdbm ; + if ($newConfigLdbm = alreadyExistsInNew($config_ldbm, 1)) { + foreach $param (@params) { + if ($config_ldbm->exists($param)){ + my @valuesToMigrate = $config_ldbm->getValues($param); + if (@valuesToMigrate){ + if ($newConfigLdbm->exists($param)){ + my @currentValues = $newConfigLdbm->getValues($param); + if (Diffs(\@valuesToMigrate, \@currentValues)) { + $newConfigLdbm->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + } + } + else { + $newConfigLdbm->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + } + } + } + } + updateEntry($newConfigLdbm, "CONFIG_LDBM_DATABASE", 0, 1) if ($hasChanged); + } +} + +############################################################################# + +sub migrateChainingBE_config{ + my $chaining_config = shift; + my $DN = $chaining_config->getDN(1); + my @params = (); + my $hasChanged = 0; + my $newChainingConfig; + if ($DN =~ /^cn=config,cn=chaining database,cn=plugins,cn=config$/i){ + $newChainingConfig = searchEntry("cn=config,cn=chaining database,cn=plugins,cn=config"); + @params = keys(%ChainingConfigParams); + } + if ($DN =~ /^cn=default instance config,cn=chaining database,cn=plugins,cn=config$/i){ + $newChainingConfig = searchEntry("cn=default instance config,cn=chaining database,cn=plugins,cn=config"); + @params = keys(%ChainingDefaultInstanceConfigParams); + } + foreach $param (@params) { + if ($chaining_config->exists($param)){ + my @valuesToMigrate = $chaining_config->getValues($param); + if (@valuesToMigrate){ + printTrace("\nParam: $param values To migrate: @valuesToMigrate",3); + if ($newChainingConfig->exists($param)){ + my @currentValues = $newChainingConfig->getValues($param); + printTrace("\nParam: $param new current values: @currentValues",3); + if (Diffs(\@valuesToMigrate, \@currentValues)) { + $newChainingConfig->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + } + } + else { + $newChainingConfig->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + } + } + } + } + updateEntry($newChainingConfig, "CHAINING_BACKEND_CONFIG", 0, 1) if ($hasChanged); +} + +############################################################################# + +sub registerSuffix_ChainingBE { + my $ldbmDatabase = shift; + my $CN = $ldbmDatabase->{cn}[0]; + my $suffixArg = "nsslapd-suffix"; + my $suffix = $ldbmDatabase->{$suffixArg}[0]; + $oldChainingBackends{$suffix} = $CN; +} + +sub storeMultiplexorBindDN { + my $chaining_instance = shift; + my $DN = $chaining_instance->getDN(1); + if ($chaining_instance->exists("nsMultiplexorBindDN")){ + my $bindDN = $chaining_instance->{nsMultiplexorBindDN}[0]; + my $newBindDN = searchEntry($bindDN); + if (! $newBindDN){ + # the bindDN entry doesn't yet exist in new => it will have to be migrated + $MultiplexorBindDNEntriesToMigrate{$bindDN}="\n" ; + printTrace("\nThe bindDN: $bindDN need to be migrated",3); + } + else { + # do nothing as the entry already exists in new + } + } + +} + +sub importMultiplexorBindDNEntries { + # import all entries present in @MultiplexorBindDNEntriesToMigrate in new + my @MultiplexorBindDNs = keys (%MultiplexorBindDNEntriesToMigrate); + my $ldif_dir = $ldif_rep; + foreach $bindDN (@MultiplexorBindDNs) { + printTrace("\nimportMultiplexorBindDNEntries: bindDN to migrate: $bindDN",3); + # get the backend in which is stored the bind DN entry + my $backendtoExportFrom = getBackendtoExportFrom($bindDN); + printTrace("\nbackendtoExportFrom is: $backendtoExportFrom",3); + # check wether the backend has been imported in new or not + if (! alreadyMigrated($backendtoExportFrom)) { + if ($backendtoExportFrom ne $NULL) { + # if not imported => we need to import the binf DN entry + &startServer() unless (isDirectoryAlive()); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + &ExportAndAddEntry($bindDN, $backendtoExportFrom, $ldif_dir); + } + else { + # do nothing + } + } + } + # remove the empty ldif directory + rmdir($ldif_dir) if (-d $ldif_dir); + # close the LDAP connection to new + $conn->close if ($conn); +} + +sub migrateChainingBE_instance{ + my $chaining_instance = shift; + my $DN = $chaining_instance->getDN(1); + ®isterSuffix_ChainingBE($chaining_instance); + if (alreadyExistsInNew($chaining_instance)) { + # already exists + printMsg("\n\n*** CHAINING_BACKEND_INSTANCE - $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + &migrate_credential($chaining_instance, "nsmultiplexorcredentials"); + addEntryToNew($chaining_instance, "CHAINING_BACKEND_INSTANCE", 1); + storeMultiplexorBindDN($chaining_instance); + } +} + +############################################################################# + +# create a new LDIF representation of a new replica consumer +sub newLDIFreplica { + my $replica = shift; + my $DN = $replica->getDN(1); + my $newReplica = $conn->newEntry() ; + my $MASTER_OR_MULTIMASTER = "3" ; + $newReplica->setDN($DN); + foreach $Attr (@nsds5replicaAttrs) { + my @values = $replica->getValues($Attr); + $newReplica->setValues($Attr, @values) if (@values); + } + my $replicaType = $replica->{nsDS5ReplicaType}[0]; + if ($replicaType eq $MASTER_OR_MULTIMASTER) { + my @nsState = $replica->getValues("nsState"); + $newReplica->setValues("nsState", @nsState); + } + else { + $newReplica->setValues("nsDS5ReplicaId", $replicaIdvalue); + } + return $newReplica; +} + +sub MigrateNSDS5_replica{ + foreach $replica (@new6replicas) { + my $DN = $replica->getDN(1); + my $newReplica; + my @removeAttrs = qw(nsstate nsds5replicaname nsds5replicachangecount); + for (@removeAttrs) { + $replica->remove($_); + } + if (alreadyExistsInNew($replica)) { + # replica already exists + printMsg("\n\n*** NSDS5_REPLICA - $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + $newReplica = &newLDIFreplica($replica); + addEntryToNew($newReplica, "NSDS5_REPLICA", 1); + } + storeReplicaBindDN($replica); + } +} + +sub parseNSDS5_replica{ + my $replica = shift; + push @new6replicas, $replica; +} + +sub storeReplicaBindDN { + my $replica = shift; + my $DN = $replica->getDN(1); + if ($replica->exists("nsDS5ReplicaBindDN")){ + my $bindDN = $replica->{nsDS5ReplicaBindDN}[0]; + my $newBindDN = searchEntry($bindDN); + if (! $newBindDN){ + # the bindDN entry doesn't yet exist in new => it will have to be migrated + $ReplicaBindDNEntriesToMigrate{$bindDN}="\n" ; + printTrace("\nThe bindDN: $bindDN need to be migrated",3); + } + else { + # do nothing as the entry already exists in new + } + } +} + + +sub importReplicaBindDNEntries { + # import all entries present in @ReplicaBindDNEntriesToMigrate in new + my @ReplicaBindDNs = keys (%ReplicaBindDNEntriesToMigrate); + my $ldif_dir = $ldif_rep; + my $replBind_entry = ""; + my @bindDN_elements = ""; + my $bindDN_parent = ""; + my $parentBind_entry = ""; + foreach $bindDN (@ReplicaBindDNs) { + printTrace("\nimportReplicaBindDNEntries: bindDN to migrate: $bindDN",3); + # get the backend in which is stored the bind DN entry + my $backendtoExportFrom = getBackendtoExportFrom($bindDN); + printTrace("\nbackendtoExportFrom is: $backendtoExportFrom",3); + # If backend is from config, read the entry from dse.ldif and add to new - NGK + if ($backendtoExportFrom eq "cn=config") { + my $norm_bindDN = normalizeDN($bindDN); + @bindDN_elements = ldap_explode_dn($norm_bindDN, 0); +# @bindDN_elements = split(/,/,$norm_bindDN); + my $junk = shift(@bindDN_elements); + if ($#bindDN_elements >= 1) { + $bindDN_parent = normalizeDN(join(",", @bindDN_elements)); + } + printTrace("\nOpening DSE.ldif",3); + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF); + while ($entry = readOneEntry $in) { + my $DN = $entry->getDN(1); + if ($DN eq $norm_bindDN) { + $replBind_entry = $entry; + } + if ($bindDN_parent ne "") { + if ($DN eq $bindDN_parent) { + $parentBind_entry = $entry; + } + } + } + close(DSELDIF); + &startServer() unless (isDirectoryAlive()); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + if ($bindDN_parent ne "") { + addEntryToNew($parentBind_entry, BINDDN_PARENT, 0); + } + printTrace("\nAdding BindDN with addEntryToNew",3); + addEntryToNew($replBind_entry, BINDDN, 0); + } else { + # check wether the backend has been imported in new or not + if (! alreadyMigrated($backendtoExportFrom)) { + if ($backendtoExportFrom ne $NULL) { + # if not imported => we need to import the bind DN entry + &startServer() unless (isDirectoryAlive()); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + &ExportAndAddEntry($bindDN, $backendtoExportFrom, $ldif_dir); + } + else { + # do nothing + } + } + } + } + # remove the empty ldif directory + rmdir($ldif_dir) if (-d $ldif_dir); + # close the LDAP connection to new + $conn->close if ($conn); +} + +sub alreadyMigrated { + my $backendToCheck = shift; + foreach $backend (@BACKENDS) { + return 1 if ($backend eq $backendToCheck); + } + return 0 ; +} + +sub belongsSuffix { + my $suffix = shift; + my $bindDN = shift; + return ($bindDN =~ /$suffix\s*$/i); +} + +sub length { + my $suffix = shift; + my $count = 0; + while ($suffix =~ /./g) { + $count++; + } + return $count ; +} + +sub getBackendtoExportFrom { + my $bindDN = shift ; + my $sizeOfSuffix = 0 ; + my $NULL = ""; + my @oldSuffixes = keys(%oldBackends); + my @oldChainingSuffixes = keys(%oldChainingBackends); + my $bindDN_backend = $NULL; + my $config = "cn=config"; + + my $norm_bindDN = normalizeDN($bindDN); + # Check if bindDN exists in cn=config - NGK + if (belongsSuffix($config,$norm_bindDN)) { + $bindDN_backend = $config; + printTrace("\ngetBackendtoExportFrom: bindDN_backend: $bindDN_backend",3); + } else { + foreach $suffix (@oldSuffixes){ + printTrace("\ngetBackendtoExportFrom: suffix to compare with is: $suffix",3); + if ((belongsSuffix($suffix,$norm_bindDN)) && (length($suffix) > $sizeOfSuffix)) { + $sizeOfSuffix = length($suffix); + $bindDN_backend = $oldBackends{$suffix}; + printTrace("\ngetBackendtoExportFrom: bindDN_backend: $bindDN_backend, sizeOfSuffix: $sizeOfSuffix",3); + } + } + foreach $suffix (@oldChainingSuffixes){ + printTrace("\ngetBackendtoExportFrom: suffix to compare with is a chained suffix: $suffix",3); + if ((belongsSuffix($suffix,$norm_bindDN)) && (length($suffix) > $sizeOfSuffix)) { + printMsg("\n\n*** Entry stored on a remote backend - $norm_bindDN"); + printMsg("\n*** We don't migrate it"); + return $NULL; + } + } + } + return $bindDN_backend; +} + + +sub getBackendtoImportTo { + my $bindDN = shift; + my $sizeOfSuffix = 0; + my $NULL = ""; + my $suffixArg = "nsslapd-suffix"; + my $bindDN_backend = $NULL; + open( DSELDIF, "< $DSEldif" ) || die "Can't open $DSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + $typeOfEntry = getTypeOfEntry($entry); + if ($typeOfEntry eq "LDBM_BACKEND_INSTANCE"){ + my $suffix = $entry->{$suffixArg}[0]; + if ((belongsSuffix($suffix,$bindDN)) && (length($suffix) > $sizeOfSuffix)) { + $sizeOfSuffix = length($suffix); + $bindDN_backend = $entry->{cn}[0]; + } + } + } + close(DSELDIF); + return $bindDN_backend ; +} + + +sub ExportAndAddEntry { + my $DN = shift; + my $backendtoExportFrom = shift; + my $ldif_dir = shift; + my $ldif = "$ldif_dir${PATHSEP}$backendtoExportFrom.ldif" ; + # first: export entry pointed out by the $DN to $ldif file + $ENV{"$LIB_PATH"}=$old_libpath; + if (! $ldif_dir) { $ldif_dir = $ldif_rep ;} + if (!(-d $ldif_dir)) { + mkdir($ldif_dir,0777) or die "\ncan't create $ldif_dir to store temporary ldif files\n"; + } + chdir($oldSlapdExecDir) or die "\nCould not change directory to $oldSlapdExecDir: $!\n"; + &db2Ldif($ldif, $backendtoExportFrom, $oldHome, $DN); + chdir($curdir) or die "\nCould not change directory to $curdir: $!\n"; + + # then: Add it to new + if (! $conn) { + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + } + open( BINDDNLDIF, "< $ldif" ) || die "\nCan't open $ldif: $!: \n"; + my $in = new Mozilla::LDAP::LDIF(*BINDDNLDIF) ; + while ($entry = readOneEntry $in) { + my $entryDN = $entry->getDN(1); + if ($DN eq $entryDN) { + addEntryToNew($entry, "nsds5ReplicaBindDN", 0); + } + } + close(BINDDNLDIF); + # remove the ldif file after the import + unlink($ldif) ; +} + +############################################################################# +sub MigrateNSDS_replication_agreement { + foreach $replicationAgreement (@replicationAgreements) { + my $DN = $replicationAgreement->getDN(1); + if (alreadyExistsInNew($replicationAgreement)){ + # replication agreement already exists + printMsg("\n\n*** NSDS_REPLICATION_AGREEMENT - $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + &migrate_credential($replicationAgreement, "nsDS5ReplicaCredentials"); + addEntryToNew($replicationAgreement, "NSDS_REPLICATION_AGREEMENT", 1); + } + } +} + + +sub parseNSDS_replication_agreement{ + my $replicationAgreement = shift; + push @replicationAgreements, $replicationAgreement ; +} + +############################################################################# + +sub migrateChangelog5{ + my $changelog = shift; + my $DN = $changelog->getDN(1); + my $changelogdir = "nsslapd-changelogdir"; + if (alreadyExistsInNew($changelog)){ + # cn=changelog5,cn=config already exists in new + my $newChangelog = searchEntry($DN); + my @newChangelogdir = $newChangelog->getValues($changelogdir); + $changelog->setValues($changelogdir, @newChangelogdir); + updateEntry($changelog, "CHANGELOG5", 0, 1); + } + else { + # cn=changelog5,cn=config need to be created in new. + # the changelogdir value must be setup to <new_root_server>/slapd-instance/changelogdb + $changelog->setValues($changelogdir,"${serverHome}${PATHSEP}changelogdb"); + addEntryToNew($changelog, "CHANGELOG5", 1); + } +} + + +sub migrateChangelog { + my $oldchangelogdir = ""; + my $newchangelogdir = ""; + my $changelogdir = "nsslapd-changelogdir"; + my $CL5DN = "cn=changelog5,cn=config"; + printTrace("\n\n***** Migrate Changelog...",0,1); + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF); + while ($entry = readOneEntry $in) { + $typeOfEntry = getTypeOfEntry($entry); + if ($typeOfEntry eq "CHANGELOG5"){ + $oldchangelogdir = ($entry->getValues($changelogdir))[0]; + } + } + close(DSELDIF); + if ($oldchangelogdir) { + # If using olddatadir to migrate from, the path of the changelogdb + # from the dse.ldif may not match the path where the old server + # root was archived. We may need to modify oldchangelogdir so the + # copy of the changelog files succeeds. + unless(-e $oldchangelogdir) { + if($olddatadir) { + my @cldbpath = split(/\//,$oldchangelogdir); + until($cldbpath[0] =~/^slapd-/) { + shift(@cldbpath); + } + my $tmpcldbpath = join(${PATHSEP}, @cldbpath); + $oldchangelogdir = "$oldDir${PATHSEP}$tmpcldbpath"; + } + # If oldchangelogdir still looks to be wrong, prompt for the + # location instead of just failing on the copydir operation + # and bombing out of the migration. + unless(-e $oldchangelogdir) { + print("\n\nThe old changelog directory \"$oldchangelogdir\" doesn't exist. Please enter the correct path: "); + $oldchangelogdir = <STDIN>; + } + } + &startServer() unless (isDirectoryAlive()); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + my $newChangelog = searchEntry($CL5DN); + $newchangelogdir = ($newChangelog->getValues($changelogdir))[0]; + stopServer($root,'slapd-'.$newname); + printTrace("\ncopying $oldchangelogdir${PATHSEP}* to $newchangelogdir",3); + copyDir("$oldchangelogdir","$newchangelogdir"); + + # We need to modify the DBVERSION file for a new verision of the db + open(DBVERSION,">$newchangelogdir${PATHSEP}DBVERSION") || die "Can't overwrite $newchangelogdir${PATHSEP}DBVERSION: $! "; + print DBVERSION "Changelog5/NSMMReplicationPlugin/3.0"; + close(DBVERSION); + + &startServer() unless (isDirectoryAlive()); + } +} + +############################################################################# + +sub migrateReplication{ + my $replication = shift; + my $DN = $replication->getDN(1); + if (alreadyExistsInNew($replication)){ + # replication agreement already exists + printMsg("\n\n*** $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + addEntryToNew($replication, "REPLICATION", 1); + } +} + +############################################################################# + +sub migrateSecurity{ + my $security = shift; + if ($entry->hasValue("objectClass", "nsEncryptionConfig")) { + my $certfile = "alias/slapd-" . $newname . "-cert8.db"; + my $keyfile = "alias/slapd-" . $newname. "-key3.db"; + $entry->setValues("nsCertfile",$certfile) if ! $entry->hasValue("nsCertfile",$certfile); + $entry->setValues("nsKeyfile",$keyfile) if ! $entry->hasValue("nsKeyfile",$keyfile); + } + if (alreadyExistsInNew($security)){ + # already exists in new + updateEntry($security, "SECURITY", 0, 1); + } + else { + addEntryToNew($security, "SECURITY", 1); + } +} + +############################################################################# + +sub migrateSNMP{ + my $snmp = shift; + if (alreadyExistsInNew($snmp)){ + # already exists in new + updateEntry($snmp, "SNMP", 0, 1); + } + else { + addEntryToNew($snmp, "SNMP", 1); + } +} + +############################################################################# +# printMsg print message to the user standard output. + +sub printMsg { + + my $TypeMsg = shift ; + my $Msg = shift ; + my $LineNb = shift ; + if ($LineNb) { + printTrace("Line: $LineNb, $TypeMsg, $Msg"); + } + else { + printTrace("$TypeMsg $Msg"); + } +} + +############################################################################# +# print message error to the user standard output. + +sub printTrace { + + my $Msg = shift ; + my $level = shift ; + my $sep = shift ; + + if ($sep) { + print "\n-------------------------------------------------------------------------"; + print LOGFILE "\n-------------------------------------------------------------------------"; + } + + if ($level <= $TRACELEVEL) { + print($Msg); + print LOGFILE $Msg ; + } +} + +############################################################################# +# this subroutine implements a very stupid version of diff + +sub diff { + my $f1 = shift; + my $f2 = shift; + my $lineToBeginWith = shift; + my $NULL = "" ; + my $diff_f1 = $NULL ; + my $diff_f2 = $NULL ; + my $retval = $NULL ; + my $ret; + open(F1, "$f1") or die "Could not open file $f1"; + open(F2, "$f2") or close(F1), die "Could not open file $f2"; + + while (defined($l1 = <F1>)) { + if ($lineToBeginWith){ + $lineToBeginWith -- ; + next ; + } + next if ($l1 =~ /^\#/); + $ret = defined($l2 = <F2>); + if ($ret) { + $ret = defined($l2 = <F2>) while ($ret && ($l2 =~ /^\#/)) ; + if ($ret) { + if (!($l1 eq $l2)) { + + # ignore whitespace + $l1_clean = $l1 ; + $l2_clean = $l2 ; + $l1_clean =~ s/\s//g; + $l2_clean =~ s/\s//g; + + if (!($l1_clean eq $l2_clean)) { + $diff_f1 .= "${l1}" unless ($l1_clean eq $NULL); + $diff_f2 .= "${l2}" unless ($l2_clean eq $NULL); + } + } + } + else { + next if ($l1 =~ /^\s*$/) ; + $diff_f1 .= "${l1}"; + } + } + else { + next if ($l1 =~ /^\s*$/) ; + $diff_f1 .= "${l1}"; + } + } + + while (defined($l2 = <F2>)) { + if (($l2 =~ /^\#/) || ($l2 =~ /^\s*$/)) { + next ; + } + else { + $diff_f2 .= "${l2}" ; + } + } + + close(F1); + close(F2); + + $retval .= "- differences present in your config file but not in standard file:\n\n". "$diff_f1\n" if ($diff_f1) ; + $retval .= "- differences present in standard file but not in your config file:\n\n" . "$diff_f2" if ($diff_f2) ; + return $retval ; +} + +sub CompareStdConfigFiles { + # Compare each configuration file against its default version. If it has changed, + # notify the user that the file has changed and will need to be checked by the + # user. This should be safe to do because there should be no path information + # stored in these conf files, which are just schema stuff. + # printTrace("\nCheck if standard configuration files have changed",3); + + # get the version of the DS to migrate + ($oldVersion, $oldMinor) = &getVersion($oldDir, $oldversionstr); + # get the version of the new DS + ($Version, $Minor) = &getVersion($root); + + # get old LIB_PATH + $old_libpath = &getLibPath($oldDir, $oldVersion, $oldMinor); + # get new LIB_PATH + $new_libpath = &getLibPath($root, $Version, $Minor); + + my $origFilePath = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}install${PATHSEP}schema${PATHSEP}" ; + my $FilesChanged = ""; + my $AllDiffs = "***********************************************************************"; + my $NoChanges = "" ; + my $lineToBegin = 0 ; + opendir(CONFDIR, $oldSchemaDir) or + die "Error: could not open migrated config dir $oldConfDir: $!"; + + foreach $file (readdir(CONFDIR)) { + $origFile = $origFilePath . $file ; + $configFile = $oldSchemaDir . $file ; + if (( exists($stdIncludes{lc($file)})) && (-f $origFile)) { + $diffs = &diff($configFile, $origFile, $lineToBegin); + $lineToBegin = 0 if $lineToBegin ; + if ($diffs) { + $FilesChanged .= "\n$configFile"; + $AllDiffs .= "\n$configFile is different than the standard configuration file" ; + $AllDiffs .= "\nYou will need to check this file and make sure its changes are compatible "; + $AllDiffs .= "with the new directory server\nHere are the differences:\n"; + $AllDiffs .= "$diffs \n\n"; + $AllDiffs .= "***********************************************************************"; + } + else { + $NoChanges .= "\n$configFile"; + } + } + } + closedir(CONFDIR); + +if ($FilesChanged) { + printTrace("\nNo changes to old configuration files:$NoChanges",3) ; + printTrace("\n***********************************************************************",3) ; + printMsg("\nThe following standard files have been modified: $FilesChanged"); + if ($NO_INPUT_USER) { + # do nothing + } + else { + printMsg("\nDo you want to see the differences Yes/No [No] ?") ; + my $answer = <STDIN> ; + if ($answer =~ /y|yes/i) { + printMsg("$AllDiffs"); + } + printMsg("\nDo you want to continue the migration Yes/No [No] ?"); + $answer = <STDIN> ; + if (! ($answer =~ /y|yes/i)) { + exit(1); + } + } + } +} + + + +############################################################################# + +# this is used to run the system() call, capture exit and signal codes, +# and die() upon badness; the first argument is a directory to change +# dir to, if any, and the rest are passed to system() +sub mySystem { + my $rc = &mySystemNoDie(@_); + my ($dir, @args) = @_; + if ($rc == 0) { +# success + } elsif ($rc == 0xff00) { + die "Error executing @args: error code $rc: $!"; + } elsif ($rc > 0x80) { + $rc >>= 8; + die "Error executing @args: error code $rc: $!"; + } else { + if ($rc & 0x80) { + $rc &= ~0x80; + } + die "Error executing @args: received signal $rc: $!"; + } + + # usually won't get return value + return $rc; +} + +# This version does not die but just returns the error code +sub mySystemNoDie { + my ($dir, @args) = @_; + if ($dir && ($dir ne "")) { + chdir($dir) or die "Could not change directory to $dir: $!"; + } + my $cmd = $args[0]; + # the system {$cmd} avoids some NT shell quoting problems if the $cmd + # needs to be quoted e.g. contains spaces; the map puts double quotes + # around the arguments on NT which are stripped by the command + # interpreter cmd.exe; but don't quote things which are already quoted + my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @args; + my $rc = 0; + if ($cmd =~ /[.](bat|cmd)$/) { + # we have to pass batch files directly to the NT command interpreter + $cmd = $com_spec; +# print "system $cmd /c \"@fixargs\"\n"; + $rc = 0xffff & system {$cmd} '/c', "\"@fixargs\""; + } else { +# print "system $cmd @fixargs\n"; + $rc = 0xffff & system {$cmd} @fixargs; + } + chdir(${curdir}) or die "Could not change directory to $curdir: $!"; + return $rc; +} + +########################################################################################### +# # +# Export/Import of the backends in @BACKENDS # +# # +########################################################################################### + +sub manydb2Ldif { + my $ldif_dir = shift; + $ENV{"$LIB_PATH"}=$old_libpath; + if (! $ldif_dir) { $ldif_dir = $ldif_rep ;} + if (!(-d $ldif_dir)) { + mkdir($ldif_dir,0777) or die "can't create $ldif_dir to store temporary ldif files"; + } + chdir($oldSlapdExecDir) or die "Could not change directory to $oldSlapdExecDir: $!"; + foreach $backend (@BACKENDS) { + my $ldif = "${ldif_dir}$backend.ldif" ; + &db2Ldif($ldif, $backend, $oldHome); + } + print " Done.\n"; + chdir($curdir) or die "Could not change directory to $curdir: $!"; +} + +sub db2Ldif { + my $ldif = shift ; + my $backend = shift ; + my $home = shift ; + my $include_suffix = shift ; + my $db2ldif_param ; + if ($include_suffix) { + $db2ldif_param = "db2ldif -r -D $home -n $backend -a $ldif -s \"$include_suffix\""; + } + else { + $db2ldif_param = "db2ldif -r -D $home -n $backend -a $ldif"; + } + open(DB2LDIF, "${quote}${quote}$slapdExecName${quote} $db2ldif_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n"; + sleep(1); # allow some data to accumulate in the pipe + my $ii = 0; + while (<DB2LDIF>) { + ++$ii; + if (($ii % 250) == 0) { + printMsg(" Processing...\n"); + } + printMsg($_); + } + close(DB2LDIF); + # set the ownership of the ldif file; should be the same as the 5.x slapd user id + if ((! $isNt) && ($oldlocaluser ne $localuser)) { + if (-f $ldif) { + chown( $newuid, $newgid, $ldif) or printMsg("\nUnable to change the ownership of $ldif to $localuser") ; + } + } +} + +sub manyLdif2db { + my $ldif_dir = shift; + $ENV{"$LIB_PATH"}=$new_libpath; + chdir($slapdExecDir) or die "Could not change directory to $slapdExecDir: $!"; + foreach $backend (@BACKENDS) { + my $ldif = "${ldif_dir}$backend.ldif" ; + &Ldif2db($ldif, $backend); + } + # remove the empty ldif directory + # but not if using the data dir + if (!$olddatadir) { + rmdir($ldif_dir); + } + chdir($curdir) or die "Could not change directory to $curdir: $!"; +} + + +sub Ldif2db { + my $ldif = shift ; + my $backend = shift ; + my $ldif2db_param = "ldif2db -D $serverHome -n $backend -i $ldif"; + open(LDIF2DB, "${quote}${quote}$slapdExecName${quote} $ldif2db_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n"; + sleep(1); # allow some data to accumulate in the pipe + while (<LDIF2DB>) { + printMsg($_); + } + close(LDIF2DB); + # remove the ldif file after the import + # but not if using the data dir + if (!$olddatadir) { + unlink($ldif) ; + } +} + + +########################################################################################### +# # +# Running/Stopping the Server # +# # +########################################################################################### + + + +sub isDirectoryAlive { + die "\n Migration aborted. Make sure your old and new Directory Servers are installed on the same machine \n" if ( $LDAPservername == -1 ); + my $test_conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd); + if ($test_conn) { + $test_conn->close(); + return 1; + } + else { + return 0 ; + } +} + + +sub startServer { + my $instanceDir = ${serverHome} ; + my $errLog = $instanceDir . $PATHSEP . 'logs' . $PATHSEP . 'errors'; + # emulate tail -f + # if the last line we see does not contain "slapd started", try again + my $done = 0; + my $started = 0; + my $code = 0; + my $lastLine = ""; + my $timeout = time + 240; # 4 minutes + $ENV{"$LIB_PATH"}=$new_libpath; + + my $startCmd = $instanceDir . $PATHSEP . 'start' . $script_suffix; + if (! -f $startCmd) { + $startCmd = $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix; + } + $code = &mySystem($instanceDir,$startCmd); + open(IN, $errLog) or die "Could not open error log $errLog: $!"; + my $pos = tell(IN); + while (($done == 0) && (time < $timeout)) { + for (; ($done == 0) && ($_ = <IN>); $pos = tell(IN)) { + $lastLine = $_; + # print; + # the server has already been started and shutdown once . . . + if (/slapd started\./) { + $started++; + if ($started == 2) { + $done = 1; + } + # sometimes the server will fail to come up; in that case, restart it + } elsif (/Initialization Failed/) { + # print "Server failed to start: $_"; + $code = &mySystem($instanceDir, $startCmd); + # sometimes the server will fail to come up; in that case, restart it + } elsif (/exiting\./) { + # print "Server failed to start: $_"; + #$code = &mySystem($startCmd); + $code = &mySystem($instanceDir, $startCmd); + } + } + if ($lastLine =~ /PR_Bind/) { + # server port conflicts with another one, just report and punt + print $lastLine; + print "This server cannot be started until the other server on this\n"; + print "port is shutdown.\n"; + $done = 1; + } + if ($done == 0) { + # rest a bit, then . . . + sleep(2); + # . . . reset the EOF status of the file desc + seek(IN, $pos, 0); + } + } + close(IN); + + sleep(5); + die "\nUnable to start the $Version.$Minor Directory Server\n" unless (isDirectoryAlive()); + + return 0; +} + +sub stopServer { + my $root = shift; + my $name = shift; + $maxStopIterations = 5; + print "\nShutting down server $name . . .\n"; + $ENV{"$LIB_PATH"}=$new_libpath; + $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop' . $script_suffix . $quote; + if (! -f $stopCmd) { + $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop-slapd' . $script_suffix . $quote; + } + + if (! -f $stopCmd) { + # no stop command, probably a 1.X system; for NT, we'll try net stop + # for unix, we'll get the pid and kill it + if ($isNT) { + $stopCmd = 'net stop ' . $name; + } else { + # see if there is a pid file + $pidfile = $root . $PATHSEP . $name . $PATHSEP . 'logs' . + $PATHSEP . 'pid'; + if (open(PIDFILE, $pidfile)) { + chomp($pid = <PIDFILE>); + close(PIDFILE); + while ($maxStopIterations-- && !$exitCode) { + $exitCode = kill(15, $pid); + } + $stopCmd = undef; + } + } + } + + # keep looping until the stop cmd returns an error code, which usually + # means that what ever we want to stop is stopped, or some other error + # occurred e.g. permission, or no such service + $exitCode = &runAndIgnoreOutput($stopCmd); +# print "stopServer: exitCode=$exitCode\n"; + while ($stopCmd && $maxStopIterations-- && $exitCode) { + $exitCode = &runAndIgnoreOutput($stopCmd); +# print "stopServer: exitCode=$exitCode\n"; + } + + if (!$maxStopIterations) { + print "Warning: could not shutdown the server: $!\n"; + } + sleep(10) ; + $exitCode = 0; +} + + +sub runAndIgnoreOutput { + my $cmd = shift; + printMsg("."); + open(RUNCMD, "${quote}$cmd${quote} 2>&1 |") or die "Error: could not run $cmd: $!"; + printMsg("."); + sleep(1); # allow pipe to fill with data + printMsg("."); + while (<RUNCMD>) { +# print; + } + my $code = close(RUNCMD); +# print "runAndIgnore: code=$code status=$?\n"; + return $?; +} + +############################################################################# +# migrate SSL info + +sub MigrateSSL { + my $secPwd = 'bidon' ; + # copy the SSL directory + ©Dir("$oldHome${PATHSEP}ssl","$serverHome${PATHSEP}ssl") if (-d "$oldHome${PATHSEP}ssl"); + # copy the cert db and key files + if ( -d "$oldDir${PATHSEP}alias") { + $aliasDir = "$root${PATHSEP}alias"; + if (! -d $aliasDir) { + mkdir($aliasDir, 0750); + } + &stopServer($root,'slapd-'.$newname); + my $keydb = "$aliasDir${PATHSEP}slapd-$newname-key3.db" ; + my $certdb = "$aliasDir${PATHSEP}slapd-$newname-cert8.db" ; + my $certdb7 = "$aliasDir${PATHSEP}slapd-$newname-cert7.db" ; + my $old_keydb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-key3.db" ; + my $old_certdb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-cert7.db"; + my $keydb_backup = "$aliasDir${PATHSEP}slapd-$newname-key3.db_backup" ; + my $certdb_backup = "$aliasDir${PATHSEP}slapd-$newname-cert7.db_backup" ; + if (-f $old_keydb) { + if (-f $keydb) { + if ($NO_INPUT_USER) { + printMsg("\n$keydb already exists. backup in $keydb_backup ..."); + ©BinFile($keydb,$keydb_backup); + ©BinFile($old_keydb,$keydb); + } + else { + print("\n\n$keydb already exists. Do you want to overwrite it ? [no]: "); + my $answer = <STDIN> ; + if ($answer =~ /^y|yes$/i) { + ©BinFile($old_keydb,$keydb); + } + } + } + else { + ©BinFile($old_keydb,$keydb); + } + } + if (-f $old_certdb) { + $mode = (stat($old_certdb))[2] if $PRESERVE; + if (-f $certdb) { + if ($NO_INPUT_USER) { + printMsg("\n$certdb already exists. backup in $certdb_backup ..."); + ©BinFile($certdb,$certdb_backup); + unlink($certdb) || print "Couldn't delete $certdb : $!\n"; + ©BinFile($old_certdb,$certdb7); + } + else { + print("\n\n$certdb already exists. Do you want to overwrite it ? [no]: "); + my $answer = <STDIN> ; + if ($answer =~ /^y|yes$/i) { + unlink($certdb) || print "Couldn't delete $certdb : $!\n"; + ©BinFile($old_certdb,$certdb7); + } + } + } + else { + ©BinFile($old_certdb,$certdb7); + } + } + # copy the old password file + if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") { + ©BinFile( + "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt", + "$aliasDir${PATHSEP}$type-$newname-pin.txt" + ); + } + &startServer(); + if ($PRESERVE) { + chown($newuid,$newgid,$certdb) || print "Failed to set uid $newuid gid $newgid on $certdb : $!\n"; + chmod($mode,$certdb) || print "Failed to set mode $mode on $certdb : $!\n"; + } + } + +} + +sub DisableSSL { + my $entry = $conn->search("cn=config","base","objectclass=*"); + my $LDAPparam = "nsslapd-security" ; + my $Value = "off" ; + if ($entry->{$LDAPparam}[0] ne $Value) { + printTrace("\nDisable SSL...",1); + $entry->setValues($LDAPparam, $Value); + } + my $res = $conn->update($entry); + if ($res) { + printTrace("\nSSL disabled",2); + } + else { + printMsg("\nCan't disabled SSL. The server may have problems to start"); + } +} + +# enable the migration of client authentication informations +sub MigrateCertmap { + # backup the old certmap.conf and replace it with the new one + my $oldCertmap = "$oldDir${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf"; + my $newCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf" ; + my $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ; + if (-f $oldCertmap) { + if ($NO_INPUT_USER) { + printMsg("\n$newCertmap has been backup in $backupCertmap"); + ©BinFile($newCertmap,$backupCertmap); + ©BinFile($oldCertmap,$newCertmap); + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\n\nWhere do you want to back up the file $newCertmap [$backupCertmap] ?") ; + my $Answer = <STDIN> ; + $backupCertmap = $Answer if ($Answer ne "\n"); + chomp($backupCertmap); + printTrace("\nDest: .$backupCertmap.",4); + if (-e $backupCertmap) { + printMsg("\n\n$backupCertmap already exists. Do you want to overwrite it Yes/No [No] ?") ; + if (<STDIN> =~ /yes|y/i) { + $Ask = 0 ; + } + else { + $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ; + } + } + else { + $Ask = 0 ; + } + } + printTrace("\nBackup file: $newCertmap in $backupCertmap",4); + ©BinFile($newCertmap,$backupCertmap); + ©BinFile($oldCertmap,$newCertmap); + } + } + else { + } +} + +sub hasChangedoldCertmap { + my $certmapfile = shift ; + my @reference = ("certmap default default", + "default:DNComps", + "default:FilterComps e") ; + my $cpt = 0 ; + printTrace("\nhasChangedoldCertmap",3); + open(CERTMAP,"< $certmapfile"); + while (<CERTMAP>) { + if ((! /^\s*#/) && (! /^\s*$/)) { + my $ref = $reference[$cpt] ; + printTrace("\nValue: $_, ref: $ref",4); + if (! /^\s*$ref\s*$/) { + return 1 ; + } + else { + $cpt++ ; + } + } + } + close (CERTMAP); + printTrace("\ncpt: $cpt",4); + if ($cpt < $#reference) { + return 1 ; + } + else { + return 0 ; + } +} + + +########################################################################################### +# # +# Copy directory and files functions # +# # +########################################################################################### + + +sub copyDir { + my $src = shift; + my $dest = shift; + my $exclude = shift; + + opendir( SRC, $src ) or die "Can't open directory $src: $!: "; + my $mode; + my $uid; + my $gid; + mkdir ( $dest , 0755 ) or die "\nCan't create directory $dest. \nPlease check you have enough rights to create it and/or check that your parent directory exists.\n" if !( -e $dest ); + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + local ( @files ) = readdir ( SRC ); + closedir( SRC ); + for ( @files ) { + if ( $_ eq "." || $_ eq ".." ) { + next; + } elsif ( $exclude && /$exclude/ ) { + next; + } elsif( -d "$src${PATHSEP}$_") { + ©Dir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" ); + } else { + ©BinFile ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_"); + } + } +} + +sub copyBinFile { + my $src = shift; + my $dest = shift; + my $buf = ""; + my $bufsize = 8192; + + open( SRC, $src ) || die "Can't open $src: $!\n"; + # if we are given a directory destination instead of a file, extract the + # filename portion of the source to use as the destination filename + if (-d $dest) { + $dest = $dest . $PATHSEP . &basename($src); + } + open( DEST, ">$dest" ) || die "Can't create $dest: $!\n"; + binmode SRC; + binmode DEST; + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + while (read(SRC, $buf, $bufsize)) { + print DEST $buf; + } + close( SRC ); + close( DEST ); +} + +############################################################################################################# +# backup 5.x configuration files # +# backup the directory <root_server5>/slapd-instance/config dans <root_server5>/slapd-instance/BackupConfig # # +# # +############################################################################################################# + + +sub backupConfigFiles { + # backup the 5.x config files + my $src = "$serverHome${PATHSEP}config" ; + my $dest = "$serverHome${PATHSEP}config_backup" ; + if ($NO_INPUT_USER) { + printMsg("\n$src has been backup in $dest"); + ©Dir($src,$dest); + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\n\nWhere do you want to back up your configuration directory [$dest] ?") ; + my $Answer = <STDIN> ; + $dest = $Answer if ($Answer ne "\n"); + chomp($dest); + printTrace("\nDest: .$dest.",4); + if (-e $dest) { + printMsg("\n\n$dest already exists. Do you want to overwrite it Yes/No [No] ?") ; + if (<STDIN> =~ /yes|y/i) { + $Ask = 0 ; + } + else { + $dest = "$serverHome${PATHSEP}config_backup" ; + } + } + else { + $Ask = 0 ; + } + } + printTrace("\nBackup Directory: $src in $dest",4); + ©Dir($src,$dest); + } +} +############################################################################# + +sub getLDAPservername { + my $oldLDAPservername; + my $LDAPservername; + my $localhost = "nsslapd-localhost"; + open(OLDDSELDIF, "< $oldDSEldif") or die "\nError: could not open old config file $oldDSEldif \n"; + my $in = new Mozilla::LDAP::LDIF(*OLDDSELDIF) ; + while ($entry = readOneEntry $in) { + my $DN = $entry->getDN(1) ; + if ($DN =~ /^cn=config$/i) { + my @values = $entry->getValues($localhost); + if ($entry->size($localhost)) { + $oldLDAPservername = $values[0]; + printTrace("\nName of the old LDAP server: $oldLDAPservername",3); + } + break; + } + } + close(OLDSELDIF); + + open( DSELDIF, "< $DSEldif" ) || die "\nCan't open $DSEldif \n"; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + my $DN = $entry->getDN(1) ; + if ($DN =~ /^cn=config$/i) { + my @values = $entry->getValues($localhost); + if ($entry->size($localhost)) { + $LDAPservername = $values[0]; + printTrace("\nName of the new LDAP server: $LDAPservername",3); + } + break; + } + } + close(DSELDIF); + # check ol and new Directory Instance are installed on the same physical machine. + if (lc($oldLDAPservername) ne lc($LDAPservername)) { + # warn the user he tries to migrate a 4.x server installed on a different machine from the 5.x one + printMsg("\n\nYour old instance is on $oldLDAPservername, whereas your new instance is on $LDAPservername. Migration on different machines is not supported. Do you want to continue ? Yes/No [No]:") ; + if (! (<STDIN> =~ /yes|y/i)) { + return -1; + } + } + return $LDAPservername ; +} + +############################################################################# + +sub getLibPath { + my $myDir = shift; + my $myVersion = shift; + my $myMinor = shift; + + if ($isNT) { + return $ENV{"$LIB_PATH"}; + } + if (($myVersion >= 6) && ($myMinor >= 2)) { + return + "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}". + "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}". + $ENV{"$LIB_PATH"}; + } else { + return "$myDir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + } +} + +############################################################################# + +sub getVersion { + my $dir = shift; + my $versionstr = shift; + my $version = 0; + my $minor = 0; + my $buildNumber = 0; + my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}"; + + # find the slapd executable + if (!$versionstr) { # version not specified on cmd line - find it + $prog = $dir . $progDir . $slapdExecName; + if (! -f $prog) { + $prog = $dir . $progDir2 . $slapdExecName; + if (-f $prog && $isNT) { + # if slapd is in bin/slapd and we're on NT, just assume version 1; + # apparently, slapd.exe doesn't like the -v argument . . . + return ( '1', $minor ); + } + else{ + die "Could not run slapd program $prog: $!"; + } + } + else { + chdir($dir . $progDir); + } + $cur_libpath=$ENV{"$LIB_PATH"}; + $ENV{"$LIB_PATH"}= + "$dir${PATHSEP}lib${SEP}". + "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}". + "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}". + $ENV{"$LIB_PATH"}; + # read the old version from the old slapd program + + open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or + die "Could not run slapd program $prog: $!"; + sleep(1); # allow some data to accumulate in the pipe +# print "Output from $prog -v:\n"; + while (<F>) { + if (/^Netscape-Directory/ || /^iPlanet-Directory/i) { + $versionstr = $_; + last; + } + } + $code = close(F); + # print "$prog returned code=$code status=$?\n"; + $ENV{"$LIB_PATH"}=$cur_libpath; + } + + if ($versionstr =~ /^Netscape-Directory\/(\d+)\.(\d+)(?:b\d)*\s+(\S+)/) { + $version = $1; + $minor = $2; + $buildNumber = $3; + } + elsif ($versionstr =~ /^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ... + $version = $1; + $minor = $2; + $buildNumber = $3; + } + elsif ($versionstr =~ /^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) { + $version = $1; + $minor = $2; + $buildNumber = $3; + } elsif ($versionstr =~ /(\d+)\.(\d+)/) { + $version = $1; + $minor = $2; + } + + if ($version == 0) { + die "\nCould not determine version of the directory server in $dir: \n"; + } + + # distinguish the 4.1 and the 4.11 thanks to the buildNumber + if (($version == 4) && ($minor == 1)){ + if (! ($buildNumber =~ /^B99\.16/)) { + # it's not a 4.1 Netscape Directory Server => it's a 4.11 + $minor = 11 ; + } + } + chdir($curdir) or die "Could not change directory to $curdir: $!" ; + return ( $version, $minor ); +} + +############################################################################################### +sub normalizeDir { + my $dir = shift ; + my $dir_prec = "" ; + while ($dir_prec ne $dir) { + $dir_prec = $dir ; + if ($isNT) { + grep { s@\\\\@\\@g } $dir ; + } + else { + grep { s@//@/@g } $dir ; + } + } + return $dir ; +} + + +############################################################################################### + +sub GetTime { + my $tm = localtime; + (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900); + $sec = "0$sec" unless $sec > 9 ; + $min = "0$min" unless $min > 9 ; + $hour = "0$hour" unless $hour > 9 ; + $dd = "0$dd" unless $dd > 9 ; + $mm = "0$mm" unless $mm > 9 ; + return ($sec, $min, $hour, $dd, $mm, $yy); +} + +############################################################################################### +# get uid and group id of the 5.x slapd server. +# The uid is done through the nsslapd-localuser attribute + +sub getuid_gid { + my $newuid ; + my $newgid ; + my $localuser ; + my $localuser_attr = "nsslapd-localuser" ; + if (! $isNT) { + &startServer() unless (isDirectoryAlive()); + my $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n"; + my $entry = $conn->search("cn=config ", "base","objectclass=*", 0, ($localuser_attr)) ; + # Tests wether we succeed to get the entry cn=config + die "\nCan't get the entry cn=config \n" unless ($entry); + my @values = $entry->getValues($localuser_attr); + $conn->close(); + if ($#values == -1 || ($values[0] eq "") ) { # tests wether the nsslapd-localuser attribute has a value + printMsg("\nNo localuser has been found in the configuration of the directory. "); + if ($NO_INPUT_USER) { + printMsg("\nWe considered nobody as the localuser"); + $localuser = "nobody" ; + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\nUnder what user does your $Version.$Minor directory server run [nobody] ? ") ; + $localuser = <STDIN> ; + chomp($localuser); + $localuser = "nobody" if ($localuser eq ""); + ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ; + if ($newuid) { + $Ask = 0 ; + } + else { + printMsg("\nError: $localuser is unknown from the system "); + } + } + } + } + else { + $localuser = $values[0]; # returns the first value (we should only have one localuser) + my $size = $#values ; + } + ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ; + return ($localuser, $newuid, $newgid) ; + } + else { + return () ; + } +} + +sub getolduid_gid { + my $oldlocaluser ; + my $localuserAttr = "nsslapd-localuser"; + my $entry ; + if (! $isNT) { + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + $typeOfEntry = getTypeOfEntry($entry); + if ($typeOfEntry eq "CONFIG_NODE") { + $oldlocaluser = $entry->{$localuserAttr}[0] if ($entry->exists($localuserAttr)); + break ; + } + } + close(DSE); + ($olduid, $oldgid) = (getpwnam("$oldlocaluser"))[2..3] ; + return ($oldlocaluser, $olduid, $oldgid) ; + } + else { + return (); + } +} +############################################################################################### +# get current directory + +sub getCwd { + my $command = $isNT ? "cd" : "/bin/pwd"; + open(PWDCMD, "$command 2>&1 |") or + die "Error: could not execute $command: $!"; + # without the following sleep, reading from the pipe will + # return nothing; I guess it gives the pwd command time + # to get some data to read . . . + sleep(1); + my $currentdir; + while (<PWDCMD>) { + if (!$currentdir) { + chomp($currentdir = $_); + } + } + my $code = close(PWDCMD); +# if ($code || $?) { +# print "$command returned code=$code status=$? dir=$curdir\n"; +# } +# print "getCwd curdir=\[$curdir\]\n"; + return $currentdir; +} + +################################ +# Need to migrate the credential. +# If the credential can not be migrated, leave it at it is +################################ +sub migrate_credential{ + my $entry_to_modify = shift; + my $credentials_attr = shift; + my @old_value = $entry_to_modify->getValues($credentials_attr); + my $migratecredExecName = 'migratecred'; + my $credOldHome = $oldHome; + my $credServerHome = $serverHome; + + if ($isNT) { + # oldHome may be pointing to the archived copy of the + # instance dir which may be different than the path that + # the instance was originally installed as on Windows. If + # this path is not the original install path, then the + # credential will not be migrated correctly. We should + # prompt the user on Windows for the correct path. + + print "\n\nThe old instance path must be the same as where it was"; + print "\ninitially installed, not where it was archived in order"; + print "\nfor this step to succeed. Please verify that the path"; + print "\nis correct. Note that case sensitivity is important here."; + print "\n\nOld Instance Directory: $credOldHome"; + print "\nIs this correct? (y/n): "; + chomp(my $answer = <STDIN>); + if (!($answer =~ /y|yes/i)) { + print "\nPlease enter the correct path for the old instance directory: "; + chomp($credOldHome = <STDIN>); + } + + print "\n\nThe new instance path must also be correct for this step"; + print "\nto succeed. Please verify that the path is correct. Note"; + print "\nthat case sensitivity is important here."; + print "\n\nNew Instance Directory: $credServerHome"; + print "\nIs this correct? (y/n): "; + chomp(my $answer = <STDIN>); + if (!($answer =~ /y|yes/i)) { + print "\nPlease enter the correct path for the new instance directory: "; + chomp($credServerHome = <STDIN>); + } + } +# print "\nMigratecred command is: ${quote}$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}$migratecredExecName${quote} -o $credOldHome -n $credServerHome -c @old_value\n"; + + my @new_cred = `${quote}$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}$migratecredExecName${quote} -o $credOldHome -n $credServerHome -c @old_value`; + + if ( $? == 0 ) + { + $entry_to_modify->setValues($credentials_attr, @new_cred); + } +} + diff --git a/ldap/admin/src/scripts/template-migrate5to7 b/ldap/admin/src/scripts/template-migrate5to7 new file mode 100644 index 00000000..50aead79 --- /dev/null +++ b/ldap/admin/src/scripts/template-migrate5to7 @@ -0,0 +1,3043 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# Migrate a 5.x directory server to a 7.0 directory server + +####################################################################################################### +# enable the use of Perldap functions +require DynaLoader; + +use Getopt::Std; +use Mozilla::LDAP::Conn; +use Mozilla::LDAP::Entry; +use Mozilla::LDAP::LDIF; +use Mozilla::LDAP::Utils qw(:all); +use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API +use Time::localtime; +use File::Basename; +use Class::Struct ; + +####################################################################################################### + +sub usage { + print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n"); + print(STDERR " -o oldInstancePath -n newInstancePath [-t tracelevel] [-L logfile]\n"); + print(STDERR "************** parameters in brackets are optionals, others are required **************\n"); + print(STDERR " Opts: -D rootdn - new 7.0 Directory Manager\n"); + print(STDERR " : -w password - new 7.0 Directory Manager's password\n"); + print(STDERR " : -w - - Prompt for new 7.0 Directory Manager's password\n"); + print(STDERR " : -j filename - Read new 7.0 Directory Manager's password from file\n"); + print(STDERR " : -p port - new 7.0 Directory Server port\n"); + print(STDERR " : -o oldInstancePath - Path of the old instance to migrate \n"); + print(STDERR " : -n newInstancePath - Path of the new 7.0 instance\n"); + print(STDERR " : [-d dataPath] - Path to directory containing data files to import into new instance\n"); + print(STDERR " : [-v oldVersion] - Version of old instance (obtained by running $slapdExecName -v\n"); + print(STDERR " : [-t tracelevel] - (optional) specify the level of trace (0..3)\n"); + print(STDERR " : [-L logfile] - (optional) specify the file to log the migration report \n"); + } +######################################################################################################## + +BEGIN { + + require 'uname.lib' ; + $isNT = -d '\\'; + $PATHSEP = $isNT ? "\\" : "/"; + ${SEP} = $isNT ? ";" : ":" ; + @INC = ( '.', '../../../admin/admin/bin'); + grep { s@/@\\@g } @INC if $isNT; + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + # NT needs quotes around some things unix doesn't + $quote = $isNT ? "\"" : ""; + + # If this variable is set, all file/directory creation will make sure the mode + # and ownership of the destination is the same as the source + $PRESERVE = 1 if (!$isNT); + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + if ($isNT) { + $os = "WINNT"; + } else { + $os = &uname("-s"); + } + if ($isNT) { + # we have to pass batch files directly to the NT command interpreter + $com_spec = $ENV{ComSpec}; + if (!$com_spec) { + $com_spec = $ENV{COMSPEC}; + } + if (!$com_spec || ! -f $com_spec) { + # find the first available command interpreter + foreach $drive (c..z) { + $com_spec = "$drive:\\winnt\\system32\\cmd.exe"; + last if (-f $com_spec); + $com_spec = undef; + } + if (! $com_spec) { + # punt and pray + $com_spec = 'c:\winnt\system32\cmd.exe'; + } + } + } + if ( $os eq "AIX" ) { + $dll_suffix = "_shr.a"; + } + elsif ( $os eq "HP-UX" ) { + $dll_suffix = ".sl"; + } + elsif ( $os eq "WINNT" ) { + $dll_suffix = ".dll"; + } + else { + $dll_suffix = ".so"; + } + $slapdExecName = $isNT ? 'slapd.exe' : './ns-slapd'; + select STDERR; + $| = 1; + select STDOUT; + $| = 1; +} + +SWITCH: { + if ($os eq "AIX") { + $LIB_PATH = "LIBPATH" ; + last SWITCH ; + } + if ($os eq "HP-UX") { + $LIB_PATH = "SHLIB_PATH" ; + last SWITCH ; + } + if ($isNT) { + $LIB_PATH = "PATH" ; + last SWITCH ; + } + else { + $LIB_PATH = "LD_LIBRARY_PATH" ; + last SWITCH ; + } + } + + # old parameters + ${oldDir} = "" ; + ${oldname} = "" ; + ${oldHome} = "" ; + ${oldConfDir} = "" ; + ${oldlocaluser} ; + ${olduid} ; + ${oldgid} ; + + # new parameters + ${root} = "{{DS-ROOT}}" ; + ${type} = "" ; + ${newname} = "" ; + ${newport} = "" ; + ${rootDN} = "" ; + ${rootpwd} = "" ; + ${localhost} = "" ; + ${LogFileReport} = "" ; + ${newuid} ; + ${localuser} ; + ${newgid} ; + $NO_INPUT_USER = 0 ; # by default user can give inputs during the migration process + ${curdir} = getCwd(); + ${slapdExecDir} = "${root}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + # in 7.0 the replica Id is setup to a static value + $replicaIdvalue = 65535; + + # specify the level of trace + $TRACELEVEL=1; + + $LDAP_SERVER_UNREACHABLE = 81; + + # get input users + &getParameters() ; + ${oldDir} = &normalizeDir("${oldDir}"); + ${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ; + ${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ; + ${oldSchemaDir} = "${oldConfDir}schema${PATHSEP}"; + ${oldDSEldif} = "${oldConfDir}dse.ldif"; + ${serverHome} = "${root}${PATHSEP}$type-$newname" ; + ${schemaDir} = "$serverHome${PATHSEP}config${PATHSEP}schema${PATHSEP}"; + ${DSEldif} = "$serverHome${PATHSEP}config${PATHSEP}dse.ldif"; + ${ldif_rep} = "${oldConfDir}ldif${PATHSEP}" ; + ${oldSlapdExecDir} = "${oldDir}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + + open(LOGFILE, ">> $LogFileReport"); + + printTrace("\noldDir: $oldDir, oldHome: $oldHome, \noldConfDir: $oldConfDir, \nldif_rep: $ldif_rep, \nrootDN: $rootDN, \nPort: $newport, \nNewname: $newname\n",3); + printTrace("\nLIB_PATH: $LIB_PATH",4); + + if (!(-d $serverHome)) { + printMsg("\n$serverHome doesn't exist\n"); + exit(1); + } + if (!(-d $oldHome)) { + printMsg("\n$oldHome doesn't exist\n"); + exit(1); + } + + if ($olddatadir && !(-d $olddatadir)) { + print("\n$olddatadir doesn't exist\n"); + exit(1); + } + + +%HashParametersName = (); + +# The following hash displays only general server parameters to migrate under cn=config +%GeneralSrvParamToMigrate = ( + 'nsslapd-accesscontrol'=> '\n', + 'nsslapd-errorlog-logging-enabled'=> '\n', + 'nsslapd-accesslog-logging-enabled'=> '\n', + 'nsslapd-auditlog-logging-enabled'=> '\n', + 'nsslapd-accesslog-level'=> '\n', + 'nsslapd-accesslog-logbuffering'=> '\n', + 'nsslapd-accesslog-logexpirationtime'=> '\n', + 'nsslapd-accesslog-logexpirationtimeunit'=> '\n', + 'nsslapd-accesslog-logmaxdiskspace'=> '\n', + 'nsslapd-accesslog-logminfreediskspace'=> '\n', + 'nsslapd-accesslog-logrotationtime'=> '\n', + 'nsslapd-accesslog-logrotationtimeunit'=> '\n', + 'nsslapd-accesslog-maxlogsize'=> '\n', + 'nsslapd-accesslog-maxLogsPerDir'=> '\n', + 'nsslapd-attribute-name-exceptions'=> '\n', + 'nsslapd-auditlog-logexpirationtime'=> '\n', + 'nsslapd-auditlog-logexpirationtimeunit'=> '\n', + 'nsslapd-auditlog-logmaxdiskspace'=> '\n', + 'nsslapd-auditlog-logminfreediskspace'=> '\n', + 'nsslapd-auditlog-logrotationtime'=> '\n', + 'nsslapd-auditlog-logrotationtimeunit'=> '\n', + 'nsslapd-auditlog-maxlogsize'=> '\n', + 'nsslapd-auditlog-maxLogsPerDir'=> '\n', + 'nsslapd-certmap-basedn'=> '\n', + 'nsslapd-ds4-compatible-schema'=> '\n', + 'nsslapd-enquote-sup-oc'=> '\n', + 'nsslapd-errorlog-level'=> '\n', + 'nsslapd-errorlog-logexpirationtime'=> '\n', + 'nsslapd-errorlog-logexpirationtimeunit'=> '\n', + 'nsslapd-errorlog-logmaxdiskspace'=> '\n', + 'nsslapd-errorlog-logminfreediskspace'=> '\n', + 'nsslapd-errorlog-logrotationtime'=> '\n', + 'nsslapd-errorlog-logrotationtimeunit'=> '\n', + 'nsslapd-errorlog-maxlogsize'=> '\n', + 'nsslapd-errorlog-maxlogsperdir'=> '\n', + 'nsslapd-groupevalnestlevel'=> '\n', + 'nsslapd-idletimeout'=> '\n', + 'nsslapd-ioblocktimeout'=> '\n', + 'nsslapd-lastmod'=> '\n', + 'nsslapd-listenhost'=> '\n', + 'nsslapd-maxdescriptors'=> '\n', + 'nsslapd-nagle'=> '\n', + 'nsslapd-readonly'=> '\n', + 'nsslapd-referralmode'=> '\n', + 'nsslapd-plugin-depends-on-name'=> '\n', + 'nsslapd-plugin-depends-on-type'=> '\n', + 'nsslapd-referral'=> '\n', + 'nsslapd-reservedescriptors'=> '\n', + 'nsslapd-rootpwstoragescheme'=> '\n', + 'nsslapd-schemacheck'=> '\n', + 'nsslapd-secureport'=> '\n', + 'nsslapd-security'=> '\n', + 'nsslapd-sizelimit'=> '\n', + 'nsslapd-ssl3ciphers'=> '\n', + 'nsslapd-timelimit'=> '\n', + 'passwordchange'=> '\n', + 'passwordchecksyntax'=> '\n', + 'passwordexp'=> '\n', + 'passwordhistory'=> '\n', + 'passwordinhistory'=> '\n', + 'passwordlockout'=> '\n', + 'passwordlockoutduration'=> '\n', + 'passwordmaxage'=> '\n', + 'passwordmaxfailure'=> '\n', + 'passwordminage'=> '\n', + 'passwordminlength'=> '\n', + 'passwordmustchange'=> '\n', + 'passwordresetfailurecount' => '\n', + 'passwordstoragescheme' => '\n', + 'passwordunlock' => '\n', + 'passwordwarning' => '\n' +); + +# the following hash displays global parameters related to database stored under cn=config,cn=ldbm database,cn=plugins,cn=config +%GlobalConfigLDBMparamToMigrate = ( + 'nsslapd-allidsthreshold' => '\n', + 'nsslapd-lookthroughlimit' => '\n', + 'nsslapd-mode' => '\n', + 'nsslapd-dbcachesize' => '\n', + 'nsslapd-cache-autosize' => '\n', + 'nsslapd-cache-autosize-split' => '\n', + 'nsslapd-db-transaction-logging' => '\n', + 'nsslapd-import-cachesize' => '\n' +); + +# the following hash displays specific parameters to each backends and stored under cn=DBname,cn=ldbm database,cn=plugins,cn=config +%LDBMparamToMigrate = ( + 'nsslapd-cachesize' => '\n', + 'nsslapd-cachememsize' => '\n', + 'nsslapd-readonly' => '\n', + 'nsslapd-require-index' => '\n' +); + + +%ChainingConfigParams = ( + 'nsactivechainingcomponents' => '\n', + 'nstransmittedcontrols' => '\n' + ); + +%ChainingDefaultInstanceConfigParams = ( + 'nsabandonedsearchcheckinterval' => '\n', + 'nsbindconnectionslimit' => '\n', + 'nsbindtimeout' => '\n', + 'nsbindretrylimit' => '\n', + 'nshoplimit' => '\n', + 'nsmaxresponsedelay' => '\n', + 'nsmaxtestresponsedelay' => '\n', + 'nschecklocalaci' => '\n', + 'nsconcurrentbindlimit' => '\n', + 'nsconcurrentoperationslimit' => '\n', + 'nsconnectionlife' => '\n', + 'nsoperationconnectionslimit' => '\n', + 'nsproxiedauthorization' => '\n', + 'nsreferralonscopedsearch' => '\n', + 'nsslapd-sizelimit' => '\n', + 'nsslapd-timelimit' => '\n' +); + +%changelog5params = ( + 'nsslapd-changelogmaxage' => '\n', + 'nsslapd-changelogmaxentries' => '\n' + ); + +@SNMPparams = ( + 'nssnmpenabled', + 'nssnmporganization', + 'nssnmplocation', + 'nssnmpcontact', + 'nssnmpdescription', + 'nssnmpmasterhost', + 'nssnmpmasterport', + 'nssnmpenabled', + 'aci' + ); + +%stdIncludes = ( + "." => "\n", + ".." => "\n", + "30ns-common.ldif " => "\n", + "50ns-mail.ldif " => "\n", + "50ns-news.ldif" => "\n", + "50iplanet-servicemgt.ldif"=> "\n", + "50netscape-servicemgt.ldif"=> "\n", + "50ns-mcd-browser.ldif" => "\n", + "50ns-proxy.ldif" => "\n", + "00core.ldif" => "\n", + "50ns-admin.ldif" => "\n", + "50ns-mcd-config.ldif " => "\n", + "50ns-value.ldif" => "\n", + "05rfc2247.ldif" => "\n", + "50ns-calendar.ldif" => "\n", + "50ns-mcd-li.ldif" => "\n", + "50ns-wcal.ldif" => "\n", + "05rfc2927.ldif" => "\n", + "50ns-certificate.ldif" => "\n", + "50ns-mcd-mail.ldif" => "\n", + "50ns-web.ldif" => "\n", + "10rfc2307.ldif" => "\n", + "50ns-compass.ldif" => "\n", + "50ns-media.ldif" => "\n", + "20subscriber.ldif" => "\n", + "50ns-delegated-admin.ldif"=> "\n", + "50ns-mlm.ldif" => "\n", + "25java-object.ldif" => "\n", + "50ns-directory.ldif" => "\n", + "50ns-msg.ldif" => "\n", + "28pilot.ldif" => "\n", + "50ns-legacy.ldif" => "\n", + "50ns-netshare.ldif" => "\n" +); + + +# Backends migrated (Backend CN attribute value) +@BACKENDS = () ; +# All pairs of suffix-backend are registered in this hashtable +%oldBackends = () ; + +#store the backend instances to migrate +@LDBM_backend_instances = (); + +#store the mapping tree +@Mapping_tree_entries = (); + +#store the suffix and the associated chaining backend +%oldChainingBackends = (); + +#store the multiplexor bind entries to migrate +%MultiplexorBindDNEntriesToMigrate = (); + +#store the Replica bind DN entries to migrate +%ReplicaBindDNEntriesToMigrate = (); + +# list of standard plugins +%stdPlugins = ( + "7-bit check" => "\n", + "acl plugin" => "\n", + "acl preoperation" => "\n", + "binary syntax" => "\n", + "case exact string syntax" => "\n", + "case ignore string syntax" => "\n", + "chaining database" => "\n", + "class of service" => "\n", + "country string syntax" => "\n", + "distinguished name syntax" => "\n", + "generalized time syntax" => "\n", + "integer syntax" => "\n", + "internationalization plugin" => "\n", + "ldbm database" => "\n", + "legacy replication plugin" => "\n", + "multimaster replication plugin" => "\n", + "octet string syntax" => "\n", + "clear" => "\n", + "crypt" => "\n", + "ns-mta-md5" => "\n", + "sha" => "\n", + "ssha" => "\n", + "postal address syntax" => "\n", + "referential integrity postoperation" => "\n", + "retro changelog plugin" => "\n", + "roles plugin" => "\n", + "telephone syntax" => "\n", + "uid uniqueness" => "\n", + "uri syntax" => "\n" + ); + +# list of indexes that have disappeared from the new schema compared to 5.0 +%deniedIndexes = ( + 'dncomp' => "\n" +); + +@default_indexes = (); +@indexes = (); + +# list of user added Plugin's. In 7.0, they 'll need to be recompiled +@badPlugins = () ; + +@pluginAttrs = ( + "objectclass", + "cn", + "nsslapd-pluginpath", + "nsslapd-plugininitfunc", + "nsslapd-plugintype", + "nsslapd-pluginenabled", + "nsslapd-plugin-depends-on-type", + "nsslapd-pluginid", + "nsslapd-pluginversion", + "nsslapd-pluginvendor" + ); + +@nsds5replicaAttrs = ( + 'objectclass', + 'nsDS5ReplicaRoot', + 'nsDS5ReplicaType', + 'nsDS5ReplicaLegacyConsumer', + 'nsDS5flags', + 'nsDS5ReplicaId', + 'nsDS5ReplicaPurgeDelay', + 'nsDS5ReplicaBinddn', + 'cn', + 'nsDS5ReplicaReferral' + ); + +# array of replicas to migrate +@new6replicas = (); + +# array of replication agreements to migrate +@replicationAgreements = (); + +# compare LDIF standard config files with standard ones +CompareStdConfigFiles() ; +die "\n\n The version of product you want to migrate is not a 5.x Directory Server\n" unless ($oldVersion == 5) ; + +# Shutdown the legacy Directory instance +printTrace("\nShutdown the legacy Directory Server instance: ${oldHome}",0); +&stopServer($oldDir, 'slapd-'.$oldname); + +# get the hostname of the new LDAP server +my $LDAPservername = &getLDAPservername(); + +# get the uid and gid of the 7.0 slapd user +($localuser, $newuid, $newgid) = getuid_gid(); +# get the uid and gid of the 5.x slapd user +($oldlocaluser, $olduid, $oldgid) = getolduid_gid(); +printTrace("\n7.0 localuser: $localuser, uid: $newuid, gid: $newgid",2); +printTrace("\n5.x localuser: $oldlocaluser, uid: $olduid, gid: $oldgid",2); + +# backup 7.0 configuration files in <6server_root>/slapd-instancename/config +printTrace("\nBackup $serverHome${PATHSEP}config on $serverHome${PATHSEP}config_backup ...",0); +&backupConfigFiles(); + +# migrate the schema (need to stop and start the 7.0 server) +printTrace("\nMigrate the schema...",0); +MigrateSchema(); + +# start the server unless it is already started +&startServer() unless (isDirectoryAlive()); + +############### Connect to the 7.0 LDAP Directory Server ###################### +$ENV{"$LIB_PATH"} = $new_libpath; + +die "\n Migration aborted. Make sure your old and new Directory Server are installed on the same machine \n" if ( $LDAPservername == -1 ); +$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + +# Cconnection to 7.0 LDAP server is successful ! +printTrace("\nConnected to $Version.$Minor LDAP server",0) ; + +# Parse the main configuration file: dse.ldif +printTrace("\n\nParse the old DSE ldif file: $oldDSEldif *****",0, 1); +printTrace("\nThis may take a while ...\n",0); +&MigrateDSEldif(); + +#migrate LDBM backend instances +printTrace("\n\nMigrate LDBM backend instances...",0,1); +&migrateLDBM_backend_instances(); + +#migrate mapping tree entries +printTrace("\n\nMigrate mapping tree...",0,1); +&migrateMappingTree(); + +#migrate default indexes +printTrace("\n\nMigrate default indexes...",0,1); +migrateDefaultIndexes(); + +#migrate indexes +printTrace("\n\nMigrate indexes...",0,1); +migrateIndexes(); + +#migrate replicas +printTrace("\n\nMigrate replicas...",0,1); +&MigrateNSDS5_replica(); + +#migrate replication agreements +printTrace("\n\nMigrate replication agreements...",0,1); +&MigrateNSDS_replication_agreement(); + +#migrate key/cert databases +printTrace("\n\nMigrate key/cert databases...",0,1); +&MigrateSSL(); + +# migrate certmap.conf +printTrace("\n\nMigrate Certmap.conf...",0,1); +&MigrateCertmap() ; + +################## Close the connection to 7.0 LDAP Server ##################### +printTrace("\n\n***** Close the LDAP connection to the new Directory Server instance ***** ",0); +$conn->close; + + +################## stop the new instance and Export/Import the data, restart the server ################## +if (@BACKENDS) { + &stopServer($root,'slapd-'.$newname); + if ($olddatadir) { + printTrace("\nData already contained in $olddatadir...\n",0,1) ; + $ldif_rep = "$olddatadir${PATHSEP}"; + } else { + printTrace("\nData processing...\n",0,1) ; + # migrate data for each backend: 5.x -> LDIF files + &manydb2Ldif($ldif_rep); + } + + # migrate LDIF data to the new database: LDIF -> New + &manyLdif2db($ldif_rep); + &migrateChangelog(); + printTrace("\n***** Migrate ReplicaBindDN entries...\n",0,1); + &importReplicaBindDNEntries(); + printTrace("\n***** Migrate MultiplexorBindDN entries...\n",0,1); + &importMultiplexorBindDNEntries(); + &startServer() unless (isDirectoryAlive()); +} +else { + printTrace("\nINFORMATION - There are no non-standard or non-already existing suffixes to migrate\n",0); + &migrateChangelog(); + printTrace("\n***** Migrate ReplicaBindDN entries...\n",0,1); + &importReplicaBindDNEntries(); + printTrace("\n***** Migrate MultiplexorBindDN entries...\n",0,1); + &importMultiplexorBindDNEntries(); +} + +printMsg("\n\n ****** End of migration ******\n\n"); + +close(LOGFILE); + + +########################################################################################### +# get input users +sub getParameters { + my $exit = 0 ; + my $i = 0; + my $pwdfile= ""; + + while ($i <= $#ARGV) { + if ( "$ARGV[$i]" eq "-D" ) { # directory manager + if (! $rootDN) { + $rootDN = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-w") { # password + if (! $rootpwd) { + $rootpwd = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-j") { # password file + if (! $pwdfile) { + $pwdfile = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-o") { # old instance path + if (! $oldHome ) { + $oldHome = $ARGV[++$i] ; + grep { s@\\@/@g } $oldHome if $isNT ; + if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; } + if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) { + $oldDir = $1 ; + $type = $2 ; + $oldname = $3 ; + if ($isNT) { + $oldDir = lc($oldDir) ; + $type = lc($type) ; + $oldname = lc($oldname) ; + $oldHome = lc($oldHome) ; + grep { s@/@\\@g } $oldDir ; + grep { s@/@\\@g } $oldHome ; + } + } + else { + print("\nThe old instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-n") { # new instance path + if (! $serverHome ) { + $serverHome = $ARGV[++$i] ; + grep { s@\\@/@g } $root if $isNT ; + grep { s@\\@/@g } $serverHome if $isNT ; + if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; } + if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) { + $root = $1 if ($1); + $type = $2 ; + $newname = $3 ; + if ($isNT) { + $root = lc($root) ; + $type = lc($type) ; + $newname = lc($newname) ; + $serverHome = lc($serverHome) ; + grep { s@/@\\@g } $root ; + grep { s@/@\\@g } $serverHome ; + } + } + else { + print("\nThe new instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-p") { # new DS port + if (! $newport ) { + $newport = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-d") { # old instance LDIF data dir + if (! $olddatadir ) { + $olddatadir = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-v") { # old version + if (! $oldversionstr ) { + $oldversionstr = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL + my $value = $ARGV[++$i] ; + if ($value =~ /[0-3]/) { + $TRACELEVEL = $value ; + } + else { + print("\nThe tracelevel must belong to 0..3 interval"); + &usage(); + exit(); + } + } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing + $NO_INPUT_USER = 1 ; + } elsif ("$ARGV[$i]" eq "-L") { # migration logfile + $LogFileReport = $ARGV[++$i] ; + } + else { + print("\nThe option $ARGV[$i] is not recognized"); + &usage() ; + exit(1); + } + $i++; + } + if (! $rootDN) { + print("\nThe rootDN is missing"); + $exit = 1; + } + if ($pwdfile ne "") { + # Open file and get the password + unless (open (RPASS, $pwfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $rootpwd = <RPASS>; + chomp($rootpwd); + close(RPASS); + } elsif ($rootpwd eq "-"){ + # Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; + # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $rootpwd = ReadLine(0); +# chomp($rootpwd); +# ReadMode('normal'); + } + if (! $rootpwd) { + print("\nThe rootpwd is missing"); + $exit = 1 ; + } + if (! $newport) { + print("\nThe port is missing"); + $exit = 1; + } + if (! $serverHome) { + print("\nThe new instance path is missing"); + $exit = 1; + } + if (! $oldHome) { + print("\nThe old instance path is missing"); + $exit = 1; + } + if ((! $LogFileReport) && $serverHome) { + ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime(); + $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log"; + } + if ($exit) { + &usage() ; + exit(1); + } + +} + +################################################################################################### + +sub MigrateSchema{ + my $FilesChanged = ""; + my $AllDiffs = ""; + my $NoChanges = "" ; + my $lineToBegin = 0 ; + opendir(SCHEMADIR, $oldSchemaDir) or + die "Error: could not open migrated config dir $oldSchemaDir: $!"; + + foreach $file (readdir(SCHEMADIR)) { + if (! exists($stdIncludes{lc($file)})) { + my $newSchemaFile = $schemaDir . $file; + if (-f $newSchemaFile ) { + # The ldif file already exists. Make a diff and warn the user if different. + if (diff($newSchemaFile, $oldSchemaDir.$file)) { + &stopServer($root,'slapd-'.$newname) if (isDirectoryAlive()); + $AllDiffs .= "\n$file"; + copyBinFile("$oldSchemaDir$file", $newSchemaFile); + } + } + else { + &stopServer($root,'slapd-'.$newname) if (isDirectoryAlive()); + $AllDiffs .= "\n$file"; + copyBinFile("$oldSchemaDir$file", $newSchemaFile); + } + } + } + closedir(SCHEMADIR); + if ($AllDiffs) { + printMsg("\n\n***********************************************************************"); + printMsg("\nThe following LDIF files have been migrated:"); + printMsg("$AllDiffs"); + printMsg("\n*************************************************************************\n\n"); + } + &startServer() if (! isDirectoryAlive()); +} + + +################################################################################################### +# This subroutine is used to parse the dse.ldif file and call specific routines to act with entries +sub MigrateDSEldif { + printTrace("\nMigrate DSE entries...",1); + my $tempoAlreadyDone = 0; + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + $typeOfEntry = getTypeOfEntry($entry); + SWITCH: { + if ($typeOfEntry eq "LDBM_BACKEND_INSTANCE"){ + parseLDBM_backend_instance($entry); + last SWITCH; + } + if ($typeOfEntry eq "MAPPING_TREE"){ + parseMapping_tree($entry); + last SWITCH; + } + if ($typeOfEntry eq "DEFAULT_INDEX"){ + parseDefaultIndex($entry); + last SWITCH; + } + if ($typeOfEntry eq "INDEX"){ + parseIndex($entry); + last SWITCH; + } + if ($typeOfEntry eq "STANDARD_PLUGIN"){ + migrateStdPlugin($entry); + last SWITCH; + } + if ($typeOfEntry eq "CONFIG_NODE"){ + migrateConfig_Node($entry); + last SWITCH; + } + if ($typeOfEntry eq "CONFIG_LDBM_DATABASE"){ + migrateConfig_LDBM_database($entry); + last SWITCH; + } + if ($typeOfEntry eq "CHAINING_BACKEND_CONFIG"){ + migrateChainingBE_config($entry); + last SWITCH; + } + if ($typeOfEntry eq "CHAINING_BACKEND_INSTANCE"){ + migrateChainingBE_instance($entry); + last SWITCH; + } + if ($typeOfEntry eq "NSDS5_REPLICA"){ + parseNSDS5_replica($entry); + last SWITCH; + } + if ($typeOfEntry eq "NSDS_REPLICATION_AGREEMENT"){ + parseNSDS_replication_agreement($entry); + last SWITCH; + } + if ($typeOfEntry eq "CHANGELOG5"){ + migrateChangelog5($entry); + last SWITCH; + } + if ($typeOfEntry eq "REPLICATION"){ + migrateReplication($entry); + last SWITCH; + } + if ($typeOfEntry eq "SECURITY"){ + migrateSecurity($entry); + last SWITCH; + } + if ($typeOfEntry eq "SNMP"){ + migrateSNMP($entry); + last SWITCH; + } + } + + } + close(DSELDIF); +} + +############################################################################# +# returns the "type of an entry". If the entry is not to be migrated its type is "NOT_MIGRATED_TYPE" + +sub getTypeOfEntry{ + my $entry = shift; + my $DN = $entry->getDN(1) ; # 1 is to normalize the returned DN + if (($DN =~ /cn=ldbm database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsBackendInstance"))) { + return "LDBM_BACKEND_INSTANCE"; + } + if (($DN =~ /cn=mapping tree,cn=config$/i) && (isObjectclass($entry,"nsMappingTree"))) { + return "MAPPING_TREE"; + } + if (($DN =~ /cn=default indexes,cn=config,cn=ldbm database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsIndex"))) { + return "DEFAULT_INDEX"; + } + if (isObjectclass($entry,"nsIndex")) { + return "INDEX"; + } + if ((isObjectclass($entry,"nsSlapdPlugin")) && (isStdPlugin($entry))) { + return "STANDARD_PLUGIN"; + } + if ($DN =~ /^cn=config$/i) { + return "CONFIG_NODE"; + } + if ($DN =~ /^cn=config,cn=ldbm database,cn=plugins,cn=config$/i) { + return "CONFIG_LDBM_DATABASE"; + } + if (($DN =~ /^cn=config,cn=chaining database,cn=plugins,cn=config$/i) || ($DN =~ /^cn=default instance config,cn=chaining database,cn=plugins,cn=config$/i)){ + return "CHAINING_BACKEND_CONFIG"; + } + if (($DN =~ /cn=chaining database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsBackendInstance"))) { + return "CHAINING_BACKEND_INSTANCE"; + } + if (isObjectclass($entry,"nsDS5Replica")) { + return "NSDS5_REPLICA"; + } + if (isObjectclass($entry,"nsDS5ReplicationAgreement")) { + return "NSDS_REPLICATION_AGREEMENT"; + } + if ($DN =~ /^cn=changelog5,cn=config$/i) { + return "CHANGELOG5"; + } + if (($DN =~ /cn=replication,cn=config$/i) && ($DN !~ /^cn=replication,cn=config$/i)) { + return "REPLICATION"; + } + if ($DN =~ /cn=encryption,cn=config$/i) { + return "SECURITY"; + } + if ($DN =~ /^cn=SNMP,cn=config$/i) { + return "SNMP"; + } + return "NOT_MIGRATED_TYPE"; +} + +############################################################################# + + + +############################################################################# +# returns 1 if the objectclass given in parameter is present in the objectclasses values of the entry +# given in parameter, 0 else + +sub isObjectclass { + my $entry = shift; + my $objectclass = shift; + return ($entry->hasValue("objectclass",$objectclass,1)); +} + +############################################################################# + +sub isStdPlugin { + my $entry = shift; + my $CN = $entry->{cn}[0]; + if (isObjectclass($entry,"nsSlapdPlugin")) { + return 1 if ($stdPlugins{lc($CN)}); + } + return 0; +} + + +############################################################################# + +sub alreadyExistsInNew{ + my $entry = shift; + my $mustExist = shift; + my $DN = $entry->getDN(1); # 1 to normalize the DN + # We have a name change of "uid uniqueness" plugin in DS6.x + # to "attribute uniqueness" + $DN =~ s/uid\ uniqueness/attribute\ uniqueness/ if ($DN =~ /uid\ uniqueness/); + return searchEntry($DN, $mustExist); +} + +############################################################################# +sub searchEntry { + my $DN = shift; + my $mustExist = shift; + my $res = $conn->search($DN, "base", "objectclass=*"); + my $cpt = 5; + if ($res) { + return $res; + } + else { + my $errorCode = $conn->getErrorCode(); + while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) { + printMsg("\ntry to reconnect to search $DN"); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + $res = $conn->search($DN, "base", "objectclass=*"); + $errorCode = $conn->getErrorCode(); + $cpt--; + } + if ($res){ + return $res ; + } + elsif (($errorCode eq $LDAP_SERVER_UNREACHABLE) || ($mustExist)) { + my $msg = $conn->getErrorString(); + printMsg("\n\n*** Failed to search: $DN"); + printMsg("\n*** Error Msg: $msg, Error code: $errorCode"); + } + return 0; + } +} + + +############################################################################# + +sub addEntryToNew{ + my $entry = shift; + my $typeOfEntry = shift; + my $trace = shift; + my $res = $conn->add($entry); + my $DN = $entry->getDN(1); + my $cpt = 5; + if ($res) { + printTrace("\n$typeOfEntry - Add successfull: $DN",$trace); + return 1; + } + else { + my $errorCode = $conn->getErrorCode(); + while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) { + printMsg("\ntry to reconnect to add $DN"); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + $res = $conn->add($entry); + $errorCode = $conn->getErrorCode(); + $cpt--; + } + if ($res){ + printTrace("\n$typeOfEntry - Add successfull: $DN",$trace); + return 1; + } + else { + my $msg = $conn->getErrorString(); + printMsg("\n\n*** $typeOfEntry: Add Failed: $DN"); + printMsg("\n*** Error Msg: $msg, Error code: $errorCode"); + return 0; + } + } +} + +############################################################################# + +sub updateEntry{ + my $entry = shift; + my $typeOfEntry = shift; + my $CHECK = shift; + my $trace = shift; + my $cpt = 5; + if ($CHECK) { + if (! hasChanged($entry, $typeOfEntry)) { + return 1; + } + } + my $res = $conn->update($entry); + my $DN = $entry->getDN(1); + if ($res) { + printTrace("\n$typeOfEntry - Update successfull: $DN",$trace); + return 1 ; + } + else { + my $errorCode = $conn->getErrorCode(); + while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) { + printMsg("\ntry to reconnect to update $DN"); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + $res = $conn->update($entry); + $errorCode = $conn->getErrorCode(); + $cpt--; + } + if ($res){ + printTrace("\n$typeOfEntry - Update successfull: $DN",$trace); + return 1; + } + else { + my $msg = $conn->getErrorString(); + printMsg("\n\n*** $typeOfEntry - Update Failed: $DN"); + printMsg("\n*** Error Msg: $msg, Error code: $errorCode"); + return 0; + } + } +} + + +############################################################################# +# returns 1 if the entry to migrate and the current entry are different one another + +sub hasChanged { + my $entry = shift; + my $typeOfEntry = shift; + my $DN = $entry->getDN(1); + my $newEntry = searchEntry($DN,1); + return 1 if (! $newEntry); # we shoudn't be in that case ... + # do the stuff to check wether the entry has changed or not given its type + if (($typeOfEntry eq "DEFAULT_INDEX") || ($typeOfEntry eq "INDEX")){ + my @indexTypes = $entry->getValues("nsIndexType"); + my @newIndexTypes = $newEntry->getValues("nsIndexType"); + my @nsmatchingrules = $entry->getValues("nsmatchingrule"); + my @newMatchingRules = $newEntry->getValues("nsmatchingrule"); + return 1 if (Diffs(\@indexTypes, \@newIndexTypes)); + return 1 if (Diffs(\@nsmatchingrules,\@newMatchingRules)); + return 0; + } + if ($typeOfEntry eq "CHANGELOG5"){ + printTrace("\nCheck wether changelog has changed or not",3); + my @params = keys(%changelog5params); + foreach $param (@params){ + my @values = $entry->getValues($param); + my @newValues = $newEntry->getValues($param); + return 1 if (Diffs(\@values,\@newValues)); + } + return 0; + } + if ($typeOfEntry eq "SNMP"){ + foreach $param (@SNMPparams){ + my @values = $entry->getValues($param); + my @newValues = $newEntry->getValues($param); + return 1 if (Diffs(\@values,\@newValues)); + } + return 0; + } + # we don't know how to compare such type of entry => just return 1 + return 1 ; +} + +sub isAsystemIndex { + my $index = shift; + return ($index->hasValue("nsSystemIndex","true",1)); +} + + +sub updatePathInPluginArgs { + my $plugin = shift; + my $argNum = 0; + my $argPrefix = "nsslapd-pluginarg"; + my $cont = 1; + my $Unix_oldDir = ${oldDir} ; + my $Unix_root = ${root} ; + grep { s@\\@/@g } $Unix_oldDir if $isNT; + grep { s@\\@/@g } $Unix_root if $isNT; + while ($cont) { + my $arg = $argPrefix . $argNum ; + if ($plugin->exists($arg)) { + $_ = $plugin->{$arg}[0] ; + s@$Unix_oldDir@$Unix_root@ig ; + s/$type-$oldname/$type-$newname/ig ; + $plugin->setValues($arg, $_) ; + } + else { + $cont = 0 ; + } + $argNum++; + } + return $plugin; +} + + +sub Diffs { + my $valuesToMigrate = shift; + my $currentValues = shift; + return 1 if (getDiff(\@{$valuesToMigrate},\@{$currentValues})); + return 1 if (getDiff(\@{$currentValues},\@{$valuesToMigrate})); + return 0 ; +} + +sub getDiff { + # we get references to arrays + my $elements = shift ; + my $existing_elements = shift ; + my %count = () ; + my %countEE = () ; + @diff = () ; + foreach $e (@{$elements}, @{$existing_elements}) { $count{$e}++ ;} + foreach $e (@{existing_elements}) { $countEE{$e}++ ;} + foreach $e (@{$elements}) { + # if $e is only present in @$elements, we push it to the diff array + if (($count{$e} == 1) && ($countEE{$e} == 0)) { + push @diff, $e ; + } + } + return @diff ; +} + +sub registerSuffix_Backend { + my $ldbmDatabase = shift; + my $CN = $ldbmDatabase->{cn}[0]; + my $suffixArg = "nsslapd-suffix"; + my $suffix = $ldbmDatabase->{$suffixArg}[0]; + $oldBackends{$suffix} = $CN; +} + + +############################################################################# +# # +# # +# # +############################################################################# +sub migrateLDBM_backend_instances { + foreach $entry (@LDBM_backend_instances) { + my $DN = $entry->getDN(1); # 1 is to normalize the DN + my $CN = $entry->{cn}[0]; + my $expLdif; + my $confirm = "No"; + my $dest = "$serverHome${PATHSEP}db_backup" ; + my $newSlapdExecDir = "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server"; + + if ($DN =~/cn=netscaperoot,cn=ldbm database/i){ + printTrace("\n\n*** INFORMATION - NetscapeRoot is NOT migrated",0); + } + else { + if(alreadyExistsInNew($entry)){ + printMsg("\n\n*** LDBM_BACKEND_INSTANCE - $DN already exists"); + printMsg("\n*** Migration will overwrite existing database"); + printMsg("\nDo you want to continue Yes/No [No] ?") ; + my $answer = <STDIN> ; + if ($answer =~ /y|yes/i) { + printMsg("Do you want to export the existing data Yes/No [Yes] ?"); + my $answer = <STDIN> ; + if (!($answer =~ /n|no/i)) { + mkdir $dest, 0700 unless (-d $dest); + $expLdif = "$dest${PATHSEP}$CN.ldif"; + while (!($confirm =~ /y|yes/i)) { + printMsg("\nEnter the full pathname of the file [$expLdif]:") ; + $answer = <STDIN> ; + chomp($expLdif = $answer) unless ($answer eq "\n"); + printMsg("\nExisting data will be exported under $expLdif"); + printMsg("\nContinue Yes/No [No] ?"); + $confirm = <STDIN>; + } + $ENV{"$LIB_PATH"}=$new_libpath; + chdir($newSlapdExecDir) or die "\nCould not change directory to $newSlapdExecDir: $!\n"; + printTrace("\nNow backing up database $CN in $expLdif\n",0); + &stopServer($root,'slapd-'.$newname); + &db2Ldif($expLdif, $CN, $serverHome); + &startServer() unless (isDirectoryAlive()); + } + push @BACKENDS, $CN; + } else { + printMsg("\n*** Migration will not update it"); + break; + } + } else { + printTrace("\nWe should add the backend instance $DN",3); + my $suffixarg = "nsslapd-suffix" ; + my $suffixname= $entry->{$suffixarg}[0] ; + my $newEntry = $conn->newEntry() ; + $newEntry->setDN($DN); + $newEntry->setValues("objectclass", "top", "extensibleObject", "nsBackendInstance" ); + $newEntry->setValues("cn", $CN ); + $newEntry->setValues($suffixarg, $suffixname); + my @params = keys(%LDBMparamToMigrate); + foreach $param (@params) { + my @values = $entry->getValues($param); + $newEntry->setValues($param, @values) if (@values); + } + if (addEntryToNew($newEntry, "LDBM_BACKEND_INSTANCE",1)) { + push @BACKENDS, $CN; + } + } + } + } +} + +sub parseLDBM_backend_instance { + my $entry = shift; + ®isterSuffix_Backend($entry); + push @LDBM_backend_instances, $entry; +} + +############################################################################# +sub migrateMappingTree { + foreach $entry (@Mapping_tree_entries) { + my $DN = $entry->getDN(1); # 1 si to normalize the DN + if ($DN =~/cn=\"o=netscaperoot\",cn=mapping tree,cn=config/i){ + # DO NOTHING + } + else { + if(alreadyExistsInNew($entry)){ + printMsg("\n\n*** MAPPING_TREE - $DN already exists"); + printMsg("\n*** Migration will not add the suffix"); + } + else { + addEntryToNew($entry, "MAPPING_TREE",1); + } + } + } +} + + +sub parseMapping_tree{ + my $entry = shift; + push @Mapping_tree_entries, $entry; +} + +############################################################################# +sub migrateDefaultIndexes { + foreach $index (@default_indexes) { + my $CN = $index->{cn}[0]; + my $newIndex ; + if ((! isAsystemIndex($index)) && (! $deniedIndexes{lc($CN)})) { + if ($newIndex = alreadyExistsInNew($index)) { + if (! isAsystemIndex($newIndex)) { + updateEntry($index, "DEFAULT_INDEX", 1, 2); + } + } + else { + addEntryToNew($index, "DEFAULT_INDEX", 2); + } + } + } +} + + +sub parseDefaultIndex{ + my $index = shift; + push @default_indexes, $index; +} + +############################################################################# + +sub migrateIndexes { + foreach $index (@indexes) { + my $CN = $index->{cn}[0]; + my $newIndex; + if ((! isAsystemIndex($index)) && (! $deniedIndexes{lc($CN)}) && (DN !~ /cn=netscaperoot,cn=index/i)){ + if ($newIndex = alreadyExistsInNew($index)) { + if (! isAsystemIndex($newIndex)) { + updateEntry($index, "INDEX", 1, 2); + } + } + else { + addEntryToNew($index, "INDEX", 2); + } + } + } +} + +sub parseIndex{ + my $index = shift; + push @indexes, $index; +} + +############################################################################# + +sub newLDIFplugin { + my $currentPlugin = shift; + my $DN = $currentPlugin->getDN(1); + my $newPlugin = $conn->newEntry() ; + $newPlugin->setDN($DN); + foreach $Attr (@pluginAttrs) { + my @values = $currentPlugin->getValues($Attr); + $newPlugin->setValues($Attr, @values) if (@values); + } + return $newPlugin; +} + +sub migrateStdPlugin{ + my $plugin = shift; + my $DN = $plugin->getDN(1); + my $pluginEnable = "nsslapd-pluginEnabled"; + my $argNum = 0; + my $argPrefix = "nsslapd-pluginarg"; + my $currentPlugin ; + if ($currentPlugin = alreadyExistsInNew($plugin, 1)) { + $plugin = updatePathInPluginArgs($plugin); + my $pluginEnableValue = $plugin->{$pluginEnable}[0]; + my $cont = 1; + my $pluginHasChanged = 0; + my $newPlugin = &newLDIFplugin($currentPlugin); + if (! $currentPlugin->hasValue($pluginEnable,$pluginEnableValue,1)){ + $newPlugin->setValues($pluginEnable, $pluginEnableValue); + $pluginHasChanged = 1 unless ($pluginHasChanged); + } + while($cont){ + my $arg = $argPrefix . $argNum ; + if ($plugin->exists($arg)) { + my @values = $plugin->getValues($arg); + my $value = $values[0] ; + $newPlugin->setValues($arg, $value) if (@values); + if ($currentPlugin->exists($arg)) { + if (! $currentPlugin->hasValue($arg,$value,1)) { + $pluginHasChanged = 1 unless ($pluginHasChanged); + } + } + else { + $pluginHasChanged = 1 unless ($pluginHasChanged); + } + } + else { + if ($currentPlugin->exists($arg)) { + # Just Warn the user. Do nothing. + printTrace("\nCompared to the old instance, the current new plugin $DN belongs this attribute: $arg",2); + } + else { + $cont = 0 ; + } + } + $argNum++; + } + updateEntry($newPlugin, "STANDARD_PLUGIN", 0, 1) if ($pluginHasChanged); + } +} + +############################################################################# + +sub migrateConfig_Node{ + my $config_node = shift; + my @params = keys(%GeneralSrvParamToMigrate); + my $hasChanged = 0; + my $newConfigNode; + if ($newConfigNode = alreadyExistsInNew($config_node, 1)){ + foreach $param (@params) { + if ($config_node->exists($param)){ + my @valuesToMigrate = $config_node->getValues($param); + if (@valuesToMigrate){ + if ($newConfigNode->exists($param)){ + my @currentValues = $newConfigNode->getValues($param); + if (Diffs(\@valuesToMigrate, \@currentValues)) { + $newConfigNode->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + printTrace("\nParam to update: $param with value @valuesToMigrate",3); + } + } + else { + $newConfigNode->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + printTrace("\nParam to update: $param with value @valuesToMigrate",3); + } + } + } + } + updateEntry($newConfigNode, "CONFIG_NODE", 0, 1) if ($hasChanged); + } +} + +############################################################################# + +sub migrateConfig_LDBM_database{ + my $config_ldbm = shift; + my @params = keys(%GlobalConfigLDBMparamToMigrate); + my $hasChanged = 0; + my $newConfigLdbm ; + if ($newConfigLdbm = alreadyExistsInNew($config_ldbm, 1)) { + foreach $param (@params) { + if ($config_ldbm->exists($param)){ + my @valuesToMigrate = $config_ldbm->getValues($param); + if (@valuesToMigrate){ + if ($newConfigLdbm->exists($param)){ + my @currentValues = $newConfigLdbm->getValues($param); + if (Diffs(\@valuesToMigrate, \@currentValues)) { + $newConfigLdbm->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + } + } + else { + $newConfigLdbm->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + } + } + } + } + updateEntry($newConfigLdbm, "CONFIG_LDBM_DATABASE", 0, 1) if ($hasChanged); + } +} + +############################################################################# + +sub migrateChainingBE_config{ + my $chaining_config = shift; + my $DN = $chaining_config->getDN(1); + my @params = (); + my $hasChanged = 0; + my $newChainingConfig; + if ($DN =~ /^cn=config,cn=chaining database,cn=plugins,cn=config$/i){ + $newChainingConfig = searchEntry("cn=config,cn=chaining database,cn=plugins,cn=config"); + @params = keys(%ChainingConfigParams); + } + if ($DN =~ /^cn=default instance config,cn=chaining database,cn=plugins,cn=config$/i){ + $newChainingConfig = searchEntry("cn=default instance config,cn=chaining database,cn=plugins,cn=config"); + @params = keys(%ChainingDefaultInstanceConfigParams); + } + foreach $param (@params) { + if ($chaining_config->exists($param)){ + my @valuesToMigrate = $chaining_config->getValues($param); + if (@valuesToMigrate){ + printTrace("\nParam: $param values To migrate: @valuesToMigrate",3); + if ($newChainingConfig->exists($param)){ + my @currentValues = $newChainingConfig->getValues($param); + printTrace("\nParam: $param new current values: @currentValues",3); + if (Diffs(\@valuesToMigrate, \@currentValues)) { + $newChainingConfig->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + } + } + else { + $newChainingConfig->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + } + } + } + } + updateEntry($newChainingConfig, "CHAINING_BACKEND_CONFIG", 0, 1) if ($hasChanged); +} + +############################################################################# + +sub registerSuffix_ChainingBE { + my $ldbmDatabase = shift; + my $CN = $ldbmDatabase->{cn}[0]; + my $suffixArg = "nsslapd-suffix"; + my $suffix = $ldbmDatabase->{$suffixArg}[0]; + $oldChainingBackends{$suffix} = $CN; +} + +sub storeMultiplexorBindDN { + my $chaining_instance = shift; + my $DN = $chaining_instance->getDN(1); + if ($chaining_instance->exists("nsMultiplexorBindDN")){ + my $bindDN = $chaining_instance->{nsMultiplexorBindDN}[0]; + my $newBindDN = searchEntry($bindDN); + if (! $newBindDN){ + # the bindDN entry doesn't yet exist in new => it will have to be migrated + $MultiplexorBindDNEntriesToMigrate{$bindDN}="\n" ; + printTrace("\nThe bindDN: $bindDN need to be migrated",3); + } + else { + # do nothing as the entry already exists in new + } + } + +} + +sub importMultiplexorBindDNEntries { + # import all entries present in @MultiplexorBindDNEntriesToMigrate in new + my @MultiplexorBindDNs = keys (%MultiplexorBindDNEntriesToMigrate); + my $ldif_dir = $ldif_rep; + foreach $bindDN (@MultiplexorBindDNs) { + printTrace("\nimportMultiplexorBindDNEntries: bindDN to migrate: $bindDN",3); + # get the backend in which is stored the bind DN entry + my $backendtoExportFrom = getBackendtoExportFrom($bindDN); + printTrace("\nbackendtoExportFrom is: $backendtoExportFrom",3); + # check wether the backend has been imported in new or not + if (! alreadyMigrated($backendtoExportFrom)) { + if ($backendtoExportFrom ne $NULL) { + # if not imported => we need to import the binf DN entry + &startServer() unless (isDirectoryAlive()); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + &ExportAndAddEntry($bindDN, $backendtoExportFrom, $ldif_dir); + } + else { + # do nothing + } + } + } + # remove the empty ldif directory + rmdir($ldif_dir) if (-d $ldif_dir); + # close the LDAP connection to new + $conn->close if ($conn); +} + +sub migrateChainingBE_instance{ + my $chaining_instance = shift; + my $DN = $chaining_instance->getDN(1); + ®isterSuffix_ChainingBE($chaining_instance); + if (alreadyExistsInNew($chaining_instance)) { + # already exists + printMsg("\n\n*** CHAINING_BACKEND_INSTANCE - $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + &migrate_credential($chaining_instance, "nsmultiplexorcredentials"); + addEntryToNew($chaining_instance, "CHAINING_BACKEND_INSTANCE", 1); + storeMultiplexorBindDN($chaining_instance); + } +} + +############################################################################# + +# create a new LDIF representation of a new replica consumer +sub newLDIFreplica { + my $replica = shift; + my $DN = $replica->getDN(1); + my $newReplica = $conn->newEntry() ; + my $MASTER_OR_MULTIMASTER = "3" ; + $newReplica->setDN($DN); + foreach $Attr (@nsds5replicaAttrs) { + my @values = $replica->getValues($Attr); + $newReplica->setValues($Attr, @values) if (@values); + } + my $replicaType = $replica->{nsDS5ReplicaType}[0]; + if ($replicaType eq $MASTER_OR_MULTIMASTER) { + my @nsState = $replica->getValues("nsState"); + $newReplica->setValues("nsState", @nsState); + } + else { + $newReplica->setValues("nsDS5ReplicaId", $replicaIdvalue); + } + return $newReplica; +} + +sub MigrateNSDS5_replica{ + foreach $replica (@new6replicas) { + my $DN = $replica->getDN(1); + my $newReplica; + my @removeAttrs = qw(nsstate nsds5replicaname nsds5replicachangecount); + for (@removeAttrs) { + $replica->remove($_); + } + if (alreadyExistsInNew($replica)) { + # replica already exists + printMsg("\n\n*** NSDS5_REPLICA - $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + $newReplica = &newLDIFreplica($replica); + addEntryToNew($newReplica, "NSDS5_REPLICA", 1); + } + storeReplicaBindDN($replica); + } +} + +sub parseNSDS5_replica{ + my $replica = shift; + push @new6replicas, $replica; +} + +sub storeReplicaBindDN { + my $replica = shift; + my $DN = $replica->getDN(1); + if ($replica->exists("nsDS5ReplicaBindDN")){ + my $bindDN = $replica->{nsDS5ReplicaBindDN}[0]; + my $newBindDN = searchEntry($bindDN); + if (! $newBindDN){ + # the bindDN entry doesn't yet exist in new => it will have to be migrated + $ReplicaBindDNEntriesToMigrate{$bindDN}="\n" ; + printTrace("\nThe bindDN: $bindDN need to be migrated",3); + } + else { + # do nothing as the entry already exists in new + } + } +} + + +sub importReplicaBindDNEntries { + # import all entries present in @ReplicaBindDNEntriesToMigrate in new + my @ReplicaBindDNs = keys (%ReplicaBindDNEntriesToMigrate); + my $ldif_dir = $ldif_rep; + my $replBind_entry = ""; + my @bindDN_elements = ""; + my $bindDN_parent = ""; + my $parentBind_entry = ""; + foreach $bindDN (@ReplicaBindDNs) { + printTrace("\nimportReplicaBindDNEntries: bindDN to migrate: $bindDN",3); + # get the backend in which is stored the bind DN entry + my $backendtoExportFrom = getBackendtoExportFrom($bindDN); + printTrace("\nbackendtoExportFrom is: $backendtoExportFrom",3); + # If backend is from config, read the entry from dse.ldif and add to new - NGK + if ($backendtoExportFrom eq "cn=config") { + my $norm_bindDN = normalizeDN($bindDN); + @bindDN_elements = ldap_explode_dn($norm_bindDN, 0); +# @bindDN_elements = split(/,/,$norm_bindDN); + my $junk = shift(@bindDN_elements); + if ($#bindDN_elements >= 1) { + $bindDN_parent = normalizeDN(join(",", @bindDN_elements)); + } + printTrace("\nOpening DSE.ldif",3); + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF); + while ($entry = readOneEntry $in) { + my $DN = $entry->getDN(1); + if ($DN eq $norm_bindDN) { + $replBind_entry = $entry; + } + if ($bindDN_parent ne "") { + if ($DN eq $bindDN_parent) { + $parentBind_entry = $entry; + } + } + } + close(DSELDIF); + &startServer() unless (isDirectoryAlive()); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + if ($bindDN_parent ne "") { + addEntryToNew($parentBind_entry, BINDDN_PARENT, 0); + } + printTrace("\nAdding BindDN with addEntryToNew",3); + addEntryToNew($replBind_entry, BINDDN, 0); + } else { + # check wether the backend has been imported in new or not + if (! alreadyMigrated($backendtoExportFrom)) { + if ($backendtoExportFrom ne $NULL) { + # if not imported => we need to import the bind DN entry + &startServer() unless (isDirectoryAlive()); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + &ExportAndAddEntry($bindDN, $backendtoExportFrom, $ldif_dir); + } + else { + # do nothing + } + } + } + } + # remove the empty ldif directory + rmdir($ldif_dir) if (-d $ldif_dir); + # close the LDAP connection to new + $conn->close if ($conn); +} + +sub alreadyMigrated { + my $backendToCheck = shift; + foreach $backend (@BACKENDS) { + return 1 if ($backend eq $backendToCheck); + } + return 0 ; +} + +sub belongsSuffix { + my $suffix = shift; + my $bindDN = shift; + return ($bindDN =~ /$suffix\s*$/i); +} + +sub length { + my $suffix = shift; + my $count = 0; + while ($suffix =~ /./g) { + $count++; + } + return $count ; +} + +sub getBackendtoExportFrom { + my $bindDN = shift ; + my $sizeOfSuffix = 0 ; + my $NULL = ""; + my @oldSuffixes = keys(%oldBackends); + my @oldChainingSuffixes = keys(%oldChainingBackends); + my $bindDN_backend = $NULL; + my $config = "cn=config"; + + my $norm_bindDN = normalizeDN($bindDN); + # Check if bindDN exists in cn=config - NGK + if (belongsSuffix($config,$norm_bindDN)) { + $bindDN_backend = $config; + printTrace("\ngetBackendtoExportFrom: bindDN_backend: $bindDN_backend",3); + } else { + foreach $suffix (@oldSuffixes){ + printTrace("\ngetBackendtoExportFrom: suffix to compare with is: $suffix",3); + if ((belongsSuffix($suffix,$norm_bindDN)) && (length($suffix) > $sizeOfSuffix)) { + $sizeOfSuffix = length($suffix); + $bindDN_backend = $oldBackends{$suffix}; + printTrace("\ngetBackendtoExportFrom: bindDN_backend: $bindDN_backend, sizeOfSuffix: $sizeOfSuffix",3); + } + } + foreach $suffix (@oldChainingSuffixes){ + printTrace("\ngetBackendtoExportFrom: suffix to compare with is a chained suffix: $suffix",3); + if ((belongsSuffix($suffix,$norm_bindDN)) && (length($suffix) > $sizeOfSuffix)) { + printMsg("\n\n*** Entry stored on a remote backend - $norm_bindDN"); + printMsg("\n*** We don't migrate it"); + return $NULL; + } + } + } + return $bindDN_backend; +} + + +sub getBackendtoImportTo { + my $bindDN = shift; + my $sizeOfSuffix = 0; + my $NULL = ""; + my $suffixArg = "nsslapd-suffix"; + my $bindDN_backend = $NULL; + open( DSELDIF, "< $DSEldif" ) || die "Can't open $DSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + $typeOfEntry = getTypeOfEntry($entry); + if ($typeOfEntry eq "LDBM_BACKEND_INSTANCE"){ + my $suffix = $entry->{$suffixArg}[0]; + if ((belongsSuffix($suffix,$bindDN)) && (length($suffix) > $sizeOfSuffix)) { + $sizeOfSuffix = length($suffix); + $bindDN_backend = $entry->{cn}[0]; + } + } + } + close(DSELDIF); + return $bindDN_backend ; +} + + +sub ExportAndAddEntry { + my $DN = shift; + my $backendtoExportFrom = shift; + my $ldif_dir = shift; + my $ldif = "$ldif_dir${PATHSEP}$backendtoExportFrom.ldif" ; + # first: export entry pointed out by the $DN to $ldif file + $ENV{"$LIB_PATH"}=$old_libpath; + if (! $ldif_dir) { $ldif_dir = $ldif_rep ;} + if (!(-d $ldif_dir)) { + mkdir($ldif_dir,0777) or die "\ncan't create $ldif_dir to store temporary ldif files\n"; + } + chdir($oldSlapdExecDir) or die "\nCould not change directory to $oldSlapdExecDir: $!\n"; + &db2Ldif($ldif, $backendtoExportFrom, $oldHome, $DN); + chdir($curdir) or die "\nCould not change directory to $curdir: $!\n"; + + # then: Add it to new + if (! $conn) { + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + } + open( BINDDNLDIF, "< $ldif" ) || die "\nCan't open $ldif: $!: \n"; + my $in = new Mozilla::LDAP::LDIF(*BINDDNLDIF) ; + while ($entry = readOneEntry $in) { + my $entryDN = $entry->getDN(1); + if ($DN eq $entryDN) { + addEntryToNew($entry, "nsds5ReplicaBindDN", 0); + } + } + close(BINDDNLDIF); + # remove the ldif file after the import + unlink($ldif) ; +} + +############################################################################# +sub MigrateNSDS_replication_agreement { + foreach $replicationAgreement (@replicationAgreements) { + my $DN = $replicationAgreement->getDN(1); + if (alreadyExistsInNew($replicationAgreement)){ + # replication agreement already exists + printMsg("\n\n*** NSDS_REPLICATION_AGREEMENT - $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + &migrate_credential($replicationAgreement, "nsDS5ReplicaCredentials"); + addEntryToNew($replicationAgreement, "NSDS_REPLICATION_AGREEMENT", 1); + } + } +} + + +sub parseNSDS_replication_agreement{ + my $replicationAgreement = shift; + push @replicationAgreements, $replicationAgreement ; +} + +############################################################################# + +sub migrateChangelog5{ + my $changelog = shift; + my $DN = $changelog->getDN(1); + my $changelogdir = "nsslapd-changelogdir"; + if (alreadyExistsInNew($changelog)){ + # cn=changelog5,cn=config already exists in new + my $newChangelog = searchEntry($DN); + my @newChangelogdir = $newChangelog->getValues($changelogdir); + $changelog->setValues($changelogdir, @newChangelogdir); + updateEntry($changelog, "CHANGELOG5", 0, 1); + } + else { + # cn=changelog5,cn=config need to be created in new. + # the changelogdir value must be setup to <new_root_server>/slapd-instance/changelogdb + $changelog->setValues($changelogdir,"${serverHome}${PATHSEP}changelogdb"); + addEntryToNew($changelog, "CHANGELOG5", 1); + } +} + + +sub migrateChangelog { + my $oldchangelogdir = ""; + my $newchangelogdir = ""; + my $changelogdir = "nsslapd-changelogdir"; + my $CL5DN = "cn=changelog5,cn=config"; + printTrace("\n\n***** Migrate Changelog...",0,1); + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF); + while ($entry = readOneEntry $in) { + $typeOfEntry = getTypeOfEntry($entry); + if ($typeOfEntry eq "CHANGELOG5"){ + $oldchangelogdir = ($entry->getValues($changelogdir))[0]; + } + } + close(DSELDIF); + if ($oldchangelogdir) { + # If using olddatadir to migrate from, the path of the changelogdb + # from the dse.ldif may not match the path where the old server + # root was archived. We may need to modify oldchangelogdir so the + # copy of the changelog files succeeds. + unless(-e $oldchangelogdir) { + if($olddatadir) { + my @cldbpath = split(/\//,$oldchangelogdir); + until($cldbpath[0] =~/^slapd-/) { + shift(@cldbpath); + } + my $tmpcldbpath = join(${PATHSEP}, @cldbpath); + $oldchangelogdir = "$oldDir${PATHSEP}$tmpcldbpath"; + } + # If oldchangelogdir still looks to be wrong, prompt for the + # location instead of just failing on the copydir operation + # and bombing out of the migration. + unless(-e $oldchangelogdir) { + print("\n\nThe old changelog directory \"$oldchangelogdir\" doesn't exist. Please enter the correct path: "); + $oldchangelogdir = <STDIN>; + } + } + &startServer() unless (isDirectoryAlive()); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + my $newChangelog = searchEntry($CL5DN); + $newchangelogdir = ($newChangelog->getValues($changelogdir))[0]; + stopServer($root,'slapd-'.$newname); + printTrace("\ncopying $oldchangelogdir${PATHSEP}* to $newchangelogdir",3); + copyDir("$oldchangelogdir","$newchangelogdir"); + + # We need to modify the DBVERSION file for a new verision of the db + open(DBVERSION,">$newchangelogdir${PATHSEP}DBVERSION") || die "Can't overwrite $newchangelogdir${PATHSEP}DBVERSION: $! "; + print DBVERSION "Changelog5/NSMMReplicationPlugin/3.0"; + close(DBVERSION); + + &startServer() unless (isDirectoryAlive()); + } +} + +############################################################################# + +sub migrateReplication{ + my $replication = shift; + my $DN = $replication->getDN(1); + if (alreadyExistsInNew($replication)){ + # replication agreement already exists + printMsg("\n\n*** $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + addEntryToNew($replication, "REPLICATION", 1); + } +} + +############################################################################# + +sub migrateSecurity{ + my $security = shift; + if ($entry->hasValue("objectClass", "nsEncryptionConfig")) { + my $certfile = "alias/slapd-" . $newname . "-cert8.db"; + my $keyfile = "alias/slapd-" . $newname. "-key3.db"; + $entry->setValues("nsCertfile",$certfile) if ! $entry->hasValue("nsCertfile",$certfile); + $entry->setValues("nsKeyfile",$keyfile) if ! $entry->hasValue("nsKeyfile",$keyfile); + } + if (alreadyExistsInNew($security)){ + # already exists in new + updateEntry($security, "SECURITY", 0, 1); + } + else { + addEntryToNew($security, "SECURITY", 1); + } +} + +############################################################################# + +sub migrateSNMP{ + my $snmp = shift; + if (alreadyExistsInNew($snmp)){ + # already exists in new + updateEntry($snmp, "SNMP", 0, 1); + } + else { + addEntryToNew($snmp, "SNMP", 1); + } +} + +############################################################################# +# printMsg print message to the user standard output. + +sub printMsg { + + my $TypeMsg = shift ; + my $Msg = shift ; + my $LineNb = shift ; + if ($LineNb) { + printTrace("Line: $LineNb, $TypeMsg, $Msg"); + } + else { + printTrace("$TypeMsg $Msg"); + } +} + +############################################################################# +# print message error to the user standard output. + +sub printTrace { + + my $Msg = shift ; + my $level = shift ; + my $sep = shift ; + + if ($sep) { + print "\n-------------------------------------------------------------------------"; + print LOGFILE "\n-------------------------------------------------------------------------"; + } + + if ($level <= $TRACELEVEL) { + print($Msg); + print LOGFILE $Msg ; + } +} + +############################################################################# +# this subroutine implements a very stupid version of diff + +sub diff { + my $f1 = shift; + my $f2 = shift; + my $lineToBeginWith = shift; + my $NULL = "" ; + my $diff_f1 = $NULL ; + my $diff_f2 = $NULL ; + my $retval = $NULL ; + my $ret; + open(F1, "$f1") or die "Could not open file $f1"; + open(F2, "$f2") or close(F1), die "Could not open file $f2"; + + while (defined($l1 = <F1>)) { + if ($lineToBeginWith){ + $lineToBeginWith -- ; + next ; + } + next if ($l1 =~ /^\#/); + $ret = defined($l2 = <F2>); + if ($ret) { + $ret = defined($l2 = <F2>) while ($ret && ($l2 =~ /^\#/)) ; + if ($ret) { + if (!($l1 eq $l2)) { + + # ignore whitespace + $l1_clean = $l1 ; + $l2_clean = $l2 ; + $l1_clean =~ s/\s//g; + $l2_clean =~ s/\s//g; + + if (!($l1_clean eq $l2_clean)) { + $diff_f1 .= "${l1}" unless ($l1_clean eq $NULL); + $diff_f2 .= "${l2}" unless ($l2_clean eq $NULL); + } + } + } + else { + next if ($l1 =~ /^\s*$/) ; + $diff_f1 .= "${l1}"; + } + } + else { + next if ($l1 =~ /^\s*$/) ; + $diff_f1 .= "${l1}"; + } + } + + while (defined($l2 = <F2>)) { + if (($l2 =~ /^\#/) || ($l2 =~ /^\s*$/)) { + next ; + } + else { + $diff_f2 .= "${l2}" ; + } + } + + close(F1); + close(F2); + + $retval .= "- differences present in your config file but not in standard file:\n\n". "$diff_f1\n" if ($diff_f1) ; + $retval .= "- differences present in standard file but not in your config file:\n\n" . "$diff_f2" if ($diff_f2) ; + return $retval ; +} + +sub CompareStdConfigFiles { + # Compare each configuration file against its default version. If it has changed, + # notify the user that the file has changed and will need to be checked by the + # user. This should be safe to do because there should be no path information + # stored in these conf files, which are just schema stuff. + # printTrace("\nCheck if standard configuration files have changed",3); + + # get the version of the DS to migrate + ($oldVersion, $oldMinor) = &getVersion($oldDir, $oldversionstr); + # get the version of the new DS + ($Version, $Minor) = &getVersion($root); + + # get old LIB_PATH + $old_libpath = &getLibPath($oldDir, $oldVersion, $oldMinor); + # get new LIB_PATH + $new_libpath = &getLibPath($root, $Version, $Minor); + + my $origFilePath = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}install${PATHSEP}schema${PATHSEP}" ; + my $FilesChanged = ""; + my $AllDiffs = "***********************************************************************"; + my $NoChanges = "" ; + my $lineToBegin = 0 ; + opendir(CONFDIR, $oldSchemaDir) or + die "Error: could not open migrated config dir $oldConfDir: $!"; + + foreach $file (readdir(CONFDIR)) { + $origFile = $origFilePath . $file ; + $configFile = $oldSchemaDir . $file ; + if (( exists($stdIncludes{lc($file)})) && (-f $origFile)) { + $diffs = &diff($configFile, $origFile, $lineToBegin); + $lineToBegin = 0 if $lineToBegin ; + if ($diffs) { + $FilesChanged .= "\n$configFile"; + $AllDiffs .= "\n$configFile is different than the standard configuration file" ; + $AllDiffs .= "\nYou will need to check this file and make sure its changes are compatible "; + $AllDiffs .= "with the new directory server\nHere are the differences:\n"; + $AllDiffs .= "$diffs \n\n"; + $AllDiffs .= "***********************************************************************"; + } + else { + $NoChanges .= "\n$configFile"; + } + } + } + closedir(CONFDIR); + +if ($FilesChanged) { + printTrace("\nNo changes to old configuration files:$NoChanges",3) ; + printTrace("\n***********************************************************************",3) ; + printMsg("\nThe following standard files have been modified: $FilesChanged"); + if ($NO_INPUT_USER) { + # do nothing + } + else { + printMsg("\nDo you want to see the differences Yes/No [No] ?") ; + my $answer = <STDIN> ; + if ($answer =~ /y|yes/i) { + printMsg("$AllDiffs"); + } + printMsg("\nDo you want to continue the migration Yes/No [No] ?"); + $answer = <STDIN> ; + if (! ($answer =~ /y|yes/i)) { + exit(1); + } + } + } +} + + + +############################################################################# + +# this is used to run the system() call, capture exit and signal codes, +# and die() upon badness; the first argument is a directory to change +# dir to, if any, and the rest are passed to system() +sub mySystem { + my $rc = &mySystemNoDie(@_); + my ($dir, @args) = @_; + if ($rc == 0) { +# success + } elsif ($rc == 0xff00) { + die "Error executing @args: error code $rc: $!"; + } elsif ($rc > 0x80) { + $rc >>= 8; + die "Error executing @args: error code $rc: $!"; + } else { + if ($rc & 0x80) { + $rc &= ~0x80; + } + die "Error executing @args: received signal $rc: $!"; + } + + # usually won't get return value + return $rc; +} + +# This version does not die but just returns the error code +sub mySystemNoDie { + my ($dir, @args) = @_; + if ($dir && ($dir ne "")) { + chdir($dir) or die "Could not change directory to $dir: $!"; + } + my $cmd = $args[0]; + # the system {$cmd} avoids some NT shell quoting problems if the $cmd + # needs to be quoted e.g. contains spaces; the map puts double quotes + # around the arguments on NT which are stripped by the command + # interpreter cmd.exe; but don't quote things which are already quoted + my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @args; + my $rc = 0; + if ($cmd =~ /[.](bat|cmd)$/) { + # we have to pass batch files directly to the NT command interpreter + $cmd = $com_spec; +# print "system $cmd /c \"@fixargs\"\n"; + $rc = 0xffff & system {$cmd} '/c', "\"@fixargs\""; + } else { +# print "system $cmd @fixargs\n"; + $rc = 0xffff & system {$cmd} @fixargs; + } + chdir(${curdir}) or die "Could not change directory to $curdir: $!"; + return $rc; +} + +########################################################################################### +# # +# Export/Import of the backends in @BACKENDS # +# # +########################################################################################### + +sub manydb2Ldif { + my $ldif_dir = shift; + $ENV{"$LIB_PATH"}=$old_libpath; + if (! $ldif_dir) { $ldif_dir = $ldif_rep ;} + if (!(-d $ldif_dir)) { + mkdir($ldif_dir,0777) or die "can't create $ldif_dir to store temporary ldif files"; + } + chdir($oldSlapdExecDir) or die "Could not change directory to $oldSlapdExecDir: $!"; + foreach $backend (@BACKENDS) { + my $ldif = "${ldif_dir}$backend.ldif" ; + &db2Ldif($ldif, $backend, $oldHome); + } + print " Done.\n"; + chdir($curdir) or die "Could not change directory to $curdir: $!"; +} + +sub db2Ldif { + my $ldif = shift ; + my $backend = shift ; + my $home = shift ; + my $include_suffix = shift ; + my $db2ldif_param ; + if ($include_suffix) { + $db2ldif_param = "db2ldif -r -D $home -n $backend -a $ldif -s \"$include_suffix\""; + } + else { + $db2ldif_param = "db2ldif -r -D $home -n $backend -a $ldif"; + } + open(DB2LDIF, "${quote}${quote}$slapdExecName${quote} $db2ldif_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n"; + sleep(1); # allow some data to accumulate in the pipe + my $ii = 0; + while (<DB2LDIF>) { + ++$ii; + if (($ii % 250) == 0) { + printMsg(" Processing...\n"); + } + printMsg($_); + } + close(DB2LDIF); + # set the ownership of the ldif file; should be the same as the 5.x slapd user id + if ((! $isNt) && ($oldlocaluser ne $localuser)) { + if (-f $ldif) { + chown( $newuid, $newgid, $ldif) or printMsg("\nUnable to change the ownership of $ldif to $localuser") ; + } + } +} + +sub manyLdif2db { + my $ldif_dir = shift; + $ENV{"$LIB_PATH"}=$new_libpath; + chdir($slapdExecDir) or die "Could not change directory to $slapdExecDir: $!"; + foreach $backend (@BACKENDS) { + my $ldif = "${ldif_dir}$backend.ldif" ; + &Ldif2db($ldif, $backend); + } + # remove the empty ldif directory + # but not if using the data dir + if (!$olddatadir) { + rmdir($ldif_dir); + } + chdir($curdir) or die "Could not change directory to $curdir: $!"; +} + + +sub Ldif2db { + my $ldif = shift ; + my $backend = shift ; + my $ldif2db_param = "ldif2db -D $serverHome -n $backend -i $ldif"; + open(LDIF2DB, "${quote}${quote}$slapdExecName${quote} $ldif2db_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n"; + sleep(1); # allow some data to accumulate in the pipe + while (<LDIF2DB>) { + printMsg($_); + } + close(LDIF2DB); + # remove the ldif file after the import + # but not if using the data dir + if (!$olddatadir) { + unlink($ldif) ; + } +} + + +########################################################################################### +# # +# Running/Stopping the Server # +# # +########################################################################################### + + + +sub isDirectoryAlive { + die "\n Migration aborted. Make sure your old and new Directory Servers are installed on the same machine \n" if ( $LDAPservername == -1 ); + my $test_conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd); + if ($test_conn) { + $test_conn->close(); + return 1; + } + else { + return 0 ; + } +} + + +sub startServer { + my $instanceDir = ${serverHome} ; + my $errLog = $instanceDir . $PATHSEP . 'logs' . $PATHSEP . 'errors'; + # emulate tail -f + # if the last line we see does not contain "slapd started", try again + my $done = 0; + my $started = 0; + my $code = 0; + my $lastLine = ""; + my $timeout = time + 240; # 4 minutes + $ENV{"$LIB_PATH"}=$new_libpath; + + my $startCmd = $instanceDir . $PATHSEP . 'start' . $script_suffix; + if (! -f $startCmd) { + $startCmd = $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix; + } + $code = &mySystem($instanceDir,$startCmd); + open(IN, $errLog) or die "Could not open error log $errLog: $!"; + my $pos = tell(IN); + while (($done == 0) && (time < $timeout)) { + for (; ($done == 0) && ($_ = <IN>); $pos = tell(IN)) { + $lastLine = $_; + # print; + # the server has already been started and shutdown once . . . + if (/slapd started\./) { + $started++; + if ($started == 2) { + $done = 1; + } + # sometimes the server will fail to come up; in that case, restart it + } elsif (/Initialization Failed/) { + # print "Server failed to start: $_"; + $code = &mySystem($instanceDir, $startCmd); + # sometimes the server will fail to come up; in that case, restart it + } elsif (/exiting\./) { + # print "Server failed to start: $_"; + #$code = &mySystem($startCmd); + $code = &mySystem($instanceDir, $startCmd); + } + } + if ($lastLine =~ /PR_Bind/) { + # server port conflicts with another one, just report and punt + print $lastLine; + print "This server cannot be started until the other server on this\n"; + print "port is shutdown.\n"; + $done = 1; + } + if ($done == 0) { + # rest a bit, then . . . + sleep(2); + # . . . reset the EOF status of the file desc + seek(IN, $pos, 0); + } + } + close(IN); + + sleep(5); + die "\nUnable to start the $Version.$Minor Directory Server\n" unless (isDirectoryAlive()); + + return 0; +} + +sub stopServer { + my $root = shift; + my $name = shift; + $maxStopIterations = 5; + print "\nShutting down server $name . . .\n"; + $ENV{"$LIB_PATH"}=$new_libpath; + $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop' . $script_suffix . $quote; + if (! -f $stopCmd) { + $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop-slapd' . $script_suffix . $quote; + } + + if (! -f $stopCmd) { + # no stop command, probably a 1.X system; for NT, we'll try net stop + # for unix, we'll get the pid and kill it + if ($isNT) { + $stopCmd = 'net stop ' . $name; + } else { + # see if there is a pid file + $pidfile = $root . $PATHSEP . $name . $PATHSEP . 'logs' . + $PATHSEP . 'pid'; + if (open(PIDFILE, $pidfile)) { + chomp($pid = <PIDFILE>); + close(PIDFILE); + while ($maxStopIterations-- && !$exitCode) { + $exitCode = kill(15, $pid); + } + $stopCmd = undef; + } + } + } + + # keep looping until the stop cmd returns an error code, which usually + # means that what ever we want to stop is stopped, or some other error + # occurred e.g. permission, or no such service + $exitCode = &runAndIgnoreOutput($stopCmd); +# print "stopServer: exitCode=$exitCode\n"; + while ($stopCmd && $maxStopIterations-- && $exitCode) { + $exitCode = &runAndIgnoreOutput($stopCmd); +# print "stopServer: exitCode=$exitCode\n"; + } + + if (!$maxStopIterations) { + print "Warning: could not shutdown the server: $!\n"; + } + sleep(10) ; + $exitCode = 0; +} + + +sub runAndIgnoreOutput { + my $cmd = shift; + printMsg("."); + open(RUNCMD, "${quote}$cmd${quote} 2>&1 |") or die "Error: could not run $cmd: $!"; + printMsg("."); + sleep(1); # allow pipe to fill with data + printMsg("."); + while (<RUNCMD>) { +# print; + } + my $code = close(RUNCMD); +# print "runAndIgnore: code=$code status=$?\n"; + return $?; +} + +############################################################################# +# migrate SSL info + +sub MigrateSSL { + my $secPwd = 'bidon' ; + # copy the SSL directory + ©Dir("$oldHome${PATHSEP}ssl","$serverHome${PATHSEP}ssl") if (-d "$oldHome${PATHSEP}ssl"); + # copy the cert db and key files + if ( -d "$oldDir${PATHSEP}alias") { + $aliasDir = "$root${PATHSEP}alias"; + if (! -d $aliasDir) { + mkdir($aliasDir, 0750); + } + &stopServer($root,'slapd-'.$newname); + my $keydb = "$aliasDir${PATHSEP}slapd-$newname-key3.db" ; + my $certdb = "$aliasDir${PATHSEP}slapd-$newname-cert8.db" ; + my $certdb7 = "$aliasDir${PATHSEP}slapd-$newname-cert7.db" ; + my $old_keydb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-key3.db" ; + my $old_certdb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-cert7.db"; + my $keydb_backup = "$aliasDir${PATHSEP}slapd-$newname-key3.db_backup" ; + my $certdb_backup = "$aliasDir${PATHSEP}slapd-$newname-cert7.db_backup" ; + if (-f $old_keydb) { + if (-f $keydb) { + if ($NO_INPUT_USER) { + printMsg("\n$keydb already exists. backup in $keydb_backup ..."); + ©BinFile($keydb,$keydb_backup); + ©BinFile($old_keydb,$keydb); + } + else { + print("\n\n$keydb already exists. Do you want to overwrite it ? [no]: "); + my $answer = <STDIN> ; + if ($answer =~ /^y|yes$/i) { + ©BinFile($old_keydb,$keydb); + } + } + } + else { + ©BinFile($old_keydb,$keydb); + } + } + if (-f $old_certdb) { + $mode = (stat($old_certdb))[2] if $PRESERVE; + if (-f $certdb) { + if ($NO_INPUT_USER) { + printMsg("\n$certdb already exists. backup in $certdb_backup ..."); + ©BinFile($certdb,$certdb_backup); + unlink($certdb) || print "Couldn't delete $certdb : $!\n"; + ©BinFile($old_certdb,$certdb7); + } + else { + print("\n\n$certdb already exists. Do you want to overwrite it ? [no]: "); + my $answer = <STDIN> ; + if ($answer =~ /^y|yes$/i) { + unlink($certdb) || print "Couldn't delete $certdb : $!\n"; + ©BinFile($old_certdb,$certdb7); + } + } + } + else { + ©BinFile($old_certdb,$certdb7); + } + } + # copy the old password file + if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") { + ©BinFile( + "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt", + "$aliasDir${PATHSEP}$type-$newname-pin.txt" + ); + } + &startServer(); + if ($PRESERVE) { + chown($newuid,$newgid,$certdb) || print "Failed to set uid $newuid gid $newgid on $certdb : $!\n"; + chmod($mode,$certdb) || print "Failed to set mode $mode on $certdb : $!\n"; + } + } + +} + +sub DisableSSL { + my $entry = $conn->search("cn=config","base","objectclass=*"); + my $LDAPparam = "nsslapd-security" ; + my $Value = "off" ; + if ($entry->{$LDAPparam}[0] ne $Value) { + printTrace("\nDisable SSL...",1); + $entry->setValues($LDAPparam, $Value); + } + my $res = $conn->update($entry); + if ($res) { + printTrace("\nSSL disabled",2); + } + else { + printMsg("\nCan't disabled SSL. The server may have problems to start"); + } +} + +# enable the migration of client authentication informations +sub MigrateCertmap { + # backup the old certmap.conf and replace it with the new one + my $oldCertmap = "$oldDir${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf"; + my $newCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf" ; + my $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ; + if (-f $oldCertmap) { + if ($NO_INPUT_USER) { + printMsg("\n$newCertmap has been backup in $backupCertmap"); + ©BinFile($newCertmap,$backupCertmap); + ©BinFile($oldCertmap,$newCertmap); + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\n\nWhere do you want to back up the file $newCertmap [$backupCertmap] ?") ; + my $Answer = <STDIN> ; + $backupCertmap = $Answer if ($Answer ne "\n"); + chomp($backupCertmap); + printTrace("\nDest: .$backupCertmap.",4); + if (-e $backupCertmap) { + printMsg("\n\n$backupCertmap already exists. Do you want to overwrite it Yes/No [No] ?") ; + if (<STDIN> =~ /yes|y/i) { + $Ask = 0 ; + } + else { + $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ; + } + } + else { + $Ask = 0 ; + } + } + printTrace("\nBackup file: $newCertmap in $backupCertmap",4); + ©BinFile($newCertmap,$backupCertmap); + ©BinFile($oldCertmap,$newCertmap); + } + } + else { + } +} + +sub hasChangedoldCertmap { + my $certmapfile = shift ; + my @reference = ("certmap default default", + "default:DNComps", + "default:FilterComps e") ; + my $cpt = 0 ; + printTrace("\nhasChangedoldCertmap",3); + open(CERTMAP,"< $certmapfile"); + while (<CERTMAP>) { + if ((! /^\s*#/) && (! /^\s*$/)) { + my $ref = $reference[$cpt] ; + printTrace("\nValue: $_, ref: $ref",4); + if (! /^\s*$ref\s*$/) { + return 1 ; + } + else { + $cpt++ ; + } + } + } + close (CERTMAP); + printTrace("\ncpt: $cpt",4); + if ($cpt < $#reference) { + return 1 ; + } + else { + return 0 ; + } +} + + +########################################################################################### +# # +# Copy directory and files functions # +# # +########################################################################################### + + +sub copyDir { + my $src = shift; + my $dest = shift; + my $exclude = shift; + + opendir( SRC, $src ) or die "Can't open directory $src: $!: "; + my $mode; + my $uid; + my $gid; + mkdir ( $dest , 0755 ) or die "\nCan't create directory $dest. \nPlease check you have enough rights to create it and/or check that your parent directory exists.\n" if !( -e $dest ); + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + local ( @files ) = readdir ( SRC ); + closedir( SRC ); + for ( @files ) { + if ( $_ eq "." || $_ eq ".." ) { + next; + } elsif ( $exclude && /$exclude/ ) { + next; + } elsif( -d "$src${PATHSEP}$_") { + ©Dir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" ); + } else { + ©BinFile ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_"); + } + } +} + +sub copyBinFile { + my $src = shift; + my $dest = shift; + my $buf = ""; + my $bufsize = 8192; + + open( SRC, $src ) || die "Can't open $src: $!\n"; + # if we are given a directory destination instead of a file, extract the + # filename portion of the source to use as the destination filename + if (-d $dest) { + $dest = $dest . $PATHSEP . &basename($src); + } + open( DEST, ">$dest" ) || die "Can't create $dest: $!\n"; + binmode SRC; + binmode DEST; + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + while (read(SRC, $buf, $bufsize)) { + print DEST $buf; + } + close( SRC ); + close( DEST ); +} + +############################################################################################################# +# backup 5.x configuration files # +# backup the directory <root_server5>/slapd-instance/config dans <root_server5>/slapd-instance/BackupConfig # # +# # +############################################################################################################# + + +sub backupConfigFiles { + # backup the 5.x config files + my $src = "$serverHome${PATHSEP}config" ; + my $dest = "$serverHome${PATHSEP}config_backup" ; + if ($NO_INPUT_USER) { + printMsg("\n$src has been backup in $dest"); + ©Dir($src,$dest); + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\n\nWhere do you want to back up your configuration directory [$dest] ?") ; + my $Answer = <STDIN> ; + $dest = $Answer if ($Answer ne "\n"); + chomp($dest); + printTrace("\nDest: .$dest.",4); + if (-e $dest) { + printMsg("\n\n$dest already exists. Do you want to overwrite it Yes/No [No] ?") ; + if (<STDIN> =~ /yes|y/i) { + $Ask = 0 ; + } + else { + $dest = "$serverHome${PATHSEP}config_backup" ; + } + } + else { + $Ask = 0 ; + } + } + printTrace("\nBackup Directory: $src in $dest",4); + ©Dir($src,$dest); + } +} +############################################################################# + +sub getLDAPservername { + my $oldLDAPservername; + my $LDAPservername; + my $localhost = "nsslapd-localhost"; + open(OLDDSELDIF, "< $oldDSEldif") or die "\nError: could not open old config file $oldDSEldif \n"; + my $in = new Mozilla::LDAP::LDIF(*OLDDSELDIF) ; + while ($entry = readOneEntry $in) { + my $DN = $entry->getDN(1) ; + if ($DN =~ /^cn=config$/i) { + my @values = $entry->getValues($localhost); + if ($entry->size($localhost)) { + $oldLDAPservername = $values[0]; + printTrace("\nName of the old LDAP server: $oldLDAPservername",3); + } + break; + } + } + close(OLDSELDIF); + + open( DSELDIF, "< $DSEldif" ) || die "\nCan't open $DSEldif \n"; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + my $DN = $entry->getDN(1) ; + if ($DN =~ /^cn=config$/i) { + my @values = $entry->getValues($localhost); + if ($entry->size($localhost)) { + $LDAPservername = $values[0]; + printTrace("\nName of the new LDAP server: $LDAPservername",3); + } + break; + } + } + close(DSELDIF); + # check ol and new Directory Instance are installed on the same physical machine. + if (lc($oldLDAPservername) ne lc($LDAPservername)) { + # warn the user he tries to migrate a 4.x server installed on a different machine from the 5.x one + printMsg("\n\nYour old instance is on $oldLDAPservername, whereas your new instance is on $LDAPservername. Migration on different machines is not supported. Do you want to continue ? Yes/No [No]:") ; + if (! (<STDIN> =~ /yes|y/i)) { + return -1; + } + } + return $LDAPservername ; +} + +############################################################################# + +sub getLibPath { + my $myDir = shift; + my $myVersion = shift; + my $myMinor = shift; + + if ($isNT) { + return $ENV{"$LIB_PATH"}; + } + if (($myVersion >= 6) && ($myMinor >= 2)) { + return + "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}". + "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}". + $ENV{"$LIB_PATH"}; + } else { + return "$myDir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + } +} + +############################################################################# + +sub getVersion { + my $dir = shift; + my $versionstr = shift; + my $version = 0; + my $minor = 0; + my $buildNumber = 0; + my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}"; + + # find the slapd executable + if (!$versionstr) { # version not specified on cmd line - find it + $prog = $dir . $progDir . $slapdExecName; + if (! -f $prog) { + $prog = $dir . $progDir2 . $slapdExecName; + if (-f $prog && $isNT) { + # if slapd is in bin/slapd and we're on NT, just assume version 1; + # apparently, slapd.exe doesn't like the -v argument . . . + return ( '1', $minor ); + } + else{ + die "Could not run slapd program $prog: $!"; + } + } + else { + chdir($dir . $progDir); + } + $cur_libpath=$ENV{"$LIB_PATH"}; + $ENV{"$LIB_PATH"}= + "$dir${PATHSEP}lib${SEP}". + "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}". + "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}". + $ENV{"$LIB_PATH"}; + # read the old version from the old slapd program + + open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or + die "Could not run slapd program $prog: $!"; + sleep(1); # allow some data to accumulate in the pipe +# print "Output from $prog -v:\n"; + while (<F>) { + if (/^Netscape-Directory/ || /^iPlanet-Directory/i) { + $versionstr = $_; + last; + } + } + $code = close(F); + # print "$prog returned code=$code status=$?\n"; + $ENV{"$LIB_PATH"}=$cur_libpath; + } + + if ($versionstr =~ /^Netscape-Directory\/(\d+)\.(\d+)(?:b\d)*\s+(\S+)/) { + $version = $1; + $minor = $2; + $buildNumber = $3; + } + elsif ($versionstr =~ /^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ... + $version = $1; + $minor = $2; + $buildNumber = $3; + } + elsif ($versionstr =~ /^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) { + $version = $1; + $minor = $2; + $buildNumber = $3; + } elsif ($versionstr =~ /(\d+)\.(\d+)/) { + $version = $1; + $minor = $2; + } + + if ($version == 0) { + die "\nCould not determine version of the directory server in $dir: \n"; + } + + # distinguish the 4.1 and the 4.11 thanks to the buildNumber + if (($version == 4) && ($minor == 1)){ + if (! ($buildNumber =~ /^B99\.16/)) { + # it's not a 4.1 Netscape Directory Server => it's a 4.11 + $minor = 11 ; + } + } + chdir($curdir) or die "Could not change directory to $curdir: $!" ; + return ( $version, $minor ); +} + +############################################################################################### +sub normalizeDir { + my $dir = shift ; + my $dir_prec = "" ; + while ($dir_prec ne $dir) { + $dir_prec = $dir ; + if ($isNT) { + grep { s@\\\\@\\@g } $dir ; + } + else { + grep { s@//@/@g } $dir ; + } + } + return $dir ; +} + + +############################################################################################### + +sub GetTime { + my $tm = localtime; + (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900); + $sec = "0$sec" unless $sec > 9 ; + $min = "0$min" unless $min > 9 ; + $hour = "0$hour" unless $hour > 9 ; + $dd = "0$dd" unless $dd > 9 ; + $mm = "0$mm" unless $mm > 9 ; + return ($sec, $min, $hour, $dd, $mm, $yy); +} + +############################################################################################### +# get uid and group id of the 5.x slapd server. +# The uid is done through the nsslapd-localuser attribute + +sub getuid_gid { + my $newuid ; + my $newgid ; + my $localuser ; + my $localuser_attr = "nsslapd-localuser" ; + if (! $isNT) { + &startServer() unless (isDirectoryAlive()); + my $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n"; + my $entry = $conn->search("cn=config ", "base","objectclass=*", 0, ($localuser_attr)) ; + # Tests wether we succeed to get the entry cn=config + die "\nCan't get the entry cn=config \n" unless ($entry); + my @values = $entry->getValues($localuser_attr); + $conn->close(); + if ($#values == -1 || ($values[0] eq "") ) { # tests wether the nsslapd-localuser attribute has a value + printMsg("\nNo localuser has been found in the configuration of the directory. "); + if ($NO_INPUT_USER) { + printMsg("\nWe considered nobody as the localuser"); + $localuser = "nobody" ; + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\nUnder what user does your $Version.$Minor directory server run [nobody] ? ") ; + $localuser = <STDIN> ; + chomp($localuser); + $localuser = "nobody" if ($localuser eq ""); + ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ; + if ($newuid) { + $Ask = 0 ; + } + else { + printMsg("\nError: $localuser is unknown from the system "); + } + } + } + } + else { + $localuser = $values[0]; # returns the first value (we should only have one localuser) + my $size = $#values ; + } + ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ; + return ($localuser, $newuid, $newgid) ; + } + else { + return () ; + } +} + +sub getolduid_gid { + my $oldlocaluser ; + my $localuserAttr = "nsslapd-localuser"; + my $entry ; + if (! $isNT) { + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + $typeOfEntry = getTypeOfEntry($entry); + if ($typeOfEntry eq "CONFIG_NODE") { + $oldlocaluser = $entry->{$localuserAttr}[0] if ($entry->exists($localuserAttr)); + break ; + } + } + close(DSE); + ($olduid, $oldgid) = (getpwnam("$oldlocaluser"))[2..3] ; + return ($oldlocaluser, $olduid, $oldgid) ; + } + else { + return (); + } +} +############################################################################################### +# get current directory + +sub getCwd { + my $command = $isNT ? "cd" : "/bin/pwd"; + open(PWDCMD, "$command 2>&1 |") or + die "Error: could not execute $command: $!"; + # without the following sleep, reading from the pipe will + # return nothing; I guess it gives the pwd command time + # to get some data to read . . . + sleep(1); + my $currentdir; + while (<PWDCMD>) { + if (!$currentdir) { + chomp($currentdir = $_); + } + } + my $code = close(PWDCMD); +# if ($code || $?) { +# print "$command returned code=$code status=$? dir=$curdir\n"; +# } +# print "getCwd curdir=\[$curdir\]\n"; + return $currentdir; +} + +################################ +# Need to migrate the credential. +# If the credential can not be migrated, leave it at it is +################################ +sub migrate_credential{ + my $entry_to_modify = shift; + my $credentials_attr = shift; + my @old_value = $entry_to_modify->getValues($credentials_attr); + my $migratecredExecName = 'migratecred'; + my $credOldHome = $oldHome; + my $credServerHome = $serverHome; + + if ($isNT) { + # oldHome may be pointing to the archived copy of the + # instance dir which may be different than the path that + # the instance was originally installed as on Windows. If + # this path is not the original install path, then the + # credential will not be migrated correctly. We should + # prompt the user on Windows for the correct path. + + print "\n\nThe old instance path must be the same as where it was"; + print "\ninitially installed, not where it was archived in order"; + print "\nfor this step to succeed. Please verify that the path"; + print "\nis correct. Note that case sensitivity is important here."; + print "\n\nOld Instance Directory: $credOldHome"; + print "\nIs this correct? (y/n): "; + chomp(my $answer = <STDIN>); + if (!($answer =~ /y|yes/i)) { + print "\nPlease enter the correct path for the old instance directory: "; + chomp($credOldHome = <STDIN>); + } + + print "\n\nThe new instance path must also be correct for this step"; + print "\nto succeed. Please verify that the path is correct. Note"; + print "\nthat case sensitivity is important here."; + print "\n\nNew Instance Directory: $credServerHome"; + print "\nIs this correct? (y/n): "; + chomp(my $answer = <STDIN>); + if (!($answer =~ /y|yes/i)) { + print "\nPlease enter the correct path for the new instance directory: "; + chomp($credServerHome = <STDIN>); + } + } +# print "\nMigratecred command is: ${quote}$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}$migratecredExecName${quote} -o $credOldHome -n $credServerHome -c @old_value\n"; + + my @new_cred = `${quote}$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}$migratecredExecName${quote} -o $credOldHome -n $credServerHome -c @old_value`; + + if ( $? == 0 ) + { + $entry_to_modify->setValues($credentials_attr, @new_cred); + } +} + diff --git a/ldap/admin/src/scripts/template-migrate6to7 b/ldap/admin/src/scripts/template-migrate6to7 new file mode 100644 index 00000000..26f117b6 --- /dev/null +++ b/ldap/admin/src/scripts/template-migrate6to7 @@ -0,0 +1,3049 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# Migrate a 6.x directory server to a 7.0 directory server + +####################################################################################################### +# enable the use of Perldap functions +require DynaLoader; + +use Getopt::Std; +use Mozilla::LDAP::Conn; +use Mozilla::LDAP::Entry; +use Mozilla::LDAP::LDIF; +use Mozilla::LDAP::Utils qw(:all); +use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API +use Time::localtime; +use File::Basename; +use Class::Struct ; + +####################################################################################################### + +sub usage { + print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n"); + print(STDERR " -o oldInstancePath -n newInstancePath [-t tracelevel] [-L logfile]\n"); + print(STDERR "************** parameters in brackets are optionals, others are required **************\n"); + print(STDERR " Opts: -D rootdn - new 7.0 Directory Manager\n"); + print(STDERR " : -w password - new 7.0 Directory Manager's password\n"); + print(STDERR " : -w - - Prompt for new 7.0 Directory Manager's password\n"); + print(STDERR " : -j filename - Read new 7.0 Directory Manager's password from file\n"); + print(STDERR " : -p port - new 7.0 Directory Server port\n"); + print(STDERR " : -o oldInstancePath - Path of the old instance to migrate \n"); + print(STDERR " : -n newInstancePath - Path of the new 7.0 instance\n"); + print(STDERR " : [-d dataPath] - Path to directory containing data files to import into new instance\n"); + print(STDERR " : [-v oldVersion] - Version of old instance (obtained by running $slapdExecName -v\n"); + print(STDERR " : [-t tracelevel] - (optional) specify the level of trace (0..3)\n"); + print(STDERR " : [-L logfile] - (optional) specify the file to log the migration report \n"); + } +######################################################################################################## + +BEGIN { + + require 'uname.lib' ; + $isNT = -d '\\'; + $PATHSEP = $isNT ? "\\" : "/"; + ${SEP} = $isNT ? ";" : ":" ; + @INC = ( '.', '../../../admin/admin/bin'); + grep { s@/@\\@g } @INC if $isNT; + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + # NT needs quotes around some things unix doesn't + $quote = $isNT ? "\"" : ""; + + # If this variable is set, all file/directory creation will make sure the mode + # and ownership of the destination is the same as the source + $PRESERVE = 1 if (!$isNT); + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + if ($isNT) { + $os = "WINNT"; + } else { + $os = &uname("-s"); + } + if ($isNT) { + # we have to pass batch files directly to the NT command interpreter + $com_spec = $ENV{ComSpec}; + if (!$com_spec) { + $com_spec = $ENV{COMSPEC}; + } + if (!$com_spec || ! -f $com_spec) { + # find the first available command interpreter + foreach $drive (c..z) { + $com_spec = "$drive:\\winnt\\system32\\cmd.exe"; + last if (-f $com_spec); + $com_spec = undef; + } + if (! $com_spec) { + # punt and pray + $com_spec = 'c:\winnt\system32\cmd.exe'; + } + } + } + if ( $os eq "AIX" ) { + $dll_suffix = "_shr.a"; + } + elsif ( $os eq "HP-UX" ) { + $dll_suffix = ".sl"; + } + elsif ( $os eq "WINNT" ) { + $dll_suffix = ".dll"; + } + else { + $dll_suffix = ".so"; + } + $slapdExecName = $isNT ? 'slapd.exe' : './ns-slapd'; + select STDERR; + $| = 1; + select STDOUT; + $| = 1; +} + +SWITCH: { + if ($os eq "AIX") { + $LIB_PATH = "LIBPATH" ; + last SWITCH ; + } + if ($os eq "HP-UX") { + $LIB_PATH = "SHLIB_PATH" ; + last SWITCH ; + } + if ($isNT) { + $LIB_PATH = "PATH" ; + last SWITCH ; + } + else { + $LIB_PATH = "LD_LIBRARY_PATH" ; + last SWITCH ; + } + } + + # old parameters + ${oldDir} = "" ; + ${oldname} = "" ; + ${oldHome} = "" ; + ${oldConfDir} = "" ; + ${oldlocaluser} ; + ${olduid} ; + ${oldgid} ; + + # new parameters + ${root} = "{{DS-ROOT}}" ; + ${type} = "" ; + ${newname} = "" ; + ${newport} = "" ; + ${rootDN} = "" ; + ${rootpwd} = "" ; + ${localhost} = "" ; + ${LogFileReport} = "" ; + ${newuid} ; + ${localuser} ; + ${newgid} ; + $NO_INPUT_USER = 0 ; # by default user can give inputs during the migration process + ${curdir} = getCwd(); + ${slapdExecDir} = "${root}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + # in 7.0 the replica Id is setup to a static value + $replicaIdvalue = 65535; + + # specify the level of trace + $TRACELEVEL=1; + + $LDAP_SERVER_UNREACHABLE = 81; + + # get input users + &getParameters() ; + ${oldDir} = &normalizeDir("${oldDir}"); + ${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ; + ${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ; + ${oldSchemaDir} = "${oldConfDir}schema${PATHSEP}"; + ${oldDSEldif} = "${oldConfDir}dse.ldif"; + ${serverHome} = "${root}${PATHSEP}$type-$newname" ; + ${schemaDir} = "$serverHome${PATHSEP}config${PATHSEP}schema${PATHSEP}"; + ${DSEldif} = "$serverHome${PATHSEP}config${PATHSEP}dse.ldif"; + ${ldif_rep} = "${oldConfDir}ldif${PATHSEP}" ; + ${oldSlapdExecDir} = "${oldDir}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + + open(LOGFILE, ">> $LogFileReport"); + + printTrace("\noldDir: $oldDir, oldHome: $oldHome, \noldConfDir: $oldConfDir, \nldif_rep: $ldif_rep, \nrootDN: $rootDN, \nPort: $newport, \nNewname: $newname\n",3); + printTrace("\nLIB_PATH: $LIB_PATH",4); + + if (!(-d $serverHome)) { + printMsg("\n$serverHome doesn't exist\n"); + exit(1); + } + if (!(-d $oldHome)) { + printMsg("\n$oldHome doesn't exist\n"); + exit(1); + } + + if ($olddatadir && !(-d $olddatadir)) { + print("\n$olddatadir doesn't exist\n"); + exit(1); + } + + +%HashParametersName = (); + +# The following hash displays only general server parameters to migrate under cn=config +%GeneralSrvParamToMigrate = ( + 'nsslapd-accesscontrol'=> '\n', + 'nsslapd-errorlog-logging-enabled'=> '\n', + 'nsslapd-accesslog-logging-enabled'=> '\n', + 'nsslapd-auditlog-logging-enabled'=> '\n', + 'nsslapd-accesslog-level'=> '\n', + 'nsslapd-accesslog-logbuffering'=> '\n', + 'nsslapd-accesslog-logexpirationtime'=> '\n', + 'nsslapd-accesslog-logexpirationtimeunit'=> '\n', + 'nsslapd-accesslog-logmaxdiskspace'=> '\n', + 'nsslapd-accesslog-logminfreediskspace'=> '\n', + 'nsslapd-accesslog-logrotationtime'=> '\n', + 'nsslapd-accesslog-logrotationtimeunit'=> '\n', + 'nsslapd-accesslog-maxlogsize'=> '\n', + 'nsslapd-accesslog-maxLogsPerDir'=> '\n', + 'nsslapd-attribute-name-exceptions'=> '\n', + 'nsslapd-auditlog-logexpirationtime'=> '\n', + 'nsslapd-auditlog-logexpirationtimeunit'=> '\n', + 'nsslapd-auditlog-logmaxdiskspace'=> '\n', + 'nsslapd-auditlog-logminfreediskspace'=> '\n', + 'nsslapd-auditlog-logrotationtime'=> '\n', + 'nsslapd-auditlog-logrotationtimeunit'=> '\n', + 'nsslapd-auditlog-maxlogsize'=> '\n', + 'nsslapd-auditlog-maxLogsPerDir'=> '\n', + 'nsslapd-certmap-basedn'=> '\n', + 'nsslapd-ds4-compatible-schema'=> '\n', + 'nsslapd-enquote-sup-oc'=> '\n', + 'nsslapd-errorlog-level'=> '\n', + 'nsslapd-errorlog-logexpirationtime'=> '\n', + 'nsslapd-errorlog-logexpirationtimeunit'=> '\n', + 'nsslapd-errorlog-logmaxdiskspace'=> '\n', + 'nsslapd-errorlog-logminfreediskspace'=> '\n', + 'nsslapd-errorlog-logrotationtime'=> '\n', + 'nsslapd-errorlog-logrotationtimeunit'=> '\n', + 'nsslapd-errorlog-maxlogsize'=> '\n', + 'nsslapd-errorlog-maxlogsperdir'=> '\n', + 'nsslapd-groupevalnestlevel'=> '\n', + 'nsslapd-idletimeout'=> '\n', + 'nsslapd-ioblocktimeout'=> '\n', + 'nsslapd-lastmod'=> '\n', + 'nsslapd-listenhost'=> '\n', + 'nsslapd-maxdescriptors'=> '\n', + 'nsslapd-nagle'=> '\n', + 'nsslapd-readonly'=> '\n', + 'nsslapd-referralmode'=> '\n', + 'nsslapd-plugin-depends-on-name'=> '\n', + 'nsslapd-plugin-depends-on-type'=> '\n', + 'nsslapd-referral'=> '\n', + 'nsslapd-reservedescriptors'=> '\n', + 'nsslapd-rootpwstoragescheme'=> '\n', + 'nsslapd-schemacheck'=> '\n', + 'nsslapd-secureport'=> '\n', + 'nsslapd-security'=> '\n', + 'nsslapd-sizelimit'=> '\n', + 'nsslapd-ssl3ciphers'=> '\n', + 'nsslapd-timelimit'=> '\n', + 'passwordchange'=> '\n', + 'passwordchecksyntax'=> '\n', + 'passwordexp'=> '\n', + 'passwordhistory'=> '\n', + 'passwordinhistory'=> '\n', + 'passwordlockout'=> '\n', + 'passwordlockoutduration'=> '\n', + 'passwordmaxage'=> '\n', + 'passwordmaxfailure'=> '\n', + 'passwordminage'=> '\n', + 'passwordminlength'=> '\n', + 'passwordmustchange'=> '\n', + 'passwordresetfailurecount' => '\n', + 'passwordstoragescheme' => '\n', + 'passwordunlock' => '\n', + 'passwordwarning' => '\n' +); + +# the following hash displays global parameters related to database stored under cn=config,cn=ldbm database,cn=plugins,cn=config +%GlobalConfigLDBMparamToMigrate = ( + 'nsslapd-allidsthreshold' => '\n', + 'nsslapd-lookthroughlimit' => '\n', + 'nsslapd-mode' => '\n', + 'nsslapd-dbcachesize' => '\n', + 'nsslapd-cache-autosize' => '\n', + 'nsslapd-cache-autosize-split' => '\n', + 'nsslapd-db-transaction-logging' => '\n', + 'nsslapd-import-cachesize' => '\n' +); + +# the following hash displays specific parameters to each backends and stored under cn=DBname,cn=ldbm database,cn=plugins,cn=config +%LDBMparamToMigrate = ( + 'nsslapd-cachesize' => '\n', + 'nsslapd-cachememsize' => '\n', + 'nsslapd-readonly' => '\n', + 'nsslapd-require-index' => '\n' +); + + +%ChainingConfigParams = ( + 'nsactivechainingcomponents' => '\n', + 'nstransmittedcontrols' => '\n' + ); + +%ChainingDefaultInstanceConfigParams = ( + 'nsabandonedsearchcheckinterval' => '\n', + 'nsbindconnectionslimit' => '\n', + 'nsbindtimeout' => '\n', + 'nsbindretrylimit' => '\n', + 'nshoplimit' => '\n', + 'nsmaxresponsedelay' => '\n', + 'nsmaxtestresponsedelay' => '\n', + 'nschecklocalaci' => '\n', + 'nsconcurrentbindlimit' => '\n', + 'nsconcurrentoperationslimit' => '\n', + 'nsconnectionlife' => '\n', + 'nsoperationconnectionslimit' => '\n', + 'nsproxiedauthorization' => '\n', + 'nsreferralonscopedsearch' => '\n', + 'nsslapd-sizelimit' => '\n', + 'nsslapd-timelimit' => '\n' +); + +%changelog5params = ( + 'nsslapd-changelogmaxage' => '\n', + 'nsslapd-changelogmaxentries' => '\n' + ); + +@SNMPparams = ( + 'nssnmpenabled', + 'nssnmporganization', + 'nssnmplocation', + 'nssnmpcontact', + 'nssnmpdescription', + 'nssnmpmasterhost', + 'nssnmpmasterport', + 'nssnmpenabled', + 'aci' + ); + +%stdIncludes = ( + "." => "\n", + ".." => "\n", + "30ns-common.ldif " => "\n", + "50ns-mail.ldif " => "\n", + "50ns-news.ldif" => "\n", + "50iplanet-servicemgt.ldif"=> "\n", + "50netscape-servicemgt.ldif"=> "\n", + "50ns-mcd-browser.ldif" => "\n", + "50ns-proxy.ldif" => "\n", + "00core.ldif" => "\n", + "50ns-admin.ldif" => "\n", + "50ns-mcd-config.ldif " => "\n", + "50ns-value.ldif" => "\n", + "05rfc2247.ldif" => "\n", + "50ns-calendar.ldif" => "\n", + "50ns-mcd-li.ldif" => "\n", + "50ns-wcal.ldif" => "\n", + "05rfc2927.ldif" => "\n", + "50ns-certificate.ldif" => "\n", + "50ns-mcd-mail.ldif" => "\n", + "50ns-web.ldif" => "\n", + "10rfc2307.ldif" => "\n", + "50ns-compass.ldif" => "\n", + "50ns-media.ldif" => "\n", + "20subscriber.ldif" => "\n", + "50ns-delegated-admin.ldif"=> "\n", + "50ns-mlm.ldif" => "\n", + "25java-object.ldif" => "\n", + "50ns-directory.ldif" => "\n", + "50ns-msg.ldif" => "\n", + "28pilot.ldif" => "\n", + "50ns-legacy.ldif" => "\n", + "50ns-netshare.ldif" => "\n" +); + + +# Backends migrated (Backend CN attribute value) +@BACKENDS = () ; +# All pairs of suffix-backend are registered in this hashtable +%oldBackends = () ; + +#store the backend instances to migrate +@LDBM_backend_instances = (); + +#store the mapping tree +@Mapping_tree_entries = (); + +#store the suffix and the associated chaining backend +%oldChainingBackends = (); + +#store the multiplexor bind entries to migrate +%MultiplexorBindDNEntriesToMigrate = (); + +#store the Replica bind DN entries to migrate +%ReplicaBindDNEntriesToMigrate = (); + +# list of standard plugins +%stdPlugins = ( + "7-bit check" => "\n", + "acl plugin" => "\n", + "acl preoperation" => "\n", + "binary syntax" => "\n", + "case exact string syntax" => "\n", + "case ignore string syntax" => "\n", + "chaining database" => "\n", + "class of service" => "\n", + "country string syntax" => "\n", + "distinguished name syntax" => "\n", + "generalized time syntax" => "\n", + "integer syntax" => "\n", + "internationalization plugin" => "\n", + "ldbm database" => "\n", + "legacy replication plugin" => "\n", + "multimaster replication plugin" => "\n", + "octet string syntax" => "\n", + "clear" => "\n", + "crypt" => "\n", + "ns-mta-md5" => "\n", + "sha" => "\n", + "ssha" => "\n", + "postal address syntax" => "\n", + "referential integrity postoperation" => "\n", + "retro changelog plugin" => "\n", + "roles plugin" => "\n", + "telephone syntax" => "\n", + "uid uniqueness" => "\n", + "uri syntax" => "\n" + ); + +# list of indexes that have disappeared from the new schema compared to 6.x +%deniedIndexes = ( + 'dncomp' => "\n" +); + +@default_indexes = (); +@indexes = (); + +# list of user added Plugin's. In 7.0, they 'll need to be recompiled +@badPlugins = () ; + +@pluginAttrs = ( + "objectclass", + "cn", + "nsslapd-pluginpath", + "nsslapd-plugininitfunc", + "nsslapd-plugintype", + "nsslapd-pluginenabled", + "nsslapd-plugin-depends-on-type", + "nsslapd-pluginid", + "nsslapd-pluginversion", + "nsslapd-pluginvendor" + ); + +@nsds5replicaAttrs = ( + 'objectclass', + 'nsDS5ReplicaRoot', + 'nsDS5ReplicaType', + 'nsDS5ReplicaLegacyConsumer', + 'nsDS5flags', + 'nsDS5ReplicaId', + 'nsDS5ReplicaPurgeDelay', + 'nsDS5ReplicaBinddn', + 'cn', + 'nsDS5ReplicaReferral' + ); + +# array of replicas to migrate +@new6replicas = (); + +# array of replication agreements to migrate +@replicationAgreements = (); + +# compare LDIF standard config files with standard ones +CompareStdConfigFiles() ; +die "\n\n The version of product you want to migrate is not a 6.x Directory Server\n" unless ($oldVersion == 6) ; + +# Shutdown the legacy Directory instance +printTrace("\nShutdown the legacy Directory Server instance: ${oldHome}",0); +&stopServer($oldDir, 'slapd-'.$oldname); + +# get the hostname of the new LDAP server +my $LDAPservername = &getLDAPservername(); + +# get the uid and gid of the 7.0 slapd user +($localuser, $newuid, $newgid) = getuid_gid(); +# get the uid and gid of the 6.x slapd user +($oldlocaluser, $olduid, $oldgid) = getolduid_gid(); +printTrace("\n7.0 localuser: $localuser, uid: $newuid, gid: $newgid",2); +printTrace("\n6.x localuser: $oldlocaluser, uid: $olduid, gid: $oldgid",2); + +# backup 7.0 configuration files in <6server_root>/slapd-instancename/config +printTrace("\nBackup $serverHome${PATHSEP}config on $serverHome${PATHSEP}config_backup ...",0); +&backupConfigFiles(); + +# migrate the schema (need to stop and start the 7.0 server) +printTrace("\nMigrate the schema...",0); +MigrateSchema(); + +# start the server unless it is already started +&startServer() unless (isDirectoryAlive()); + +############### Connect to the 7.0 LDAP Directory Server ###################### +$ENV{"$LIB_PATH"} = $new_libpath; + +die "\n Migration aborted. Make sure your old and new Directory Server are installed on the same machine \n" if ( $LDAPservername == -1 ); +$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + +# Cconnection to 7.0 LDAP server is successful ! +printTrace("\nConnected to $Version.$Minor LDAP server",0) ; + +# Parse the main configuration file: dse.ldif +printTrace("\n\nParse the old DSE ldif file: $oldDSEldif *****",0, 1); +printTrace("\nThis may take a while ...\n",0); +&MigrateDSEldif(); + +#migrate LDBM backend instances +printTrace("\n\nMigrate LDBM backend instances...",0,1); +&migrateLDBM_backend_instances(); + +#migrate mapping tree entries +printTrace("\n\nMigrate mapping tree...",0,1); +&migrateMappingTree(); + +#migrate default indexes +printTrace("\n\nMigrate default indexes...",0,1); +migrateDefaultIndexes(); + +#migrate indexes +printTrace("\n\nMigrate indexes...",0,1); +migrateIndexes(); + +#migrate replicas +printTrace("\n\nMigrate replicas...",0,1); +&MigrateNSDS5_replica(); + +#migrate replication agreements +printTrace("\n\nMigrate replication agreements...",0,1); +&MigrateNSDS_replication_agreement(); + +#migrate key/cert databases +printTrace("\n\nMigrate key/cert databases...",0,1); +&MigrateSSL(); + +# migrate certmap.conf +printTrace("\n\nMigrate Certmap.conf...",0,1); +&MigrateCertmap() ; + +################## Close the connection to 7.0 LDAP Server ##################### +printTrace("\n\n***** Close the LDAP connection to the new Directory Server instance ***** ",0); +$conn->close; + + +################## stop the new instance and Export/Import the data, restart the server ################## +if (@BACKENDS) { + &stopServer($root,'slapd-'.$newname); + if ($olddatadir) { + printTrace("\nData already contained in $olddatadir...\n",0,1) ; + $ldif_rep = "$olddatadir${PATHSEP}"; + } else { + printTrace("\nData processing...\n",0,1) ; + # migrate data for each backend: 6.x -> LDIF files + &manydb2Ldif($ldif_rep); + } + + # migrate LDIF data to the new database: LDIF -> New + &manyLdif2db($ldif_rep); + &migrateChangelog(); + printTrace("\n***** Migrate ReplicaBindDN entries...\n",0,1); + &importReplicaBindDNEntries(); + printTrace("\n***** Migrate MultiplexorBindDN entries...\n",0,1); + &importMultiplexorBindDNEntries(); + &startServer() unless (isDirectoryAlive()); +} +else { + printTrace("\nINFORMATION - There are no non-standard or non-already existing suffixes to migrate\n",0); + &migrateChangelog(); + printTrace("\n***** Migrate ReplicaBindDN entries...\n",0,1); + &importReplicaBindDNEntries(); + printTrace("\n***** Migrate MultiplexorBindDN entries...\n",0,1); + &importMultiplexorBindDNEntries(); +} + +printMsg("\n\n ****** End of migration ******\n\n"); + +close(LOGFILE); + + +########################################################################################### +# get input users +sub getParameters { + my $exit = 0 ; + my $i = 0; + my $pwdfile= ""; + + while ($i <= $#ARGV) { + if ( "$ARGV[$i]" eq "-D" ) { # directory manager + if (! $rootDN) { + $rootDN = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-w") { # password + if (! $rootpwd) { + $rootpwd = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-j") { # password file + if (! $pwdfile) { + $pwdfile = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-o") { # old instance path + if (! $oldHome ) { + $oldHome = $ARGV[++$i] ; + grep { s@\\@/@g } $oldHome if $isNT ; + if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; } + if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) { + $oldDir = $1 ; + $type = $2 ; + $oldname = $3 ; + if ($isNT) { + $oldDir = lc($oldDir) ; + $type = lc($type) ; + $oldname = lc($oldname) ; + $oldHome = lc($oldHome) ; + grep { s@/@\\@g } $oldDir ; + grep { s@/@\\@g } $oldHome ; + } + } + else { + print("\nThe old instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-n") { # new instance path + if (! $serverHome ) { + $serverHome = $ARGV[++$i] ; + grep { s@\\@/@g } $root if $isNT ; + grep { s@\\@/@g } $serverHome if $isNT ; + if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; } + if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) { + $root = $1 if ($1); + $type = $2 ; + $newname = $3 ; + if ($isNT) { + $root = lc($root) ; + $type = lc($type) ; + $newname = lc($newname) ; + $serverHome = lc($serverHome) ; + grep { s@/@\\@g } $root ; + grep { s@/@\\@g } $serverHome ; + } + } + else { + print("\nThe new instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-p") { # new DS port + if (! $newport ) { + $newport = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-d") { # old instance LDIF data dir + if (! $olddatadir ) { + $olddatadir = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-v") { # old version + if (! $oldversionstr ) { + $oldversionstr = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL + my $value = $ARGV[++$i] ; + if ($value =~ /[0-3]/) { + $TRACELEVEL = $value ; + } + else { + print("\nThe tracelevel must belong to 0..3 interval"); + &usage(); + exit(); + } + } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing + $NO_INPUT_USER = 1 ; + } elsif ("$ARGV[$i]" eq "-L") { # migration logfile + $LogFileReport = $ARGV[++$i] ; + } + else { + print("\nThe option $ARGV[$i] is not recognized"); + &usage() ; + exit(1); + } + $i++; + } + if (! $rootDN) { + print("\nThe rootDN is missing"); + $exit = 1; + } + if ($pwdfile ne "") { + # Open file and get the password + unless (open (RPASS, $pwfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $rootpwd = <RPASS>; + chomp($rootpwd); + close(RPASS); + } elsif ($rootpwd eq "-"){ + # Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; + # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $rootpwd = ReadLine(0); +# chomp($rootpwd); +# ReadMode('normal'); + } + if (! $rootpwd) { + print("\nThe rootpwd is missing"); + $exit = 1 ; + } + if (! $newport) { + print("\nThe port is missing"); + $exit = 1; + } + if (! $serverHome) { + print("\nThe new instance path is missing"); + $exit = 1; + } + if (! $oldHome) { + print("\nThe old instance path is missing"); + $exit = 1; + } + if ((! $LogFileReport) && $serverHome) { + ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime(); + $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log"; + } + if ($exit) { + &usage() ; + exit(1); + } + +} + +################################################################################################### + +sub MigrateSchema{ + my $FilesChanged = ""; + my $AllDiffs = ""; + my $NoChanges = "" ; + my $lineToBegin = 0 ; + opendir(SCHEMADIR, $oldSchemaDir) or + die "Error: could not open migrated config dir $oldSchemaDir: $!"; + + foreach $file (readdir(SCHEMADIR)) { + if (! exists($stdIncludes{lc($file)})) { + my $newSchemaFile = $schemaDir . $file; + if (-f $newSchemaFile ) { + # The ldif file already exists. Make a diff and warn the user if different. + if (diff($newSchemaFile, $oldSchemaDir.$file)) { + &stopServer($root,'slapd-'.$newname) if (isDirectoryAlive()); + $AllDiffs .= "\n$file"; + copyBinFile("$oldSchemaDir$file", $newSchemaFile); + } + } + else { + &stopServer($root,'slapd-'.$newname) if (isDirectoryAlive()); + $AllDiffs .= "\n$file"; + copyBinFile("$oldSchemaDir$file", $newSchemaFile); + } + } + } + closedir(SCHEMADIR); + if ($AllDiffs) { + printMsg("\n\n***********************************************************************"); + printMsg("\nThe following LDIF files have been migrated:"); + printMsg("$AllDiffs"); + printMsg("\n*************************************************************************\n\n"); + } + &startServer() if (! isDirectoryAlive()); +} + + +################################################################################################### +# This subroutine is used to parse the dse.ldif file and call specific routines to act with entries +sub MigrateDSEldif { + printTrace("\nMigrate DSE entries...",1); + my $tempoAlreadyDone = 0; + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + $typeOfEntry = getTypeOfEntry($entry); + SWITCH: { + if ($typeOfEntry eq "LDBM_BACKEND_INSTANCE"){ + parseLDBM_backend_instance($entry); + last SWITCH; + } + if ($typeOfEntry eq "MAPPING_TREE"){ + parseMapping_tree($entry); + last SWITCH; + } + if ($typeOfEntry eq "DEFAULT_INDEX"){ + parseDefaultIndex($entry); + last SWITCH; + } + if ($typeOfEntry eq "INDEX"){ + parseIndex($entry); + last SWITCH; + } + if ($typeOfEntry eq "STANDARD_PLUGIN"){ + migrateStdPlugin($entry); + last SWITCH; + } + if ($typeOfEntry eq "CONFIG_NODE"){ + migrateConfig_Node($entry); + last SWITCH; + } + if ($typeOfEntry eq "CONFIG_LDBM_DATABASE"){ + migrateConfig_LDBM_database($entry); + last SWITCH; + } + if ($typeOfEntry eq "CHAINING_BACKEND_CONFIG"){ + migrateChainingBE_config($entry); + last SWITCH; + } + if ($typeOfEntry eq "CHAINING_BACKEND_INSTANCE"){ + migrateChainingBE_instance($entry); + last SWITCH; + } + if ($typeOfEntry eq "NSDS5_REPLICA"){ + parseNSDS5_replica($entry); + last SWITCH; + } + if ($typeOfEntry eq "NSDS_REPLICATION_AGREEMENT"){ + parseNSDS_replication_agreement($entry); + last SWITCH; + } + if ($typeOfEntry eq "CHANGELOG5"){ + migrateChangelog5($entry); + last SWITCH; + } + if ($typeOfEntry eq "REPLICATION"){ + migrateReplication($entry); + last SWITCH; + } + if ($typeOfEntry eq "SECURITY"){ + migrateSecurity($entry); + last SWITCH; + } + if ($typeOfEntry eq "SNMP"){ + migrateSNMP($entry); + last SWITCH; + } + } + + } + close(DSELDIF); +} + +############################################################################# +# returns the "type of an entry". If the entry is not to be migrated its type is "NOT_MIGRATED_TYPE" + +sub getTypeOfEntry{ + my $entry = shift; + my $DN = $entry->getDN(1) ; # 1 is to normalize the returned DN + if (($DN =~ /cn=ldbm database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsBackendInstance"))) { + return "LDBM_BACKEND_INSTANCE"; + } + if (($DN =~ /cn=mapping tree,cn=config$/i) && (isObjectclass($entry,"nsMappingTree"))) { + return "MAPPING_TREE"; + } + if (($DN =~ /cn=default indexes,cn=config,cn=ldbm database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsIndex"))) { + return "DEFAULT_INDEX"; + } + if (isObjectclass($entry,"nsIndex")) { + return "INDEX"; + } + if ((isObjectclass($entry,"nsSlapdPlugin")) && (isStdPlugin($entry))) { + return "STANDARD_PLUGIN"; + } + if ($DN =~ /^cn=config$/i) { + return "CONFIG_NODE"; + } + if ($DN =~ /^cn=config,cn=ldbm database,cn=plugins,cn=config$/i) { + return "CONFIG_LDBM_DATABASE"; + } + if (($DN =~ /^cn=config,cn=chaining database,cn=plugins,cn=config$/i) || ($DN =~ /^cn=default instance config,cn=chaining database,cn=plugins,cn=config$/i)){ + return "CHAINING_BACKEND_CONFIG"; + } + if (($DN =~ /cn=chaining database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsBackendInstance"))) { + return "CHAINING_BACKEND_INSTANCE"; + } + if (isObjectclass($entry,"nsDS5Replica")) { + return "NSDS5_REPLICA"; + } + if (isObjectclass($entry,"nsDS5ReplicationAgreement")) { + return "NSDS_REPLICATION_AGREEMENT"; + } + if ($DN =~ /^cn=changelog5,cn=config$/i) { + return "CHANGELOG5"; + } + if (($DN =~ /cn=replication,cn=config$/i) && ($DN !~ /^cn=replication,cn=config$/i)) { + return "REPLICATION"; + } + if ($DN =~ /cn=encryption,cn=config$/i) { + return "SECURITY"; + } + if ($DN =~ /^cn=SNMP,cn=config$/i) { + return "SNMP"; + } + return "NOT_MIGRATED_TYPE"; +} + +############################################################################# + + + +############################################################################# +# returns 1 if the objectclass given in parameter is present in the objectclasses values of the entry +# given in parameter, 0 else + +sub isObjectclass { + my $entry = shift; + my $objectclass = shift; + return ($entry->hasValue("objectclass",$objectclass,1)); +} + +############################################################################# + +sub isStdPlugin { + my $entry = shift; + my $CN = $entry->{cn}[0]; + if (isObjectclass($entry,"nsSlapdPlugin")) { + return 1 if ($stdPlugins{lc($CN)}); + } + return 0; +} + + +############################################################################# + +sub alreadyExistsInNew{ + my $entry = shift; + my $mustExist = shift; + my $DN = $entry->getDN(1); # 1 to normalize the DN + # We have a name change of "uid uniqueness" plugin in DS6.x + # to "attribute uniqueness" + $DN =~ s/uid\ uniqueness/attribute\ uniqueness/ if ($DN =~ /uid\ uniqueness/); + return searchEntry($DN, $mustExist); +} + +############################################################################# +sub searchEntry { + my $DN = shift; + my $mustExist = shift; + my $res = $conn->search($DN, "base", "objectclass=*"); + my $cpt = 5; + if ($res) { + return $res; + } + else { + my $errorCode = $conn->getErrorCode(); + while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) { + printMsg("\ntry to reconnect to search $DN"); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + $res = $conn->search($DN, "base", "objectclass=*"); + $errorCode = $conn->getErrorCode(); + $cpt--; + } + if ($res){ + return $res ; + } + elsif (($errorCode eq $LDAP_SERVER_UNREACHABLE) || ($mustExist)) { + my $msg = $conn->getErrorString(); + printMsg("\n\n*** Failed to search: $DN"); + printMsg("\n*** Error Msg: $msg, Error code: $errorCode"); + } + return 0; + } +} + + +############################################################################# + +sub addEntryToNew{ + my $entry = shift; + my $typeOfEntry = shift; + my $trace = shift; + my $res = $conn->add($entry); + my $DN = $entry->getDN(1); + my $cpt = 5; + if ($res) { + printTrace("\n$typeOfEntry - Add successfull: $DN",$trace); + return 1; + } + else { + my $errorCode = $conn->getErrorCode(); + while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) { + printMsg("\ntry to reconnect to add $DN"); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + $res = $conn->add($entry); + $errorCode = $conn->getErrorCode(); + $cpt--; + } + if ($res){ + printTrace("\n$typeOfEntry - Add successfull: $DN",$trace); + return 1; + } + else { + my $msg = $conn->getErrorString(); + printMsg("\n\n*** $typeOfEntry: Add Failed: $DN"); + printMsg("\n*** Error Msg: $msg, Error code: $errorCode"); + return 0; + } + } +} + +############################################################################# + +sub updateEntry{ + my $entry = shift; + my $typeOfEntry = shift; + my $CHECK = shift; + my $trace = shift; + my $cpt = 5; + if ($CHECK) { + if (! hasChanged($entry, $typeOfEntry)) { + return 1; + } + } + my $res = $conn->update($entry); + my $DN = $entry->getDN(1); + if ($res) { + printTrace("\n$typeOfEntry - Update successfull: $DN",$trace); + return 1 ; + } + else { + my $errorCode = $conn->getErrorCode(); + while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) { + printMsg("\ntry to reconnect to update $DN"); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + $res = $conn->update($entry); + $errorCode = $conn->getErrorCode(); + $cpt--; + } + if ($res){ + printTrace("\n$typeOfEntry - Update successfull: $DN",$trace); + return 1; + } + else { + my $msg = $conn->getErrorString(); + printMsg("\n\n*** $typeOfEntry - Update Failed: $DN"); + printMsg("\n*** Error Msg: $msg, Error code: $errorCode"); + return 0; + } + } +} + + +############################################################################# +# returns 1 if the entry to migrate and the current entry are different one another + +sub hasChanged { + my $entry = shift; + my $typeOfEntry = shift; + my $DN = $entry->getDN(1); + my $newEntry = searchEntry($DN,1); + return 1 if (! $newEntry); # we shoudn't be in that case ... + # do the stuff to check wether the entry has changed or not given its type + if (($typeOfEntry eq "DEFAULT_INDEX") || ($typeOfEntry eq "INDEX")){ + my @indexTypes = $entry->getValues("nsIndexType"); + my @newIndexTypes = $newEntry->getValues("nsIndexType"); + my @nsmatchingrules = $entry->getValues("nsmatchingrule"); + my @newMatchingRules = $newEntry->getValues("nsmatchingrule"); + return 1 if (Diffs(\@indexTypes, \@newIndexTypes)); + return 1 if (Diffs(\@nsmatchingrules,\@newMatchingRules)); + return 0; + } + if ($typeOfEntry eq "CHANGELOG5"){ + printTrace("\nCheck wether changelog has changed or not",3); + my @params = keys(%changelog5params); + foreach $param (@params){ + my @values = $entry->getValues($param); + my @newValues = $newEntry->getValues($param); + return 1 if (Diffs(\@values,\@newValues)); + } + return 0; + } + if ($typeOfEntry eq "SNMP"){ + foreach $param (@SNMPparams){ + my @values = $entry->getValues($param); + my @newValues = $newEntry->getValues($param); + return 1 if (Diffs(\@values,\@newValues)); + } + return 0; + } + # we don't know how to compare such type of entry => just return 1 + return 1 ; +} + +sub isAsystemIndex { + my $index = shift; + return ($index->hasValue("nsSystemIndex","true",1)); +} + + +sub updatePathInPluginArgs { + my $plugin = shift; + my $argNum = 0; + my $argPrefix = "nsslapd-pluginarg"; + my $cont = 1; + my $Unix_oldDir = ${oldDir} ; + my $Unix_root = ${root} ; + grep { s@\\@/@g } $Unix_oldDir if $isNT; + grep { s@\\@/@g } $Unix_root if $isNT; + while ($cont) { + my $arg = $argPrefix . $argNum ; + if ($plugin->exists($arg)) { + $_ = $plugin->{$arg}[0] ; + s@$Unix_oldDir@$Unix_root@ig ; + s/$type-$oldname/$type-$newname/ig ; + $plugin->setValues($arg, $_) ; + } + else { + $cont = 0 ; + } + $argNum++; + } + return $plugin; +} + + +sub Diffs { + my $valuesToMigrate = shift; + my $currentValues = shift; + return 1 if (getDiff(\@{$valuesToMigrate},\@{$currentValues})); + return 1 if (getDiff(\@{$currentValues},\@{$valuesToMigrate})); + return 0 ; +} + +sub getDiff { + # we get references to arrays + my $elements = shift ; + my $existing_elements = shift ; + my %count = () ; + my %countEE = () ; + @diff = () ; + foreach $e (@{$elements}, @{$existing_elements}) { $count{$e}++ ;} + foreach $e (@{existing_elements}) { $countEE{$e}++ ;} + foreach $e (@{$elements}) { + # if $e is only present in @$elements, we push it to the diff array + if (($count{$e} == 1) && ($countEE{$e} == 0)) { + push @diff, $e ; + } + } + return @diff ; +} + +sub registerSuffix_Backend { + my $ldbmDatabase = shift; + my $CN = $ldbmDatabase->{cn}[0]; + my $suffixArg = "nsslapd-suffix"; + my $suffix = $ldbmDatabase->{$suffixArg}[0]; + $oldBackends{$suffix} = $CN; +} + + +############################################################################# +# # +# # +# # +############################################################################# +sub migrateLDBM_backend_instances { + foreach $entry (@LDBM_backend_instances) { + my $DN = $entry->getDN(1); # 1 is to normalize the DN + my $CN = $entry->{cn}[0]; + my $expLdif; + my $confirm = "No"; + my $dest = "$serverHome${PATHSEP}db_backup" ; + my $newSlapdExecDir = "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server"; + + if ($DN =~/cn=netscaperoot,cn=ldbm database/i){ + printTrace("\n\n*** INFORMATION - NetscapeRoot is NOT migrated",0); + } + else { + if(alreadyExistsInNew($entry)){ + printMsg("\n\n*** LDBM_BACKEND_INSTANCE - $DN already exists"); + printMsg("\n*** Migration will overwrite existing database"); + printMsg("\nDo you want to continue Yes/No [No] ?") ; + my $answer = <STDIN> ; + if ($answer =~ /y|yes/i) { + printMsg("Do you want to export the existing data Yes/No [Yes] ?"); + my $answer = <STDIN> ; + if (!($answer =~ /n|no/i)) { + mkdir $dest, 0700 unless (-d $dest); + $expLdif = "$dest${PATHSEP}$CN.ldif"; + while (!($confirm =~ /y|yes/i)) { + printMsg("\nEnter the full pathname of the file [$expLdif]:") ; + $answer = <STDIN> ; + chomp($expLdif = $answer) unless ($answer eq "\n"); + printMsg("\nExisting data will be exported under $expLdif"); + printMsg("\nContinue Yes/No [No] ?"); + $confirm = <STDIN>; + } + $ENV{"$LIB_PATH"}=$new_libpath; + chdir($newSlapdExecDir) or die "\nCould not change directory to $newSlapdExecDir: $!\n"; + printTrace("\nNow backing up database $CN in $expLdif\n",0); + &stopServer($root,'slapd-'.$newname); + &db2Ldif($expLdif, $CN, $serverHome); + &startServer() unless (isDirectoryAlive()); + } + push @BACKENDS, $CN; + } else { + printMsg("\n*** Migration will not update it"); + break; + } + } else { + printTrace("\nWe should add the backend instance $DN",3); + my $suffixarg = "nsslapd-suffix" ; + my $suffixname= $entry->{$suffixarg}[0] ; + my $newEntry = $conn->newEntry() ; + $newEntry->setDN($DN); + $newEntry->setValues("objectclass", "top", "extensibleObject", "nsBackendInstance" ); + $newEntry->setValues("cn", $CN ); + $newEntry->setValues($suffixarg, $suffixname); + my @params = keys(%LDBMparamToMigrate); + foreach $param (@params) { + my @values = $entry->getValues($param); + $newEntry->setValues($param, @values) if (@values); + } + if (addEntryToNew($newEntry, "LDBM_BACKEND_INSTANCE",1)) { + push @BACKENDS, $CN; + } + } + } + } +} + +sub parseLDBM_backend_instance { + my $entry = shift; + ®isterSuffix_Backend($entry); + push @LDBM_backend_instances, $entry; +} + +############################################################################# +sub migrateMappingTree { + foreach $entry (@Mapping_tree_entries) { + my $DN = $entry->getDN(1); # 1 si to normalize the DN + if ($DN =~/cn=\"o=netscaperoot\",cn=mapping tree,cn=config/i){ + # DO NOTHING + } + else { + if(alreadyExistsInNew($entry)){ + printMsg("\n\n*** MAPPING_TREE - $DN already exists"); + printMsg("\n*** Migration will not add the suffix"); + } + else { + addEntryToNew($entry, "MAPPING_TREE",1); + } + } + } +} + + +sub parseMapping_tree{ + my $entry = shift; + push @Mapping_tree_entries, $entry; +} + +############################################################################# +sub migrateDefaultIndexes { + foreach $index (@default_indexes) { + my $CN = $index->{cn}[0]; + my $newIndex ; + if ((! isAsystemIndex($index)) && (! $deniedIndexes{lc($CN)})) { + if ($newIndex = alreadyExistsInNew($index)) { + if (! isAsystemIndex($newIndex)) { + updateEntry($index, "DEFAULT_INDEX", 1, 2); + } + } + else { + addEntryToNew($index, "DEFAULT_INDEX", 2); + } + } + } +} + + +sub parseDefaultIndex{ + my $index = shift; + push @default_indexes, $index; +} + +############################################################################# + +sub migrateIndexes { + foreach $index (@indexes) { + my $CN = $index->{cn}[0]; + my $newIndex; + if ((! isAsystemIndex($index)) && (! $deniedIndexes{lc($CN)}) && (DN !~ /cn=netscaperoot,cn=index/i)){ + if ($newIndex = alreadyExistsInNew($index)) { + if (! isAsystemIndex($newIndex)) { + updateEntry($index, "INDEX", 1, 2); + } + } + else { + addEntryToNew($index, "INDEX", 2); + } + } + } +} + +sub parseIndex{ + my $index = shift; + push @indexes, $index; +} + +############################################################################# + +sub newLDIFplugin { + my $currentPlugin = shift; + my $DN = $currentPlugin->getDN(1); + my $newPlugin = $conn->newEntry() ; + $newPlugin->setDN($DN); + foreach $Attr (@pluginAttrs) { + my @values = $currentPlugin->getValues($Attr); + $newPlugin->setValues($Attr, @values) if (@values); + } + return $newPlugin; +} + +sub migrateStdPlugin{ + my $plugin = shift; + my $DN = $plugin->getDN(1); + my $pluginEnable = "nsslapd-pluginEnabled"; + my $argNum = 0; + my $argPrefix = "nsslapd-pluginarg"; + my $currentPlugin ; + if ($currentPlugin = alreadyExistsInNew($plugin, 1)) { + $plugin = updatePathInPluginArgs($plugin); + my $pluginEnableValue = $plugin->{$pluginEnable}[0]; + my $cont = 1; + my $pluginHasChanged = 0; + my $newPlugin = &newLDIFplugin($currentPlugin); + if (! $currentPlugin->hasValue($pluginEnable,$pluginEnableValue,1)){ + $newPlugin->setValues($pluginEnable, $pluginEnableValue); + $pluginHasChanged = 1 unless ($pluginHasChanged); + } + while($cont){ + my $arg = $argPrefix . $argNum ; + if ($plugin->exists($arg)) { + my @values = $plugin->getValues($arg); + my $value = $values[0] ; + $newPlugin->setValues($arg, $value) if (@values); + if ($currentPlugin->exists($arg)) { + if (! $currentPlugin->hasValue($arg,$value,1)) { + $pluginHasChanged = 1 unless ($pluginHasChanged); + } + } + else { + $pluginHasChanged = 1 unless ($pluginHasChanged); + } + } + else { + if ($currentPlugin->exists($arg)) { + # Just Warn the user. Do nothing. + printTrace("\nCompared to the old instance, the current new plugin $DN belongs this attribute: $arg",2); + } + else { + $cont = 0 ; + } + } + $argNum++; + } + updateEntry($newPlugin, "STANDARD_PLUGIN", 0, 1) if ($pluginHasChanged); + } +} + +############################################################################# + +sub migrateConfig_Node{ + my $config_node = shift; + my @params = keys(%GeneralSrvParamToMigrate); + my $hasChanged = 0; + my $newConfigNode; + if ($newConfigNode = alreadyExistsInNew($config_node, 1)){ + foreach $param (@params) { + if ($config_node->exists($param)){ + my @valuesToMigrate = $config_node->getValues($param); + if (@valuesToMigrate){ + if ($newConfigNode->exists($param)){ + my @currentValues = $newConfigNode->getValues($param); + if (Diffs(\@valuesToMigrate, \@currentValues)) { + $newConfigNode->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + printTrace("\nParam to update: $param with value @valuesToMigrate",3); + } + } + else { + $newConfigNode->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + printTrace("\nParam to update: $param with value @valuesToMigrate",3); + } + } + } + } + updateEntry($newConfigNode, "CONFIG_NODE", 0, 1) if ($hasChanged); + } +} + +############################################################################# + +sub migrateConfig_LDBM_database{ + my $config_ldbm = shift; + my @params = keys(%GlobalConfigLDBMparamToMigrate); + my $hasChanged = 0; + my $newConfigLdbm ; + if ($newConfigLdbm = alreadyExistsInNew($config_ldbm, 1)) { + foreach $param (@params) { + if ($config_ldbm->exists($param)){ + my @valuesToMigrate = $config_ldbm->getValues($param); + if (@valuesToMigrate){ + if ($newConfigLdbm->exists($param)){ + my @currentValues = $newConfigLdbm->getValues($param); + if (Diffs(\@valuesToMigrate, \@currentValues)) { + $newConfigLdbm->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + } + } + else { + $newConfigLdbm->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + } + } + } + } + updateEntry($newConfigLdbm, "CONFIG_LDBM_DATABASE", 0, 1) if ($hasChanged); + } +} + +############################################################################# + +sub migrateChainingBE_config{ + my $chaining_config = shift; + my $DN = $chaining_config->getDN(1); + my @params = (); + my $hasChanged = 0; + my $newChainingConfig; + if ($DN =~ /^cn=config,cn=chaining database,cn=plugins,cn=config$/i){ + $newChainingConfig = searchEntry("cn=config,cn=chaining database,cn=plugins,cn=config"); + @params = keys(%ChainingConfigParams); + } + if ($DN =~ /^cn=default instance config,cn=chaining database,cn=plugins,cn=config$/i){ + $newChainingConfig = searchEntry("cn=default instance config,cn=chaining database,cn=plugins,cn=config"); + @params = keys(%ChainingDefaultInstanceConfigParams); + } + foreach $param (@params) { + if ($chaining_config->exists($param)){ + my @valuesToMigrate = $chaining_config->getValues($param); + if (@valuesToMigrate){ + printTrace("\nParam: $param values To migrate: @valuesToMigrate",3); + if ($newChainingConfig->exists($param)){ + my @currentValues = $newChainingConfig->getValues($param); + printTrace("\nParam: $param new current values: @currentValues",3); + if (Diffs(\@valuesToMigrate, \@currentValues)) { + $newChainingConfig->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + } + } + else { + $newChainingConfig->setValues($param, @valuesToMigrate); + $hasChanged = 1 unless ($hasChanged); + } + } + } + } + updateEntry($newChainingConfig, "CHAINING_BACKEND_CONFIG", 0, 1) if ($hasChanged); +} + +############################################################################# + +sub registerSuffix_ChainingBE { + my $ldbmDatabase = shift; + my $CN = $ldbmDatabase->{cn}[0]; + my $suffixArg = "nsslapd-suffix"; + my $suffix = $ldbmDatabase->{$suffixArg}[0]; + $oldChainingBackends{$suffix} = $CN; +} + +sub storeMultiplexorBindDN { + my $chaining_instance = shift; + my $DN = $chaining_instance->getDN(1); + if ($chaining_instance->exists("nsMultiplexorBindDN")){ + my $bindDN = $chaining_instance->{nsMultiplexorBindDN}[0]; + my $newBindDN = searchEntry($bindDN); + if (! $newBindDN){ + # the bindDN entry doesn't yet exist in new => it will have to be migrated + $MultiplexorBindDNEntriesToMigrate{$bindDN}="\n" ; + printTrace("\nThe bindDN: $bindDN need to be migrated",3); + } + else { + # do nothing as the entry already exists in new + } + } + +} + +sub importMultiplexorBindDNEntries { + # import all entries present in @MultiplexorBindDNEntriesToMigrate in new + my @MultiplexorBindDNs = keys (%MultiplexorBindDNEntriesToMigrate); + my $ldif_dir = $ldif_rep; + foreach $bindDN (@MultiplexorBindDNs) { + printTrace("\nimportMultiplexorBindDNEntries: bindDN to migrate: $bindDN",3); + # get the backend in which is stored the bind DN entry + my $backendtoExportFrom = getBackendtoExportFrom($bindDN); + printTrace("\nbackendtoExportFrom is: $backendtoExportFrom",3); + # check wether the backend has been imported in new or not + if (! alreadyMigrated($backendtoExportFrom)) { + if ($backendtoExportFrom ne $NULL) { + # if not imported => we need to import the binf DN entry + &startServer() unless (isDirectoryAlive()); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + &ExportAndAddEntry($bindDN, $backendtoExportFrom, $ldif_dir); + } + else { + # do nothing + } + } + } + # remove the empty ldif directory + rmdir($ldif_dir) if (-d $ldif_dir); + # close the LDAP connection to new + $conn->close if ($conn); +} + +sub migrateChainingBE_instance{ + my $chaining_instance = shift; + my $DN = $chaining_instance->getDN(1); + ®isterSuffix_ChainingBE($chaining_instance); + if (alreadyExistsInNew($chaining_instance)) { + # already exists + printMsg("\n\n*** CHAINING_BACKEND_INSTANCE - $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + &migrate_credential($chaining_instance, "nsmultiplexorcredentials"); + addEntryToNew($chaining_instance, "CHAINING_BACKEND_INSTANCE", 1); + storeMultiplexorBindDN($chaining_instance); + } +} + +############################################################################# + +# create a new LDIF representation of a new replica consumer +sub newLDIFreplica { + my $replica = shift; + my $DN = $replica->getDN(1); + my $newReplica = $conn->newEntry() ; + my $MASTER_OR_MULTIMASTER = "3" ; + $newReplica->setDN($DN); + foreach $Attr (@nsds5replicaAttrs) { + my @values = $replica->getValues($Attr); + $newReplica->setValues($Attr, @values) if (@values); + } + my $replicaType = $replica->{nsDS5ReplicaType}[0]; + if ($replicaType eq $MASTER_OR_MULTIMASTER) { + my @nsState = $replica->getValues("nsState"); + # nsState omitted because it is incomatible between 32 and 64 bit + # servers. Bug 624441 + # $newReplica->setValues("nsState", @nsState); + } + else { + $newReplica->setValues("nsDS5ReplicaId", $replicaIdvalue); + } + return $newReplica; +} + +sub MigrateNSDS5_replica{ + foreach $replica (@new6replicas) { + my $DN = $replica->getDN(1); + my $newReplica; + my @removeAttrs = qw(nsstate nsds5replicaname nsds5replicachangecount); + for (@removeAttrs) { + $replica->remove($_); + } + if (alreadyExistsInNew($replica)) { + # replica already exists + printMsg("\n\n*** NSDS5_REPLICA - $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + $newReplica = &newLDIFreplica($replica); + addEntryToNew($newReplica, "NSDS5_REPLICA", 1); + } + storeReplicaBindDN($replica); + } +} + +sub parseNSDS5_replica{ + my $replica = shift; + push @new6replicas, $replica; +} + +sub storeReplicaBindDN { + my $replica = shift; + my $DN = $replica->getDN(1); + if ($replica->exists("nsDS5ReplicaBindDN")){ + my $bindDN = $replica->{nsDS5ReplicaBindDN}[0]; + my $newBindDN = searchEntry($bindDN); + if (! $newBindDN){ + # the bindDN entry doesn't yet exist in new => it will have to be migrated + $ReplicaBindDNEntriesToMigrate{$bindDN}="\n" ; + printTrace("\nThe bindDN: $bindDN need to be migrated",3); + } + else { + # do nothing as the entry already exists in new + } + } +} + + +sub importReplicaBindDNEntries { + # import all entries present in @ReplicaBindDNEntriesToMigrate in new + my @ReplicaBindDNs = keys (%ReplicaBindDNEntriesToMigrate); + my $ldif_dir = $ldif_rep; + my $replBind_entry = ""; + my @bindDN_elements = ""; + my $bindDN_parent = ""; + my $parentBind_entry = ""; + foreach $bindDN (@ReplicaBindDNs) { + printTrace("\nimportReplicaBindDNEntries: bindDN to migrate: $bindDN",3); + # get the backend in which is stored the bind DN entry + my $backendtoExportFrom = getBackendtoExportFrom($bindDN); + printTrace("\nbackendtoExportFrom is: $backendtoExportFrom",3); + # If backend is from config, read the entry from dse.ldif and add to new - NGK + if ($backendtoExportFrom eq "cn=config") { + my $norm_bindDN = normalizeDN($bindDN); + @bindDN_elements = ldap_explode_dn($norm_bindDN, 0); +# @bindDN_elements = split(/,/,$norm_bindDN); + my $junk = shift(@bindDN_elements); + if ($#bindDN_elements >= 1) { + $bindDN_parent = normalizeDN(join(",", @bindDN_elements)); + } + printTrace("\nOpening DSE.ldif",3); + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF); + while ($entry = readOneEntry $in) { + my $DN = $entry->getDN(1); + if ($DN eq $norm_bindDN) { + $replBind_entry = $entry; + } + if ($bindDN_parent ne "") { + if ($DN eq $bindDN_parent) { + $parentBind_entry = $entry; + } + } + } + close(DSELDIF); + &startServer() unless (isDirectoryAlive()); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + if ($bindDN_parent ne "") { + addEntryToNew($parentBind_entry, BINDDN_PARENT, 0); + } + printTrace("\nAdding BindDN with addEntryToNew",3); + addEntryToNew($replBind_entry, BINDDN, 0); + } else { + # check wether the backend has been imported in new or not + if (! alreadyMigrated($backendtoExportFrom)) { + if ($backendtoExportFrom ne $NULL) { + # if not imported => we need to import the bind DN entry + &startServer() unless (isDirectoryAlive()); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + &ExportAndAddEntry($bindDN, $backendtoExportFrom, $ldif_dir); + } + else { + # do nothing + } + } + } + } + # remove the empty ldif directory + rmdir($ldif_dir) if (-d $ldif_dir); + # close the LDAP connection to new + $conn->close if ($conn); +} + +sub alreadyMigrated { + my $backendToCheck = shift; + foreach $backend (@BACKENDS) { + return 1 if ($backend eq $backendToCheck); + } + return 0 ; +} + +sub belongsSuffix { + my $suffix = shift; + my $bindDN = shift; + return ($bindDN =~ /$suffix\s*$/i); +} + +sub length { + my $suffix = shift; + my $count = 0; + while ($suffix =~ /./g) { + $count++; + } + return $count ; +} + +sub getBackendtoExportFrom { + my $bindDN = shift ; + my $sizeOfSuffix = 0 ; + my $NULL = ""; + my @oldSuffixes = keys(%oldBackends); + my @oldChainingSuffixes = keys(%oldChainingBackends); + my $bindDN_backend = $NULL; + my $config = "cn=config"; + + my $norm_bindDN = normalizeDN($bindDN); + # Check if bindDN exists in cn=config - NGK + if (belongsSuffix($config,$norm_bindDN)) { + $bindDN_backend = $config; + printTrace("\ngetBackendtoExportFrom: bindDN_backend: $bindDN_backend",3); + } else { + foreach $suffix (@oldSuffixes){ + printTrace("\ngetBackendtoExportFrom: suffix to compare with is: $suffix",3); + if ((belongsSuffix($suffix,$norm_bindDN)) && (length($suffix) > $sizeOfSuffix)) { + $sizeOfSuffix = length($suffix); + $bindDN_backend = $oldBackends{$suffix}; + printTrace("\ngetBackendtoExportFrom: bindDN_backend: $bindDN_backend, sizeOfSuffix: $sizeOfSuffix",3); + } + } + foreach $suffix (@oldChainingSuffixes){ + printTrace("\ngetBackendtoExportFrom: suffix to compare with is a chained suffix: $suffix",3); + if ((belongsSuffix($suffix,$norm_bindDN)) && (length($suffix) > $sizeOfSuffix)) { + printMsg("\n\n*** Entry stored on a remote backend - $norm_bindDN"); + printMsg("\n*** We don't migrate it"); + return $NULL; + } + } + } + return $bindDN_backend; +} + + +sub getBackendtoImportTo { + my $bindDN = shift; + my $sizeOfSuffix = 0; + my $NULL = ""; + my $suffixArg = "nsslapd-suffix"; + my $bindDN_backend = $NULL; + open( DSELDIF, "< $DSEldif" ) || die "Can't open $DSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + $typeOfEntry = getTypeOfEntry($entry); + if ($typeOfEntry eq "LDBM_BACKEND_INSTANCE"){ + my $suffix = $entry->{$suffixArg}[0]; + if ((belongsSuffix($suffix,$bindDN)) && (length($suffix) > $sizeOfSuffix)) { + $sizeOfSuffix = length($suffix); + $bindDN_backend = $entry->{cn}[0]; + } + } + } + close(DSELDIF); + return $bindDN_backend ; +} + + +sub ExportAndAddEntry { + my $DN = shift; + my $backendtoExportFrom = shift; + my $ldif_dir = shift; + my $ldif = "$ldif_dir${PATHSEP}$backendtoExportFrom.ldif" ; + # first: export entry pointed out by the $DN to $ldif file + $ENV{"$LIB_PATH"}=$old_libpath; + if (! $ldif_dir) { $ldif_dir = $ldif_rep ;} + if (!(-d $ldif_dir)) { + mkdir($ldif_dir,0777) or die "\ncan't create $ldif_dir to store temporary ldif files\n"; + } + chdir($oldSlapdExecDir) or die "\nCould not change directory to $oldSlapdExecDir: $!\n"; + &db2Ldif($ldif, $backendtoExportFrom, $oldHome, $DN); + chdir($curdir) or die "\nCould not change directory to $curdir: $!\n"; + + # then: Add it to new + if (! $conn) { + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + } + open( BINDDNLDIF, "< $ldif" ) || die "\nCan't open $ldif: $!: \n"; + my $in = new Mozilla::LDAP::LDIF(*BINDDNLDIF) ; + while ($entry = readOneEntry $in) { + my $entryDN = $entry->getDN(1); + if ($DN eq $entryDN) { + addEntryToNew($entry, "nsds5ReplicaBindDN", 0); + } + } + close(BINDDNLDIF); + # remove the ldif file after the import + unlink($ldif) ; +} + +############################################################################# +sub MigrateNSDS_replication_agreement { + foreach $replicationAgreement (@replicationAgreements) { + my $DN = $replicationAgreement->getDN(1); + if (alreadyExistsInNew($replicationAgreement)){ + # replication agreement already exists + printMsg("\n\n*** NSDS_REPLICATION_AGREEMENT - $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + &migrate_credential($replicationAgreement, "nsDS5ReplicaCredentials"); + addEntryToNew($replicationAgreement, "NSDS_REPLICATION_AGREEMENT", 1); + } + } +} + + +sub parseNSDS_replication_agreement{ + my $replicationAgreement = shift; + push @replicationAgreements, $replicationAgreement ; +} + +############################################################################# + +sub migrateChangelog5{ + my $changelog = shift; + my $DN = $changelog->getDN(1); + my $changelogdir = "nsslapd-changelogdir"; + if (alreadyExistsInNew($changelog)){ + # cn=changelog5,cn=config already exists in new + my $newChangelog = searchEntry($DN); + my @newChangelogdir = $newChangelog->getValues($changelogdir); + $changelog->setValues($changelogdir, @newChangelogdir); + updateEntry($changelog, "CHANGELOG5", 0, 1); + } + else { + # cn=changelog5,cn=config need to be created in new. + # the changelogdir value must be setup to <new_root_server>/slapd-instance/changelogdb + $changelog->setValues($changelogdir,"${serverHome}${PATHSEP}changelogdb"); + addEntryToNew($changelog, "CHANGELOG5", 1); + } +} + + +sub migrateChangelog { + my $oldchangelogdir = ""; + my $newchangelogdir = ""; + my $changelogdir = "nsslapd-changelogdir"; + my $CL5DN = "cn=changelog5,cn=config"; + printTrace("\n\n***** Migrate Changelog...",0,1); + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF); + while ($entry = readOneEntry $in) { + $typeOfEntry = getTypeOfEntry($entry); + if ($typeOfEntry eq "CHANGELOG5"){ + $oldchangelogdir = ($entry->getValues($changelogdir))[0]; + } + } + close(DSELDIF); + if ($oldchangelogdir) { + # If using olddatadir to migrate from, the path of the changelogdb + # from the dse.ldif may not match the path where the old server + # root was archived. We may need to modify oldchangelogdir so the + # copy of the changelog files succeeds. + unless(-e $oldchangelogdir) { + if($olddatadir) { + my @cldbpath = split(/\//,$oldchangelogdir); + until($cldbpath[0] =~/^slapd-/) { + shift(@cldbpath); + } + my $tmpcldbpath = join(${PATHSEP}, @cldbpath); + $oldchangelogdir = "$oldDir${PATHSEP}$tmpcldbpath"; + } + # If oldchangelogdir still looks to be wrong, prompt for the + # location instead of just failing on the copydir operation + # and bombing out of the migration. + unless(-e $oldchangelogdir) { + print("\n\nThe old changelog directory \"$oldchangelogdir\" doesn't exist. Please enter the correct path: "); + $oldchangelogdir = <STDIN>; + } + } + &startServer() unless (isDirectoryAlive()); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + my $newChangelog = searchEntry($CL5DN); + $newchangelogdir = ($newChangelog->getValues($changelogdir))[0]; + stopServer($root,'slapd-'.$newname); + printTrace("\ncopying $oldchangelogdir${PATHSEP}* to $newchangelogdir",3); + copyDir("$oldchangelogdir","$newchangelogdir"); + + # We need to modify the DBVERSION file for a new verision of the db + open(DBVERSION,">$newchangelogdir${PATHSEP}DBVERSION") || die "Can't overwrite $newchangelogdir${PATHSEP}DBVERSION: $! "; + print DBVERSION "Changelog5/NSMMReplicationPlugin/3.0"; + close(DBVERSION); + + &startServer() unless (isDirectoryAlive()); + } +} + +############################################################################# + +sub migrateReplication{ + my $replication = shift; + my $DN = $replication->getDN(1); + if (alreadyExistsInNew($replication)){ + # replication agreement already exists + printMsg("\n\n*** $DN already exists"); + printMsg("\n*** Migration will not update it"); + } + else { + addEntryToNew($replication, "REPLICATION", 1); + } +} + +############################################################################# + +sub migrateSecurity{ + my $security = shift; + if ($entry->hasValue("objectClass", "nsEncryptionConfig")) { + my $certfile = "alias/slapd-" . $newname . "-cert8.db"; + my $keyfile = "alias/slapd-" . $newname. "-key3.db"; + $entry->setValues("nsCertfile",$certfile) if ! $entry->hasValue("nsCertfile",$certfile); + $entry->setValues("nsKeyfile",$keyfile) if ! $entry->hasValue("nsKeyfile",$keyfile); + } + if (alreadyExistsInNew($security)){ + # already exists in new + updateEntry($security, "SECURITY", 0, 1); + } + else { + addEntryToNew($security, "SECURITY", 1); + } +} + +############################################################################# + +sub migrateSNMP{ + my $snmp = shift; + if (alreadyExistsInNew($snmp)){ + # already exists in new + updateEntry($snmp, "SNMP", 0, 1); + } + else { + addEntryToNew($snmp, "SNMP", 1); + } +} + +############################################################################# +# printMsg print message to the user standard output. + +sub printMsg { + + my $TypeMsg = shift ; + my $Msg = shift ; + my $LineNb = shift ; + if ($LineNb) { + printTrace("Line: $LineNb, $TypeMsg, $Msg"); + } + else { + printTrace("$TypeMsg $Msg"); + } +} + +############################################################################# +# print message error to the user standard output. + +sub printTrace { + + my $Msg = shift ; + my $level = shift ; + my $sep = shift ; + + if ($sep) { + print "\n-------------------------------------------------------------------------"; + print LOGFILE "\n-------------------------------------------------------------------------"; + } + + if ($level <= $TRACELEVEL) { + print($Msg); + print LOGFILE $Msg ; + } +} + +############################################################################# +# this subroutine implements a very stupid version of diff + +sub diff { + my $f1 = shift; + my $f2 = shift; + my $lineToBeginWith = shift; + my $NULL = "" ; + my $diff_f1 = $NULL ; + my $diff_f2 = $NULL ; + my $retval = $NULL ; + my $ret; + open(F1, "$f1") or die "Could not open file $f1"; + open(F2, "$f2") or close(F1), die "Could not open file $f2"; + + while (defined($l1 = <F1>)) { + if ($lineToBeginWith){ + $lineToBeginWith -- ; + next ; + } + next if ($l1 =~ /^\#/); + $ret = defined($l2 = <F2>); + if ($ret) { + $ret = defined($l2 = <F2>) while ($ret && ($l2 =~ /^\#/)) ; + if ($ret) { + if (!($l1 eq $l2)) { + + # ignore whitespace + $l1_clean = $l1 ; + $l2_clean = $l2 ; + $l1_clean =~ s/\s//g; + $l2_clean =~ s/\s//g; + + if (!($l1_clean eq $l2_clean)) { + $diff_f1 .= "${l1}" unless ($l1_clean eq $NULL); + $diff_f2 .= "${l2}" unless ($l2_clean eq $NULL); + } + } + } + else { + next if ($l1 =~ /^\s*$/) ; + $diff_f1 .= "${l1}"; + } + } + else { + next if ($l1 =~ /^\s*$/) ; + $diff_f1 .= "${l1}"; + } + } + + while (defined($l2 = <F2>)) { + if (($l2 =~ /^\#/) || ($l2 =~ /^\s*$/)) { + next ; + } + else { + $diff_f2 .= "${l2}" ; + } + } + + close(F1); + close(F2); + + $retval .= "- differences present in your config file but not in standard file:\n\n". "$diff_f1\n" if ($diff_f1) ; + $retval .= "- differences present in standard file but not in your config file:\n\n" . "$diff_f2" if ($diff_f2) ; + return $retval ; +} + +sub CompareStdConfigFiles { + # Compare each configuration file against its default version. If it has changed, + # notify the user that the file has changed and will need to be checked by the + # user. This should be safe to do because there should be no path information + # stored in these conf files, which are just schema stuff. + # printTrace("\nCheck if standard configuration files have changed",3); + + # get the version of the DS to migrate + ($oldVersion, $oldMinor) = &getVersion($oldDir, $oldversionstr); + # get the version of the new DS + ($Version, $Minor) = &getVersion($root); + + # get old LIB_PATH + $old_libpath = &getLibPath($oldDir, $oldVersion, $oldMinor); + # get new LIB_PATH + $new_libpath = &getLibPath($root, $Version, $Minor); + + my $origFilePath = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}install${PATHSEP}schema${PATHSEP}" ; + my $FilesChanged = ""; + my $AllDiffs = "***********************************************************************"; + my $NoChanges = "" ; + my $lineToBegin = 0 ; + opendir(CONFDIR, $oldSchemaDir) or + die "Error: could not open migrated config dir $oldConfDir: $!"; + + foreach $file (readdir(CONFDIR)) { + $origFile = $origFilePath . $file ; + $configFile = $oldSchemaDir . $file ; + if (( exists($stdIncludes{lc($file)})) && (-f $origFile)) { + $diffs = &diff($configFile, $origFile, $lineToBegin); + $lineToBegin = 0 if $lineToBegin ; + if ($diffs) { + $FilesChanged .= "\n$configFile"; + $AllDiffs .= "\n$configFile is different than the standard configuration file" ; + $AllDiffs .= "\nYou will need to check this file and make sure its changes are compatible "; + $AllDiffs .= "with the new directory server\nHere are the differences:\n"; + $AllDiffs .= "$diffs \n\n"; + $AllDiffs .= "***********************************************************************"; + } + else { + $NoChanges .= "\n$configFile"; + } + } + } + closedir(CONFDIR); + +if ($FilesChanged) { + printTrace("\nNo changes to old configuration files:$NoChanges",3) ; + printTrace("\n***********************************************************************",3) ; + printMsg("\nThe following standard files have been modified: $FilesChanged"); + if ($NO_INPUT_USER) { + # do nothing + } + else { + printMsg("\nDo you want to see the differences Yes/No [No] ?") ; + my $answer = <STDIN> ; + if ($answer =~ /y|yes/i) { + printMsg("$AllDiffs"); + } + printMsg("\nDo you want to continue the migration Yes/No [No] ?"); + $answer = <STDIN> ; + if (! ($answer =~ /y|yes/i)) { + exit(1); + } + } + } +} + + + +############################################################################# + +# this is used to run the system() call, capture exit and signal codes, +# and die() upon badness; the first argument is a directory to change +# dir to, if any, and the rest are passed to system() +sub mySystem { + my $rc = &mySystemNoDie(@_); + my ($dir, @args) = @_; + if ($rc == 0) { +# success + } elsif ($rc == 0xff00) { + die "Error executing @args: error code $rc: $!"; + } elsif ($rc > 0x80) { + $rc >>= 8; + die "Error executing @args: error code $rc: $!"; + } else { + if ($rc & 0x80) { + $rc &= ~0x80; + } + die "Error executing @args: received signal $rc: $!"; + } + + # usually won't get return value + return $rc; +} + +# This version does not die but just returns the error code +sub mySystemNoDie { + my ($dir, @args) = @_; + if ($dir && ($dir ne "")) { + chdir($dir) or die "Could not change directory to $dir: $!"; + } + my $cmd = $args[0]; + # the system {$cmd} avoids some NT shell quoting problems if the $cmd + # needs to be quoted e.g. contains spaces; the map puts double quotes + # around the arguments on NT which are stripped by the command + # interpreter cmd.exe; but don't quote things which are already quoted + my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @args; + my $rc = 0; + if ($cmd =~ /[.](bat|cmd)$/) { + # we have to pass batch files directly to the NT command interpreter + $cmd = $com_spec; +# print "system $cmd /c \"@fixargs\"\n"; + $rc = 0xffff & system {$cmd} '/c', "\"@fixargs\""; + } else { +# print "system $cmd @fixargs\n"; + $rc = 0xffff & system {$cmd} @fixargs; + } + chdir(${curdir}) or die "Could not change directory to $curdir: $!"; + return $rc; +} + +########################################################################################### +# # +# Export/Import of the backends in @BACKENDS # +# # +########################################################################################### + +sub manydb2Ldif { + my $ldif_dir = shift; + $ENV{"$LIB_PATH"}=$old_libpath; + if (! $ldif_dir) { $ldif_dir = $ldif_rep ;} + if (!(-d $ldif_dir)) { + mkdir($ldif_dir,0777) or die "can't create $ldif_dir to store temporary ldif files"; + } + chdir($oldSlapdExecDir) or die "Could not change directory to $oldSlapdExecDir: $!"; + foreach $backend (@BACKENDS) { + my $ldif = "${ldif_dir}$backend.ldif" ; + &db2Ldif($ldif, $backend, $oldHome); + } + print " Done.\n"; + chdir($curdir) or die "Could not change directory to $curdir: $!"; +} + +sub db2Ldif { + my $ldif = shift ; + my $backend = shift ; + my $home = shift ; + my $include_suffix = shift ; + my $db2ldif_param ; + if ($include_suffix) { + $db2ldif_param = "db2ldif -r -D $home -n $backend -a $ldif -s \"$include_suffix\""; + } + else { + $db2ldif_param = "db2ldif -r -D $home -n $backend -a $ldif"; + } + open(DB2LDIF, "${quote}${quote}$slapdExecName${quote} $db2ldif_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n"; + sleep(1); # allow some data to accumulate in the pipe + my $ii = 0; + while (<DB2LDIF>) { + ++$ii; + if (($ii % 250) == 0) { + printMsg(" Processing...\n"); + } + printMsg($_); + } + close(DB2LDIF); + # set the ownership of the ldif file; should be the same as the 6.x slapd user id + if ((! $isNt) && ($oldlocaluser ne $localuser)) { + if (-f $ldif) { + chown( $newuid, $newgid, $ldif) or printMsg("\nUnable to change the ownership of $ldif to $localuser") ; + } + } +} + +sub manyLdif2db { + my $ldif_dir = shift; + $ENV{"$LIB_PATH"}=$new_libpath; + chdir($slapdExecDir) or die "Could not change directory to $slapdExecDir: $!"; + foreach $backend (@BACKENDS) { + my $ldif = "${ldif_dir}$backend.ldif" ; + &Ldif2db($ldif, $backend); + } + # remove the empty ldif directory + # but not if using the data dir + if (!$olddatadir) { + rmdir($ldif_dir); + } + chdir($curdir) or die "Could not change directory to $curdir: $!"; +} + + +sub Ldif2db { + my $ldif = shift ; + my $backend = shift ; + my $ldif2db_param = "ldif2db -D $serverHome -n $backend -i $ldif"; + open(LDIF2DB, "${quote}${quote}$slapdExecName${quote} $ldif2db_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n"; + sleep(1); # allow some data to accumulate in the pipe + while (<LDIF2DB>) { + printMsg($_); + } + close(LDIF2DB); + # remove the ldif file after the import + # but not if using the data dir + if (!$olddatadir) { + unlink($ldif) ; + } +} + + +########################################################################################### +# # +# Running/Stopping the Server # +# # +########################################################################################### + + + +sub isDirectoryAlive { + die "\n Migration aborted. Make sure your old and new Directory Servers are installed on the same machine \n" if ( $LDAPservername == -1 ); + my $test_conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd); + if ($test_conn) { + $test_conn->close(); + return 1; + } + else { + return 0 ; + } +} + + +sub startServer { + my $instanceDir = ${serverHome} ; + my $errLog = $instanceDir . $PATHSEP . 'logs' . $PATHSEP . 'errors'; + # emulate tail -f + # if the last line we see does not contain "slapd started", try again + my $done = 0; + my $started = 0; + my $code = 0; + my $lastLine = ""; + my $timeout = time + 240; # 4 minutes + $ENV{"$LIB_PATH"}=$new_libpath; + + my $startCmd = $instanceDir . $PATHSEP . 'start' . $script_suffix; + if (! -f $startCmd) { + $startCmd = $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix; + } + $code = &mySystem($instanceDir,$startCmd); + open(IN, $errLog) or die "Could not open error log $errLog: $!"; + my $pos = tell(IN); + while (($done == 0) && (time < $timeout)) { + for (; ($done == 0) && ($_ = <IN>); $pos = tell(IN)) { + $lastLine = $_; + # print; + # the server has already been started and shutdown once . . . + if (/slapd started\./) { + $started++; + if ($started == 2) { + $done = 1; + } + # sometimes the server will fail to come up; in that case, restart it + } elsif (/Initialization Failed/) { + # print "Server failed to start: $_"; + $code = &mySystem($instanceDir, $startCmd); + # sometimes the server will fail to come up; in that case, restart it + } elsif (/exiting\./) { + # print "Server failed to start: $_"; + #$code = &mySystem($startCmd); + $code = &mySystem($instanceDir, $startCmd); + } + } + if ($lastLine =~ /PR_Bind/) { + # server port conflicts with another one, just report and punt + print $lastLine; + print "This server cannot be started until the other server on this\n"; + print "port is shutdown.\n"; + $done = 1; + } + if ($done == 0) { + # rest a bit, then . . . + sleep(2); + # . . . reset the EOF status of the file desc + seek(IN, $pos, 0); + } + } + close(IN); + + sleep(5); + die "\nUnable to start the $Version.$Minor Directory Server\n" unless (isDirectoryAlive()); + + return 0; +} + +sub stopServer { + my $root = shift; + my $name = shift; + $maxStopIterations = 5; + print "\nShutting down server $name . . .\n"; + $ENV{"$LIB_PATH"}=$new_libpath; + $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop' . $script_suffix . $quote; + if (! -f $stopCmd) { + $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop-slapd' . $script_suffix . $quote; + } + + if (! -f $stopCmd) { + # no stop command, probably a 1.X system; for NT, we'll try net stop + # for unix, we'll get the pid and kill it + if ($isNT) { + $stopCmd = 'net stop ' . $name; + } else { + # see if there is a pid file + $pidfile = $root . $PATHSEP . $name . $PATHSEP . 'logs' . + $PATHSEP . 'pid'; + if (open(PIDFILE, $pidfile)) { + chomp($pid = <PIDFILE>); + close(PIDFILE); + while ($maxStopIterations-- && !$exitCode) { + $exitCode = kill(15, $pid); + } + $stopCmd = undef; + } + } + } + + # keep looping until the stop cmd returns an error code, which usually + # means that what ever we want to stop is stopped, or some other error + # occurred e.g. permission, or no such service + $exitCode = &runAndIgnoreOutput($stopCmd); +# print "stopServer: exitCode=$exitCode\n"; + while ($stopCmd && $maxStopIterations-- && $exitCode) { + $exitCode = &runAndIgnoreOutput($stopCmd); +# print "stopServer: exitCode=$exitCode\n"; + } + + if (!$maxStopIterations) { + print "Warning: could not shutdown the server: $!\n"; + } + sleep(10) ; + $exitCode = 0; +} + + +sub runAndIgnoreOutput { + my $cmd = shift; + printMsg("."); + open(RUNCMD, "${quote}$cmd${quote} 2>&1 |") or die "Error: could not run $cmd: $!"; + printMsg("."); + sleep(1); # allow pipe to fill with data + printMsg("."); + while (<RUNCMD>) { +# print; + } + my $code = close(RUNCMD); +# print "runAndIgnore: code=$code status=$?\n"; + return $?; +} + +############################################################################# +# migrate SSL info + +sub MigrateSSL { + my $secPwd = 'bidon' ; + # copy the SSL directory + ©Dir("$oldHome${PATHSEP}ssl","$serverHome${PATHSEP}ssl") if (-d "$oldHome${PATHSEP}ssl"); + # copy the cert db and key files + if ( -d "$oldDir${PATHSEP}alias") { + $aliasDir = "$root${PATHSEP}alias"; + if (! -d $aliasDir) { + mkdir($aliasDir, 0750); + } + &stopServer($root,'slapd-'.$newname); + my $keydb = "$aliasDir${PATHSEP}slapd-$newname-key3.db" ; + my $certdb = "$aliasDir${PATHSEP}slapd-$newname-cert8.db" ; + my $certdb7 = "$aliasDir${PATHSEP}slapd-$newname-cert7.db" ; + my $old_keydb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-key3.db" ; + my $old_certdb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-cert7.db"; + my $keydb_backup = "$aliasDir${PATHSEP}slapd-$newname-key3.db_backup" ; + my $certdb_backup = "$aliasDir${PATHSEP}slapd-$newname-cert7.db_backup" ; + if (-f $old_keydb) { + if (-f $keydb) { + if ($NO_INPUT_USER) { + printMsg("\n$keydb already exists. backup in $keydb_backup ..."); + ©BinFile($keydb,$keydb_backup); + ©BinFile($old_keydb,$keydb); + } + else { + print("\n\n$keydb already exists. Do you want to overwrite it ? [no]: "); + my $answer = <STDIN> ; + if ($answer =~ /^y|yes$/i) { + ©BinFile($old_keydb,$keydb); + } + } + } + else { + ©BinFile($old_keydb,$keydb); + } + } + if (-f $old_certdb) { + $mode = (stat($old_certdb))[2] if $PRESERVE; + if (-f $certdb) { + if ($NO_INPUT_USER) { + printMsg("\n$certdb already exists. backup in $certdb_backup ..."); + ©BinFile($certdb,$certdb_backup); + unlink($certdb) || print "Couldn't delete $certdb : $!\n"; + ©BinFile($old_certdb,$certdb7); + } + else { + print("\n\n$certdb already exists. Do you want to overwrite it ? [no]: "); + my $answer = <STDIN> ; + if ($answer =~ /^y|yes$/i) { + unlink($certdb) || print "Couldn't delete $certdb : $!\n"; + ©BinFile($old_certdb,$certdb7); + } + } + } + else { + ©BinFile($old_certdb,$certdb7); + } + } + # copy the old password file + if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") { + ©BinFile( + "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt", + "$aliasDir${PATHSEP}$type-$newname-pin.txt" + ); + } + &startServer(); + if ($PRESERVE) { + chown($newuid,$newgid,$certdb) || print "Failed to set uid $newuid gid $newgid on $certdb : $!\n"; + chmod($mode,$certdb) || print "Failed to set mode $mode on $certdb : $!\n"; + } + } + +} + +sub DisableSSL { + my $entry = $conn->search("cn=config","base","objectclass=*"); + my $LDAPparam = "nsslapd-security" ; + my $Value = "off" ; + if ($entry->{$LDAPparam}[0] ne $Value) { + printTrace("\nDisable SSL...",1); + $entry->setValues($LDAPparam, $Value); + } + my $res = $conn->update($entry); + if ($res) { + printTrace("\nSSL disabled",2); + } + else { + printMsg("\nCan't disabled SSL. The server may have problems to start"); + } +} + +# enable the migration of client authentication informations +sub MigrateCertmap { + # backup the old certmap.conf and replace it with the new one + my $oldCertmap = "$oldDir${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf"; + my $newCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf" ; + my $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ; + if (-f $oldCertmap) { + if ($NO_INPUT_USER) { + printMsg("\n$newCertmap has been backup in $backupCertmap"); + ©BinFile($newCertmap,$backupCertmap); + ©BinFile($oldCertmap,$newCertmap); + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\n\nWhere do you want to back up the file $newCertmap [$backupCertmap] ?") ; + my $Answer = <STDIN> ; + $backupCertmap = $Answer if ($Answer ne "\n"); + chomp($backupCertmap); + printTrace("\nDest: .$backupCertmap.",4); + if (-e $backupCertmap) { + printMsg("\n\n$backupCertmap already exists. Do you want to overwrite it Yes/No [No] ?") ; + if (<STDIN> =~ /yes|y/i) { + $Ask = 0 ; + } + else { + $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ; + } + } + else { + $Ask = 0 ; + } + } + printTrace("\nBackup file: $newCertmap in $backupCertmap",4); + ©BinFile($newCertmap,$backupCertmap); + ©BinFile($oldCertmap,$newCertmap); + } + } + else { + } +} + +sub hasChangedoldCertmap { + my $certmapfile = shift ; + my @reference = ("certmap default default", + "default:DNComps", + "default:FilterComps e") ; + my $cpt = 0 ; + printTrace("\nhasChangedoldCertmap",3); + open(CERTMAP,"< $certmapfile"); + while (<CERTMAP>) { + if ((! /^\s*#/) && (! /^\s*$/)) { + my $ref = $reference[$cpt] ; + printTrace("\nValue: $_, ref: $ref",4); + if (! /^\s*$ref\s*$/) { + return 1 ; + } + else { + $cpt++ ; + } + } + } + close (CERTMAP); + printTrace("\ncpt: $cpt",4); + if ($cpt < $#reference) { + return 1 ; + } + else { + return 0 ; + } +} + + +########################################################################################### +# # +# Copy directory and files functions # +# # +########################################################################################### + + +sub copyDir { + my $src = shift; + my $dest = shift; + my $exclude = shift; + + opendir( SRC, $src ) or die "Can't open directory $src: $!: "; + my $mode; + my $uid; + my $gid; + mkdir ( $dest , 0755 ) or die "\nCan't create directory $dest. \nPlease check you have enough rights to create it and/or check that your parent directory exists.\n" if !( -e $dest ); + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + local ( @files ) = readdir ( SRC ); + closedir( SRC ); + for ( @files ) { + if ( $_ eq "." || $_ eq ".." ) { + next; + } elsif ( $exclude && /$exclude/ ) { + next; + } elsif ( $_ =~ /^__/ ) { + # region files are incompatible between 32 + # and 64 bit servers + next; + } elsif( -d "$src${PATHSEP}$_") { + ©Dir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" ); + } else { + ©BinFile ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_"); + } + } +} + +sub copyBinFile { + my $src = shift; + my $dest = shift; + my $buf = ""; + my $bufsize = 8192; + + open( SRC, $src ) || die "Can't open $src: $!\n"; + # if we are given a directory destination instead of a file, extract the + # filename portion of the source to use as the destination filename + if (-d $dest) { + $dest = $dest . $PATHSEP . &basename($src); + } + open( DEST, ">$dest" ) || die "Can't create $dest: $!\n"; + binmode SRC; + binmode DEST; + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + while (read(SRC, $buf, $bufsize)) { + print DEST $buf; + } + close( SRC ); + close( DEST ); +} + +############################################################################################################# +# backup 6.x configuration files # +# backup the directory <root_server5>/slapd-instance/config dans <root_server5>/slapd-instance/BackupConfig # # +# # +############################################################################################################# + + +sub backupConfigFiles { + # backup the 6.x config files + my $src = "$serverHome${PATHSEP}config" ; + my $dest = "$serverHome${PATHSEP}config_backup" ; + if ($NO_INPUT_USER) { + printMsg("\n$src has been backup in $dest"); + ©Dir($src,$dest); + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\n\nWhere do you want to back up your configuration directory [$dest] ?") ; + my $Answer = <STDIN> ; + $dest = $Answer if ($Answer ne "\n"); + chomp($dest); + printTrace("\nDest: .$dest.",4); + if (-e $dest) { + printMsg("\n\n$dest already exists. Do you want to overwrite it Yes/No [No] ?") ; + if (<STDIN> =~ /yes|y/i) { + $Ask = 0 ; + } + else { + $dest = "$serverHome${PATHSEP}config_backup" ; + } + } + else { + $Ask = 0 ; + } + } + printTrace("\nBackup Directory: $src in $dest",4); + ©Dir($src,$dest); + } +} +############################################################################# + +sub getLDAPservername { + my $oldLDAPservername; + my $LDAPservername; + my $localhost = "nsslapd-localhost"; + open(OLDDSELDIF, "< $oldDSEldif") or die "\nError: could not open old config file $oldDSEldif \n"; + my $in = new Mozilla::LDAP::LDIF(*OLDDSELDIF) ; + while ($entry = readOneEntry $in) { + my $DN = $entry->getDN(1) ; + if ($DN =~ /^cn=config$/i) { + my @values = $entry->getValues($localhost); + if ($entry->size($localhost)) { + $oldLDAPservername = $values[0]; + printTrace("\nName of the old LDAP server: $oldLDAPservername",3); + } + break; + } + } + close(OLDSELDIF); + + open( DSELDIF, "< $DSEldif" ) || die "\nCan't open $DSEldif \n"; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + my $DN = $entry->getDN(1) ; + if ($DN =~ /^cn=config$/i) { + my @values = $entry->getValues($localhost); + if ($entry->size($localhost)) { + $LDAPservername = $values[0]; + printTrace("\nName of the new LDAP server: $LDAPservername",3); + } + break; + } + } + close(DSELDIF); + # check ol and new Directory Instance are installed on the same physical machine. + if (lc($oldLDAPservername) ne lc($LDAPservername)) { + # warn the user he tries to migrate a 4.x server installed on a different machine from the 6.x one + printMsg("\n\nYour old instance is on $oldLDAPservername, whereas your new instance is on $LDAPservername. Migration on different machines is not supported. Do you want to continue ? Yes/No [No]:") ; + if (! (<STDIN> =~ /yes|y/i)) { + return -1; + } + } + return $LDAPservername ; +} + +############################################################################# + +sub getLibPath { + my $myDir = shift; + my $myVersion = shift; + my $myMinor = shift; + + if ($isNT) { + return $ENV{"$LIB_PATH"}; + } + if (($myVersion >= 6) && ($myMinor >= 2)) { + return + "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}". + "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}". + $ENV{"$LIB_PATH"}; + } else { + return "$myDir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + } +} + +############################################################################# + +sub getVersion { + my $dir = shift; + my $versionstr = shift; + my $version = 0; + my $minor = 0; + my $buildNumber = 0; + my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}"; + + # find the slapd executable + if (!$versionstr) { # version not specified on cmd line - find it + $prog = $dir . $progDir . $slapdExecName; + if (! -f $prog) { + $prog = $dir . $progDir2 . $slapdExecName; + if (-f $prog && $isNT) { + # if slapd is in bin/slapd and we're on NT, just assume version 1; + # apparently, slapd.exe doesn't like the -v argument . . . + return ( '1', $minor ); + } + else{ + die "Could not run slapd program $prog: $!"; + } + } + else { + chdir($dir . $progDir); + } + $cur_libpath=$ENV{"$LIB_PATH"}; + $ENV{"$LIB_PATH"}= + "$dir${PATHSEP}lib${SEP}". + "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}". + "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}". + $ENV{"$LIB_PATH"}; + # read the old version from the old slapd program + + open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or + die "Could not run slapd program $prog: $!"; + sleep(1); # allow some data to accumulate in the pipe +# print "Output from $prog -v:\n"; + while (<F>) { + if (/^Netscape-Directory/ || /^iPlanet-Directory/i) { + $versionstr = $_; + last; + } + } + $code = close(F); + # print "$prog returned code=$code status=$?\n"; + $ENV{"$LIB_PATH"}=$cur_libpath; + } + + if ($versionstr =~ /^Netscape-Directory\/(\d+)\.(\d+)(?:b\d)*\s+(\S+)/) { + $version = $1; + $minor = $2; + $buildNumber = $3; + } + elsif ($versionstr =~ /^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ... + $version = $1; + $minor = $2; + $buildNumber = $3; + } + elsif ($versionstr =~ /^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) { + $version = $1; + $minor = $2; + $buildNumber = $3; + } elsif ($versionstr =~ /(\d+)\.(\d+)/) { + $version = $1; + $minor = $2; + } + + if ($version == 0) { + die "\nCould not determine version of the directory server in $dir: \n"; + } + + # distinguish the 4.1 and the 4.11 thanks to the buildNumber + if (($version == 4) && ($minor == 1)){ + if (! ($buildNumber =~ /^B99\.16/)) { + # it's not a 4.1 Netscape Directory Server => it's a 4.11 + $minor = 11 ; + } + } + chdir($curdir) or die "Could not change directory to $curdir: $!" ; + return ( $version, $minor ); +} + +############################################################################################### +sub normalizeDir { + my $dir = shift ; + my $dir_prec = "" ; + while ($dir_prec ne $dir) { + $dir_prec = $dir ; + if ($isNT) { + grep { s@\\\\@\\@g } $dir ; + } + else { + grep { s@//@/@g } $dir ; + } + } + return $dir ; +} + + +############################################################################################### + +sub GetTime { + my $tm = localtime; + (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900); + $sec = "0$sec" unless $sec > 9 ; + $min = "0$min" unless $min > 9 ; + $hour = "0$hour" unless $hour > 9 ; + $dd = "0$dd" unless $dd > 9 ; + $mm = "0$mm" unless $mm > 9 ; + return ($sec, $min, $hour, $dd, $mm, $yy); +} + +############################################################################################### +# get uid and group id of the 6.x slapd server. +# The uid is done through the nsslapd-localuser attribute + +sub getuid_gid { + my $newuid ; + my $newgid ; + my $localuser ; + my $localuser_attr = "nsslapd-localuser" ; + if (! $isNT) { + &startServer() unless (isDirectoryAlive()); + my $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n"; + my $entry = $conn->search("cn=config ", "base","objectclass=*", 0, ($localuser_attr)) ; + # Tests wether we succeed to get the entry cn=config + die "\nCan't get the entry cn=config \n" unless ($entry); + my @values = $entry->getValues($localuser_attr); + $conn->close(); + if ($#values == -1 || ($values[0] eq "") ) { # tests wether the nsslapd-localuser attribute has a value + printMsg("\nNo localuser has been found in the configuration of the directory. "); + if ($NO_INPUT_USER) { + printMsg("\nWe considered nobody as the localuser"); + $localuser = "nobody" ; + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\nUnder what user does your $Version.$Minor directory server run [nobody] ? ") ; + $localuser = <STDIN> ; + chomp($localuser); + $localuser = "nobody" if ($localuser eq ""); + ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ; + if ($newuid) { + $Ask = 0 ; + } + else { + printMsg("\nError: $localuser is unknown from the system "); + } + } + } + } + else { + $localuser = $values[0]; # returns the first value (we should only have one localuser) + my $size = $#values ; + } + ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ; + return ($localuser, $newuid, $newgid) ; + } + else { + return () ; + } +} + +sub getolduid_gid { + my $oldlocaluser ; + my $localuserAttr = "nsslapd-localuser"; + my $entry ; + if (! $isNT) { + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + $typeOfEntry = getTypeOfEntry($entry); + if ($typeOfEntry eq "CONFIG_NODE") { + $oldlocaluser = $entry->{$localuserAttr}[0] if ($entry->exists($localuserAttr)); + break ; + } + } + close(DSE); + ($olduid, $oldgid) = (getpwnam("$oldlocaluser"))[2..3] ; + return ($oldlocaluser, $olduid, $oldgid) ; + } + else { + return (); + } +} +############################################################################################### +# get current directory + +sub getCwd { + my $command = $isNT ? "cd" : "/bin/pwd"; + open(PWDCMD, "$command 2>&1 |") or + die "Error: could not execute $command: $!"; + # without the following sleep, reading from the pipe will + # return nothing; I guess it gives the pwd command time + # to get some data to read . . . + sleep(1); + my $currentdir; + while (<PWDCMD>) { + if (!$currentdir) { + chomp($currentdir = $_); + } + } + my $code = close(PWDCMD); +# if ($code || $?) { +# print "$command returned code=$code status=$? dir=$curdir\n"; +# } +# print "getCwd curdir=\[$curdir\]\n"; + return $currentdir; +} + +################################ +# Need to migrate the credential. +# If the credential can not be migrated, leave it at it is +################################ +sub migrate_credential{ + my $entry_to_modify = shift; + my $credentials_attr = shift; + my @old_value = $entry_to_modify->getValues($credentials_attr); + my $migratecredExecName = 'migratecred'; + my $credOldHome = $oldHome; + my $credServerHome = $serverHome; + + if ($isNT) { + # oldHome may be pointing to the archived copy of the + # instance dir which may be different than the path that + # the instance was originally installed as on Windows. If + # this path is not the original install path, then the + # credential will not be migrated correctly. We should + # prompt the user on Windows for the correct path. + + print "\n\nThe old instance path must be the same as where it was"; + print "\ninitially installed, not where it was archived in order"; + print "\nfor this step to succeed. Please verify that the path"; + print "\nis correct. Note that case sensitivity is important here."; + print "\n\nOld Instance Directory: $credOldHome"; + print "\nIs this correct? (y/n): "; + chomp(my $answer = <STDIN>); + if (!($answer =~ /y|yes/i)) { + print "\nPlease enter the correct path for the old instance directory: "; + chomp($credOldHome = <STDIN>); + } + + print "\n\nThe new instance path must also be correct for this step"; + print "\nto succeed. Please verify that the path is correct. Note"; + print "\nthat case sensitivity is important here."; + print "\n\nNew Instance Directory: $credServerHome"; + print "\nIs this correct? (y/n): "; + chomp(my $answer = <STDIN>); + if (!($answer =~ /y|yes/i)) { + print "\nPlease enter the correct path for the new instance directory: "; + chomp($credServerHome = <STDIN>); + } + } +# print "\nMigratecred command is: ${quote}$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}$migratecredExecName${quote} -o $credOldHome -n $credServerHome -c @old_value\n"; + + my @new_cred = `${quote}$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}$migratecredExecName${quote} -o $credOldHome -n $credServerHome -c @old_value`; + + if ( $? == 0 ) + { + $entry_to_modify->setValues($credentials_attr, @new_cred); + } +} + diff --git a/ldap/admin/src/scripts/template-migrateInstance5 b/ldap/admin/src/scripts/template-migrateInstance5 new file mode 100644 index 00000000..3d3396c2 --- /dev/null +++ b/ldap/admin/src/scripts/template-migrateInstance5 @@ -0,0 +1,518 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +use Time::localtime; + +BEGIN { + require 'uname.lib'; + $| = 1; + $isNT = -d '\\'; + $PATHSEP = $isNT ? "\\" : "/"; + $SEP = $isNT ? ";" : ":" ; + $exitCode = 0; + @INC = ( '.', '../../../admin/admin/bin'); + grep { s@/@\\@g } @INC if $isNT; + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + # NT needs quotes around some things unix doesn't + $quote = $isNT ? "\"" : ""; + if ($isNT) { + # we have to pass batch files directly to the NT command interpreter + $com_spec = $ENV{ComSpec}; + if (!$com_spec) { + $com_spec = $ENV{COMSPEC}; + } + if (!$com_spec || ! -f $com_spec) { + # find the first available command interpreter + foreach $drive (c..z) { + $com_spec = "$drive:\\winnt\\system32\\cmd.exe"; + last if (-f $com_spec); + $com_spec = undef; + } + if (! $com_spec) { + # punt and pray + $com_spec = 'c:\winnt\system32\cmd.exe'; + } + } + $os = "WINNT"; + } else { + $os = &uname("-s"); + if ($os eq "SunOS") { + $isSolaris9 = ( &uname("-r") eq "5.9" ); + } + } + + if ( ($os eq "AIX") || ($os eq "HP-UX") ) { + $sigChildHandler = 'sigChildHandler'; + } + SWITCH: { + if ($os eq "AIX") { + $LIB_PATH = "LIBPATH" ; + last SWITCH ; + } + if ($os eq "HP-UX") { + $LIB_PATH = "SHLIB_PATH" ; + last SWITCH ; + } + if ($isNT) { + $LIB_PATH = "PATH" ; + last SWITCH ; + } + else { + $LIB_PATH = "LD_LIBRARY_PATH" ; + last SWITCH ; + } + } + $slapdExecName = $isNT ? 'slapd.exe' : 'ns-slapd'; + select STDERR; + $| = 1; + select STDOUT; + $| = 1; +} + + + +$TRACELEVEL = 0; +${root} = "{{DS-ROOT}}" ; +${type} = "" ; +${newname} = "" ; +${newport} = "" ; +${rootDN} = "" ; +${rootpwd} = "" ; +${localhost} = "" ; +${LogFileReport} = "" ; + +# get input users +&getParameters() ; + + +${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ; +${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ; +${oldSlapdConf} = "${oldConfDir}slapd.conf" ; +${serverHome} = "${root}${PATHSEP}$type-$newname" ; +${ldif_rep} = "${oldConfDir}${PATHSEP}ldif${PATHSEP}" ; +${curdir} = getCwd(); + + +if (!(-d $serverHome)) { + print("\n$serverHome doesn't exist\n"); + exit(1); + } + if (!(-d $oldHome)) { + print("\n$oldHome doesn't exist\n"); + exit(1); + } +$ENV{"$LIB_PATH"} = "$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"} ; +if ($isSolaris9) { + $ENV{"$LIB_PATH"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.005_03${PATHSEP}lib${PATHSEP}sun4-solaris${PATHSEP}CORE${SEP}".$ENV{"$LIB_PATH"} ; +} + +if ($isNT) { + $ENV{"PERL5LIB"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.005_03${PATHSEP}site${PATHSEP}lib${SEP}".$ENV{"PERL5LIB"} ; +} +else { + $ENV{"PERL5LIB"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.005_03${PATHSEP}lib${PATHSEP}site${SEP}".$ENV{"PERL5LIB"} ; +} + +# get the version of the DS to migrate +($oldVersion, $oldMinor) = &getVersion($oldDir); +# get the version of the new DS +($Version, $Minor) = &getVersion($root); + +if ($Version >= 5) { + if ($oldVersion == 4) { + $myscript = "migrateTo5" ; + printMsg("\n******* Migration from $oldVersion.$oldMinor Netscape Directory Server to $Version.$Minor iPlanet Directory Server *********\n"); + } + elsif ($oldVersion == 5 ) { + printMsg("\nWarning. You may experiment some problems considering the version of directory server you want to migrate is not a 5.0") if ($oldMinor != 0); + if ($oldMinor > $Minor) { + die "The migration from a version to an oldest one is not supported\nMigration aborted\n"; + } + $myscript = "migrate50to51" ; + printMsg("\n******* Migration from $oldVersion.$oldMinor to $Version.$Minor iPlanet Directory Server *********\n"); + } + else { + die "We don't support the version of directory server you want to migrate"; + } +} +else { + die "\n\nThe version of directory you want to upgrade is not a 5.x product\nMigration aborted\n"; +} + + + +my $start_time = gmtime ; +@args = ($, $myscript, @ARGV, '-L', $LogFileReport); +$exitCode = &mySystem(@args); +#die "Error: @args: $!" if ($exitCode != 0); + +open(LOGFILE,">> $LogFileReport") or die "\nCan't write to $LogFileReport\n$!\n"; +if (! $exitCode) { + my $end_time = gmtime ; + printMsg("-> Migration started at $start_time\n"); + printMsg("-> Migration ended at $end_time\n\n"); +} +printMsg("***********************************************\n\n"); +print("-> The migration report file is available at: $LogFileReport\n\n"); + +close(LOGFILE); + +####################################################################################################################### +sub usage { + print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n"); + print(STDERR " -o oldInstancePath -n newInstancePath [-t tracelevel] \n"); + print(STDERR " [-L logfile] [-noinput]\n"); + print(STDERR "************** parameters in brackets are optionals, others are required **************\n"); + print(STDERR " Opts: -D rootdn - new 5.x Directory Manager\n"); + print(STDERR " : -w password - new 5.x Directory Manager's password\n"); + print(STDERR " : -w - - Prompt for new 5.x Directory Manager's password\n"); + print(STDERR " : -j filename - Read new 5.x Directory Manager's password from file\n"); + print(STDERR " : -p port - new 5.x Directory Server port\n"); + print(STDERR " : -o oldInstancePath - Path of the old instance to migrate \n"); + print(STDERR " : -n newInstancePath - Path of the new 5.x instance\n"); + print(STDERR " : [-t tracelevel] - specify the level of trace (0..3) by default setup to 1\n"); + print(STDERR " : [-L logfile] - specify the file to log the migration report \n"); + print(STDERR " : [-noinput] - no user interventions during migration processing to solve conflicts\n"); + + } + + +####################################################################################################################### +# get input users + +sub getParameters { + my $exit = 0 ; + my $i = 0; + my $pwdfile= ""; + + while ($i <= $#ARGV) { + if ( "$ARGV[$i]" eq "-D" ) { # directory manager + if (! $rootDN) { + $rootDN = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-w") { # password + if (! $rootpwd) { + $rootpwd = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-j") { # password file + if (! $pwdfile) { + $pwdfile = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-o") { # old instance path + if (! $oldHome ) { + $oldHome = $ARGV[++$i] ; + grep { s@\\@/@g } $oldHome if $isNT ; + if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; } + if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) { + $oldDir = $1 ; + $type = $2 ; + $oldname = $3 ; + if ($isNT) { + $oldDir = lc($oldDir) ; + $type = lc($type) ; + $oldname = lc($oldname) ; + $oldHome = lc($oldHome) ; + grep { s@/@\\@g } $oldDir ; + grep { s@/@\\@g } $oldHome ; + } + } + else { + print("\nThe old instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-n") { # 5.x instance path + if (! $serverHome ) { + $serverHome = $ARGV[++$i] ; + grep { s@\\@/@g } $root if $isNT ; + grep { s@\\@/@g } $serverHome if $isNT ; + if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; } + if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) { + $root = $1 if ($1); + $type = $2 ; + $newname = $3 ; + if ($isNT) { + $root = lc($root) ; + $type = lc($type) ; + $newname = lc($newname) ; + $serverHome = lc($serverHome) ; + grep { s@/@\\@g } $root ; + grep { s@/@\\@g } $serverHome ; + } + } + else { + print("\nThe 5.x instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-p") { # 5.x DS port + if (! $newport ) { + $newport = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL + my $value = $ARGV[++$i] ; + if ($value =~ /[0-3]/) { + $TRACELEVEL = $value ; + } + else { + print("\nThe tracelevel must belong to 0..3 interval"); + &usage(); + exit(); + } + } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing + } elsif ("$ARGV[$i]" eq "-L") { # user defined logfile for the migration + $LogFileReport = $ARGV[++$i]; + } + else { + &usage() ; + exit(1); + } + $i++; + } + + if (! $rootDN) { + print("\nThe rootDN is missing"); + $exit = 1; + } + if ($pwdfile ne "") { + # Open file and get the password + unless (open (RPASS, $pwfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $rootpwd = <RPASS>; + chomp($rootpwd); + close(RPASS); + } elsif ($rootpwd eq "-"){ + # Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; + # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $rootpwd = ReadLine(0); +# chomp($rootpwd); +# ReadMode('normal'); + } + if (! $rootpwd) { + print("\nThe rootpwd is missing"); + $exit = 1 ; + } + if (! $newport) { + print("\nThe port is missing"); + $exit = 1; + } + if (! $serverHome) { + print("\nThe new instance path is missing"); + $exit = 1; + } + if (! $oldHome) { + print("\nThe old instance path is missing"); + $exit = 1; + } + if ((! $LogFileReport) && $serverHome) { + ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime(); + $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log"; + } + if ($exit) { + &usage() ; + exit(1); + } + +} + +############################################################################# +# printMsg print message to the user standard output. + +sub printMsg { + + my $TypeMsg = shift ; + my $Msg = shift ; + my $LineNb = shift ; + if ($LineNb) { + printTrace("Line: $LineNb, $TypeMsg, $Msg"); + } + else { + printTrace("$TypeMsg $Msg"); + } +} + +############################################################################# +# print message error to the user standard output. + +sub printTrace { + + my $Msg = shift ; + my $level = shift ; + if ($level <= $TRACELEVEL) { + print($Msg); + print LOGFILE $Msg; + } + +} + +############################################################################# +sub mySystem { + my $cmd = $_[0]; + # the system {$cmd} avoids some NT shell quoting problems if the $cmd + # needs to be quoted e.g. contains spaces; the map puts double quotes + # around the arguments on NT which are stripped by the command + # interpreter cmd.exe; but don't quote things which are already quoted + my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @_; + my $rc = 0; + if ($cmd =~ /[.](bat|cmd)$/) { + # we have to pass batch files directly to the NT command interpreter + $cmd = $com_spec; +# print "system $cmd /c \"@fixargs\"\n"; + $rc = system {$cmd} '/c', "\"@fixargs\""; + } else { +# print "system $cmd \"@fixargs\"\n"; + $rc = system {$cmd} @fixargs; + } + + return $rc; +} + +############################################################################# + +sub GetTime { + my $tm = localtime; + (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900); + $sec = "0$sec" unless $sec > 9 ; + $min = "0$min" unless $min > 9 ; + $hour = "0$hour" unless $hour > 9 ; + $dd = "0$dd" unless $dd > 9 ; + $mm = "0$mm" unless $mm > 9 ; + return ($sec, $min, $hour, $dd, $mm, $yy); +} + +############################################################################# + +sub getVersion { + my $dir = shift; + my $version = 0; + my $minor = 0; + my $buildNumber = 0; + my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}"; + + # find the slapd executable + $prog = $dir . $progDir . $slapdExecName; + if (! -f $prog) { + $prog = $dir . $progDir2 . $slapdExecName; + if (-f $prog && $isNT) { + # if slapd is in bin/slapd and we're on NT, just assume version 1; + # apparently, slapd.exe doesn't like the -v argument . . . + return ( '1', $minor ); + } + else{ + die "Could not run slapd program $prog: $!"; + } + } + else { + chdir($dir . $progDir); + } + $ENV{"$LIB_PATH"}="$dir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + # read the old version from the old slapd program + + open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or + die "Could not run slapd program $prog: $!"; + sleep(1); # allow some data to accumulate in the pipe +# print "Output from $prog -v:\n"; + while (<F>) { + if (/^Netscape-Directory\/(\d+)\.(\d+)\s+(\S+)/) { + $version = $1; + $minor = $2; + $buildNumber = $3; + last; + } + elsif (/^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ... + $version = $1; + $minor = $2; + $buildNumber = $3; + last; + } + elsif (/^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) { + $version = $1; + $minor = $2; + $buildNumber = $3; + last; + } + } + $code = close(F); +# print "$prog returned code=$code status=$?\n"; + $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + + if ($version == 0) { + die "\nCould not determine version of the directory server in $dir: \n"; + } + + # distinguish the 4.1 and the 4.11 thanks to the buildNumber + if (($version == 4) && ($minor == 1)){ + if (! ($buildNumber =~ /^B99\.16/)) { + # it's not a 4.1 Netscape Directory Server => it's a 4.11 + $minor = 11 ; + } + } + chdir($curdir) or die "Could not change directory to $curdir: $!" ; + return ( $version, $minor ); +} + +############################################################################################### +# get current directory + +sub getCwd { + my $command = $isNT ? "cd" : "/bin/pwd"; + open(PWDCMD, "$command 2>&1 |") or + die "Error: could not execute $command: $!"; + # without the following sleep, reading from the pipe will + # return nothing; I guess it gives the pwd command time + # to get some data to read . . . + sleep(1); + my $currentdir; + while (<PWDCMD>) { + if (!$currentdir) { + chomp($currentdir = $_); + } + } + my $code = close(PWDCMD); +# if ($code || $?) { +# print "$command returned code=$code status=$? dir=$curdir\n"; +# } +# print "getCwd curdir=\[$curdir\]\n"; + return $currentdir; +} diff --git a/ldap/admin/src/scripts/template-migrateInstance6 b/ldap/admin/src/scripts/template-migrateInstance6 new file mode 100644 index 00000000..faaf6363 --- /dev/null +++ b/ldap/admin/src/scripts/template-migrateInstance6 @@ -0,0 +1,550 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +use Time::localtime; + +BEGIN { + require 'uname.lib'; + $| = 1; + $isNT = -d '\\'; + $PATHSEP = $isNT ? "\\" : "/"; + $SEP = $isNT ? ";" : ":" ; + $exitCode = 0; + @INC = ( '.', '../../../admin/admin/bin'); + grep { s@/@\\@g } @INC if $isNT; + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + # NT needs quotes around some things unix doesn't + $quote = $isNT ? "\"" : ""; + if ($isNT) { + # we have to pass batch files directly to the NT command interpreter + $com_spec = $ENV{ComSpec}; + if (!$com_spec) { + $com_spec = $ENV{COMSPEC}; + } + if (!$com_spec || ! -f $com_spec) { + # find the first available command interpreter + foreach $drive (c..z) { + $com_spec = "$drive:\\winnt\\system32\\cmd.exe"; + last if (-f $com_spec); + $com_spec = undef; + } + if (! $com_spec) { + # punt and pray + $com_spec = 'c:\winnt\system32\cmd.exe'; + } + } + $os = "WINNT"; + } else { + $os = &uname("-s"); + if ($os eq "SunOS") { + $isSolaris9 = ( &uname("-r") eq "5.9" ); + } + } + + if ( ($os eq "AIX") || ($os eq "HP-UX") ) { + $sigChildHandler = 'sigChildHandler'; + } + SWITCH: { + if ($os eq "AIX") { + $LIB_PATH = "LIBPATH" ; + last SWITCH ; + } + if ($os eq "HP-UX") { + $LIB_PATH = "SHLIB_PATH" ; + last SWITCH ; + } + if ($isNT) { + $LIB_PATH = "PATH" ; + last SWITCH ; + } + else { + $LIB_PATH = "LD_LIBRARY_PATH" ; + last SWITCH ; + } + } + $slapdExecName = $isNT ? 'slapd.exe' : 'ns-slapd'; + select STDERR; + $| = 1; + select STDOUT; + $| = 1; +} + + + +$TRACELEVEL = 0; +${root} = "{{DS-ROOT}}" ; +${type} = "" ; +${newname} = "" ; +${newport} = "" ; +${rootDN} = "" ; +${rootpwd} = "" ; +${localhost} = "" ; +${LogFileReport} = "" ; + +# get input users +&getParameters() ; + + +${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ; +${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ; +${oldSlapdConf} = "${oldConfDir}slapd.conf" ; +${serverHome} = "${root}${PATHSEP}$type-$newname" ; +${ldif_rep} = "${oldConfDir}ldif${PATHSEP}" ; +${curdir} = getCwd(); + + +if (!(-d $serverHome)) { + print("\n$serverHome doesn't exist\n"); + exit(1); + } + if (!(-d $oldHome)) { + print("\n$oldHome doesn't exist\n"); + exit(1); + } +if ($olddatadir && !(-d $olddatadir)) { + print("\n$olddatadir doesn't exist\n"); + exit(1); + } +$ENV{"$LIB_PATH"} = "$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"} ; +if ($isSolaris9) { + $ENV{"$LIB_PATH"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.6.1${PATHSEP}lib${PATHSEP}sun4-solaris${PATHSEP}CORE${SEP}".$ENV{"$LIB_PATH"} ; +} + +if ($isNT) { + $ENV{"PERL5LIB"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.6.1${PATHSEP}site${PATHSEP}lib${SEP}".$ENV{"PERL5LIB"} ; +} +else { + $ENV{"PERL5LIB"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.6.1${PATHSEP}lib${PATHSEP}site${SEP}".$ENV{"PERL5LIB"} ; +} + +# get the version of the DS to migrate +($oldVersion, $oldMinor) = &getVersion($oldDir, $oldversionstr); +# get the version of the new DS +($Version, $Minor) = &getVersion($root); + +if ($Version >= 6) { + if ($oldVersion == 4) { + $myscript = "migrateTo6" ; + printMsg("\n******* Migration from $oldVersion.$oldMinor to $Version.$Minor Directory Server *********\n"); + } + elsif ($oldVersion == 5 ) { + printMsg("\nWarning. You may experience some problems if the version of directory server you want to migrate is not a 5.0 or 5.1") if ($oldMinor > 1); + $myscript = "migrate5to6" ; + printMsg("\n******* Migration from $oldVersion.$oldMinor to $Version.$Minor Directory Server *********\n"); + } else { + die "We don't support the version of directory server you want to migrate"; + } +} +else { + die "\n\nThe version of directory you want to upgrade is not a 6.x product\nMigration aborted\n"; +} + +my $start_time = gmtime ; +@args = ($^X, $myscript, @ARGV, '-L', $LogFileReport); +$exitCode = &mySystem(@args); +#die "Error: @args: $!" if ($exitCode != 0); + +open(LOGFILE,">> $LogFileReport") or die "\nCan't write to $LogFileReport\n$!\n"; +if (! $exitCode) { + my $end_time = gmtime ; + printMsg("-> Migration started at $start_time\n"); + printMsg("-> Migration ended at $end_time\n\n"); +} +printMsg("***********************************************\n\n"); +print("-> The migration report file is available at: $LogFileReport\n\n"); + +close(LOGFILE); + +####################################################################################################################### +sub usage { + print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n"); + print(STDERR " -o oldInstancePath -n newInstancePath [-t tracelevel] \n"); + print(STDERR " [-L logfile] [-noinput]\n"); + print(STDERR "************** parameters in brackets are optionals, others are required **************\n"); + print(STDERR " Opts: -D rootdn - new Directory Manager\n"); + print(STDERR " : -w password - new Directory Manager's password\n"); + print(STDERR " : -w - - Prompt for new Directory Manager's password\n"); + print(STDERR " : -j filename - Read new Directory Manager's password from file\n"); + print(STDERR " : -p port - new Directory Server port\n"); + print(STDERR " : -o oldInstancePath - Path of the old instance to migrate \n"); + print(STDERR " : -n newInstancePath - Path of the new instance\n"); + print(STDERR " : [-d dataPath] - Path to directory containing data files to import into new instance\n"); + print(STDERR " : [-v oldVersion] - Version of old instance (obtained by running $slapdExecName -v\n"); + print(STDERR " : [-t tracelevel] - specify the level of trace (0..3) by default setup to 1\n"); + print(STDERR " : [-L logfile] - specify the file to log the migration report \n"); + print(STDERR " : [-noinput] - no user interventions during migration processing to solve conflicts\n"); + + } + + +####################################################################################################################### +# get input users + +sub getParameters { + my $exit = 0 ; + my $i = 0; + my $pwdfile= ""; + + while ($i <= $#ARGV) { + if ( "$ARGV[$i]" eq "-D" ) { # directory manager + if (! $rootDN) { + $rootDN = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-w") { # password + if (! $rootpwd) { + $rootpwd = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-j") { # password file + if (! $pwdfile) { + $pwdfile = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-o") { # old instance path + if (! $oldHome ) { + $oldHome = $ARGV[++$i] ; + grep { s@\\@/@g } $oldHome if $isNT ; + if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; } + if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) { + $oldDir = $1 ; + $type = $2 ; + $oldname = $3 ; + if ($isNT) { + $oldDir = lc($oldDir) ; + $type = lc($type) ; + $oldname = lc($oldname) ; + $oldHome = lc($oldHome) ; + grep { s@/@\\@g } $oldDir ; + grep { s@/@\\@g } $oldHome ; + } + } + else { + print("\nThe old instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-n") { # 5.x instance path + if (! $serverHome ) { + $serverHome = $ARGV[++$i] ; + grep { s@\\@/@g } $root if $isNT ; + grep { s@\\@/@g } $serverHome if $isNT ; + if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; } + if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) { + $root = $1 if ($1); + $type = $2 ; + $newname = $3 ; + if ($isNT) { + $root = lc($root) ; + $type = lc($type) ; + $newname = lc($newname) ; + $serverHome = lc($serverHome) ; + grep { s@/@\\@g } $root ; + grep { s@/@\\@g } $serverHome ; + } + } + else { + print("\nThe new instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-p") { # 5.x DS port + if (! $newport ) { + $newport = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-d") { # old instance LDIF data dir + if (! $olddatadir ) { + $olddatadir = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-v") { # old version + if (! $oldversionstr ) { + $oldversionstr = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL + my $value = $ARGV[++$i] ; + if ($value =~ /[0-3]/) { + $TRACELEVEL = $value ; + } + else { + print("\nThe tracelevel must belong to 0..3 interval"); + &usage(); + exit(); + } + } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing + } elsif ("$ARGV[$i]" eq "-L") { # user defined logfile for the migration + $LogFileReport = $ARGV[++$i]; + } + else { + &usage() ; + exit(1); + } + $i++; + } + + if (! $rootDN) { + print("\nThe rootDN is missing"); + $exit = 1; + } + if ($pwdfile ne "") { + # Open file and get the password + unless (open (RPASS, $pwfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $rootpwd = <RPASS>; + chomp($rootpwd); + close(RPASS); + } elsif ($rootpwd eq "-"){ + # Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; + # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $rootpwd = ReadLine(0); +# chomp($rootpwd); +# ReadMode('normal'); + } + if (! $rootpwd) { + print("\nThe rootpwd is missing"); + $exit = 1 ; + } + if (! $newport) { + print("\nThe port is missing"); + $exit = 1; + } + if (! $serverHome) { + print("\nThe new instance path is missing"); + $exit = 1; + } + if (! $oldHome) { + print("\nThe old instance path is missing"); + $exit = 1; + } + if ((! $LogFileReport) && $serverHome) { + ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime(); + $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log"; + } + if ($exit) { + &usage() ; + exit(1); + } + +} + +############################################################################# +# printMsg print message to the user standard output. + +sub printMsg { + + my $TypeMsg = shift ; + my $Msg = shift ; + my $LineNb = shift ; + if ($LineNb) { + printTrace("Line: $LineNb, $TypeMsg, $Msg"); + } + else { + printTrace("$TypeMsg $Msg"); + } +} + +############################################################################# +# print message error to the user standard output. + +sub printTrace { + + my $Msg = shift ; + my $level = shift ; + if ($level <= $TRACELEVEL) { + print($Msg); + print LOGFILE $Msg; + } + +} + +############################################################################# +sub mySystem { + my $cmd = $_[0]; + # the system {$cmd} avoids some NT shell quoting problems if the $cmd + # needs to be quoted e.g. contains spaces; the map puts double quotes + # around the arguments on NT which are stripped by the command + # interpreter cmd.exe; but don't quote things which are already quoted + my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @_; + my $rc = 0; + if ($cmd =~ /[.](bat|cmd)$/) { + # we have to pass batch files directly to the NT command interpreter + $cmd = $com_spec; +# print "system $cmd /c \"@fixargs\"\n"; + $rc = system {$cmd} '/c', "\"@fixargs\""; + } else { +# print "system $cmd \"@fixargs\"\n"; + if($isNT) { + $rc = system "\"@fixargs\""; + } else { + $rc = system @fixargs; + } + } + + return $rc; +} + +############################################################################# + +sub GetTime { + my $tm = localtime; + (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900); + $sec = "0$sec" unless $sec > 9 ; + $min = "0$min" unless $min > 9 ; + $hour = "0$hour" unless $hour > 9 ; + $dd = "0$dd" unless $dd > 9 ; + $mm = "0$mm" unless $mm > 9 ; + return ($sec, $min, $hour, $dd, $mm, $yy); +} + +############################################################################# + +sub getVersion { + my $dir = shift; + my $versionstr = shift; + my $version = 0; + my $minor = 0; + my $buildNumber = 0; + my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}"; + + # find the slapd executable + if (!$versionstr) { # version not specified on cmd line - find it + $prog = $dir . $progDir . $slapdExecName; + if (! -f $prog) { + $prog = $dir . $progDir2 . $slapdExecName; + if (-f $prog && $isNT) { + # if slapd is in bin/slapd and we're on NT, just assume version 1; + # apparently, slapd.exe doesn't like the -v argument . . . + return ( '1', $minor ); + } + else{ + die "Could not run slapd program $prog: $!"; + } + } + else { + chdir($dir . $progDir); + } + $ENV{"$LIB_PATH"}= + "$dir${PATHSEP}lib${SEP}". + "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}". + "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}". + $ENV{"$LIB_PATH"}; + # read the old version from the old slapd program + + open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or + die "Could not run slapd program $prog: $!"; + sleep(1); # allow some data to accumulate in the pipe +# print "Output from $prog -v:\n"; + while (<F>) { + if (/^Netscape-Directory/ || /^iPlanet-Directory/i) { + $versionstr = $_; + last; + } + } + $code = close(F); + # print "$prog returned code=$code status=$?\n"; + $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + } + + if ($versionstr =~ /^Netscape-Directory\/(\d+)\.(\d+)(?:b\d)*\s+(\S+)/) { + $version = $1; + $minor = $2; + $buildNumber = $3; + } + elsif ($versionstr =~ /^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ... + $version = $1; + $minor = $2; + $buildNumber = $3; + } + elsif ($versionstr =~ /^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) { + $version = $1; + $minor = $2; + $buildNumber = $3; + } elsif ($versionstr =~ /(\d+)\.(\d+)/) { + $version = $1; + $minor = $2; + } + + if ($version == 0) { + die "\nCould not determine version of the directory server in $dir: \n"; + } + + # distinguish the 4.1 and the 4.11 thanks to the buildNumber + if (($version == 4) && ($minor == 1)){ + if (! ($buildNumber =~ /^B99\.16/)) { + # it's not a 4.1 Netscape Directory Server => it's a 4.11 + $minor = 11 ; + } + } + chdir($curdir) or die "Could not change directory to $curdir: $!" ; + return ( $version, $minor ); +} + +############################################################################################### +# get current directory + +sub getCwd { + my $command = $isNT ? "cd" : "/bin/pwd"; + open(PWDCMD, "$command 2>&1 |") or + die "Error: could not execute $command: $!"; + # without the following sleep, reading from the pipe will + # return nothing; I guess it gives the pwd command time + # to get some data to read . . . + sleep(1); + my $currentdir; + while (<PWDCMD>) { + if (!$currentdir) { + chomp($currentdir = $_); + } + } + my $code = close(PWDCMD); +# if ($code || $?) { +# print "$command returned code=$code status=$? dir=$curdir\n"; +# } +# print "getCwd curdir=\[$curdir\]\n"; + return $currentdir; +} diff --git a/ldap/admin/src/scripts/template-migrateInstance7 b/ldap/admin/src/scripts/template-migrateInstance7 new file mode 100644 index 00000000..2a754b10 --- /dev/null +++ b/ldap/admin/src/scripts/template-migrateInstance7 @@ -0,0 +1,559 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +use Time::localtime; + +BEGIN { + require 'uname.lib'; + $| = 1; + $isNT = -d '\\'; + $PATHSEP = $isNT ? "\\" : "/"; + $SEP = $isNT ? ";" : ":" ; + $exitCode = 0; + @INC = ( '.', '../../../admin/admin/bin'); + grep { s@/@\\@g } @INC if $isNT; + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + # NT needs quotes around some things unix doesn't + $quote = $isNT ? "\"" : ""; + if ($isNT) { + # we have to pass batch files directly to the NT command interpreter + $com_spec = $ENV{ComSpec}; + if (!$com_spec) { + $com_spec = $ENV{COMSPEC}; + } + if (!$com_spec || ! -f $com_spec) { + # find the first available command interpreter + foreach $drive (c..z) { + $com_spec = "$drive:\\winnt\\system32\\cmd.exe"; + last if (-f $com_spec); + $com_spec = undef; + } + if (! $com_spec) { + # punt and pray + $com_spec = 'c:\winnt\system32\cmd.exe'; + } + } + $os = "WINNT"; + } else { + $os = &uname("-s"); + if ($os eq "SunOS") { + $isSolaris9 = ( &uname("-r") eq "5.9" ); + } + } + + if ( ($os eq "AIX") || ($os eq "HP-UX") ) { + $sigChildHandler = 'sigChildHandler'; + } + SWITCH: { + if ($os eq "AIX") { + $LIB_PATH = "LIBPATH" ; + last SWITCH ; + } + if ($os eq "HP-UX") { + $LIB_PATH = "SHLIB_PATH" ; + last SWITCH ; + } + if ($isNT) { + $LIB_PATH = "PATH" ; + last SWITCH ; + } + else { + $LIB_PATH = "LD_LIBRARY_PATH" ; + last SWITCH ; + } + } + $slapdExecName = $isNT ? 'slapd.exe' : 'ns-slapd'; + select STDERR; + $| = 1; + select STDOUT; + $| = 1; +} + + + +$TRACELEVEL = 0; +${root} = "{{DS-ROOT}}" ; +${type} = "" ; +${newname} = "" ; +${newport} = "" ; +${rootDN} = "" ; +${rootpwd} = "" ; +${localhost} = "" ; +${LogFileReport} = "" ; + +# get input users +&getParameters() ; + + +${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ; +${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ; +${oldSlapdConf} = "${oldConfDir}slapd.conf" ; +${serverHome} = "${root}${PATHSEP}$type-$newname" ; +${ldif_rep} = "${oldConfDir}ldif${PATHSEP}" ; +${curdir} = getCwd(); + + +if (!(-d $serverHome)) { + print("\n$serverHome doesn't exist\n"); + exit(1); + } + if (!(-d $oldHome)) { + print("\n$oldHome doesn't exist\n"); + exit(1); + } +if ($olddatadir && !(-d $olddatadir)) { + print("\n$olddatadir doesn't exist\n"); + exit(1); + } +$ENV{"$LIB_PATH"} = "$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"} ; +if ($isSolaris9) { + $ENV{"$LIB_PATH"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.6.1${PATHSEP}lib${PATHSEP}sun4-solaris${PATHSEP}CORE${SEP}".$ENV{"$LIB_PATH"} ; +} + +if ($isNT) { + $ENV{"PERL5LIB"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.6.1${PATHSEP}site${PATHSEP}lib${SEP}".$ENV{"PERL5LIB"} ; +} +else { + $ENV{"PERL5LIB"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.6.1${PATHSEP}lib${PATHSEP}site${SEP}".$ENV{"PERL5LIB"} ; +} + +# get the version of the DS to migrate +($oldVersion, $oldMinor) = &getVersion($oldDir, $oldversionstr); +# get the version of the new DS +($Version, $Minor) = &getVersion($root); + +if ($Version >= 7) { + if ($oldVersion == 4) { + $myscript = "migrateTo7" ; + printMsg("\n******* Migration from $oldVersion.$oldMinor to $Version.$Minor Directory Server *********\n"); + } + elsif ($oldVersion == 5 ) { + printMsg("\nWarning. You may experience some problems if the version of directory server you want to migrate is not a 5.0 or 5.1") if ($oldMinor > 1); + $myscript = "migrate5to7" ; + printMsg("\n******* Migration from $oldVersion.$oldMinor to $Version.$Minor Directory Server *********\n"); + } + elsif ($oldVersion == 6 ) { + $myscript = "migrate6to7" ; + printMsg("\n******* Migration from $oldVersion.$oldMinor to $Version.$Minor Directory Server *********\n"); + } + else { + + die "We don't support the version of directory server you want to migrate"; + } +} +else { + die "\n\nThe version of directory you want to upgrade is not a 7.x product\nMigration aborted\n"; +} + +my $start_time = gmtime ; +@args = ($^X, $myscript, @ARGV, '-L', $LogFileReport); +$exitCode = &mySystem(@args); +#die "Error: @args: $!" if ($exitCode != 0); + +open(LOGFILE,">> $LogFileReport") or die "\nCan't write to $LogFileReport\n$!\n"; +if (! $exitCode) { + my $end_time = gmtime ; + printMsg("-> Migration started at $start_time\n"); + printMsg("-> Migration ended at $end_time\n\n"); +} +printMsg("***********************************************\n\n"); +print("-> The migration report file is available at: $LogFileReport\n\n"); + +close(LOGFILE); + +####################################################################################################################### +sub usage { + print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n"); + print(STDERR " -o oldInstancePath -n newInstancePath [-t tracelevel] \n"); + print(STDERR " [-L logfile] [-noinput]\n"); + print(STDERR "************** parameters in brackets are optionals, others are required **************\n"); + print(STDERR " Opts: -D rootdn - new Directory Manager\n"); + print(STDERR " : -w password - new Directory Manager's password\n"); + print(STDERR " : -w - - Prompt for new Directory Manager's password\n"); + print(STDERR " : -j filename - Read new Directory Manager's password from file\n"); + print(STDERR " : -p port - new Directory Server port\n"); + print(STDERR " : -o oldInstancePath - Path of the old instance to migrate \n"); + print(STDERR " : -n newInstancePath - Path of the new instance\n"); + print(STDERR " : [-d dataPath] - Path to directory containing data files to import into new instance\n"); + print(STDERR " : [-v oldVersion] - Version of old instance (obtained by running $slapdExecName -v\n"); + print(STDERR " : [-t tracelevel] - specify the level of trace (0..3) by default setup to 1\n"); + print(STDERR " : [-L logfile] - specify the file to log the migration report \n"); + print(STDERR " : [-noinput] - no user interventions during migration processing to solve conflicts\n"); + + } + + +####################################################################################################################### +# get input users + +sub getParameters { + my $exit = 0 ; + my $i = 0; + my $pwdfile= ""; + + while ($i <= $#ARGV) { + if ( "$ARGV[$i]" eq "-D" ) { # directory manager + if (! $rootDN) { + $rootDN = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-w") { # password + if (! $rootpwd) { + $rootpwd = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-j") { # password file + if (! $pwdfile) { + $pwdfile = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-o") { # old instance path + if (! $oldHome ) { + $oldHome = $ARGV[++$i] ; + grep { s@\\@/@g } $oldHome if $isNT ; + if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; } + if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) { + $oldDir = $1 ; + $type = $2 ; + $oldname = $3 ; + if ($isNT) { + $oldDir = lc($oldDir) ; + $type = lc($type) ; + $oldname = lc($oldname) ; + $oldHome = lc($oldHome) ; + grep { s@/@\\@g } $oldDir ; + grep { s@/@\\@g } $oldHome ; + } + } + else { + print("\nThe old instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-n") { # 5.x instance path + if (! $serverHome ) { + $serverHome = $ARGV[++$i] ; + grep { s@\\@/@g } $root if $isNT ; + grep { s@\\@/@g } $serverHome if $isNT ; + if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; } + if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) { + $root = $1 if ($1); + $type = $2 ; + $newname = $3 ; + if ($isNT) { + $root = lc($root) ; + $type = lc($type) ; + $newname = lc($newname) ; + $serverHome = lc($serverHome) ; + grep { s@/@\\@g } $root ; + grep { s@/@\\@g } $serverHome ; + } + } + else { + print("\nThe new instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-p") { # 5.x DS port + if (! $newport ) { + $newport = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-d") { # old instance LDIF data dir + if (! $olddatadir ) { + $olddatadir = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-v") { # old version + if (! $oldversionstr ) { + $oldversionstr = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL + my $value = $ARGV[++$i] ; + if ($value =~ /[0-3]/) { + $TRACELEVEL = $value ; + } + else { + print("\nThe tracelevel must belong to 0..3 interval"); + &usage(); + exit(); + } + } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing + } elsif ("$ARGV[$i]" eq "-L") { # user defined logfile for the migration + $LogFileReport = $ARGV[++$i]; + } + else { + &usage() ; + exit(1); + } + $i++; + } + + if (! $rootDN) { + print("\nThe rootDN is missing"); + $exit = 1; + } + if ($pwdfile ne "") { + # Open file and get the password + unless (open (RPASS, $pwfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $rootpwd = <RPASS>; + chomp($rootpwd); + close(RPASS); + } elsif ($rootpwd eq "-"){ + # Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; + # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $rootpwd = ReadLine(0); +# chomp($rootpwd); +# ReadMode('normal'); + } + if (! $rootpwd) { + print("\nThe rootpwd is missing"); + $exit = 1 ; + } + if (! $newport) { + print("\nThe port is missing"); + $exit = 1; + } + if (! $serverHome) { + print("\nThe new instance path is missing"); + $exit = 1; + } + if (! $oldHome) { + print("\nThe old instance path is missing"); + $exit = 1; + } + if ((! $LogFileReport) && $serverHome) { + ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime(); + $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log"; + } + if ($exit) { + &usage() ; + exit(1); + } + +} + +############################################################################# +# printMsg print message to the user standard output. + +sub printMsg { + + my $TypeMsg = shift ; + my $Msg = shift ; + my $LineNb = shift ; + if ($LineNb) { + printTrace("Line: $LineNb, $TypeMsg, $Msg"); + } + else { + printTrace("$TypeMsg $Msg"); + } +} + +############################################################################# +# print message error to the user standard output. + +sub printTrace { + + my $Msg = shift ; + my $level = shift ; + if ($level <= $TRACELEVEL) { + print($Msg); + print LOGFILE $Msg; + } + +} + +############################################################################# +sub mySystem { + my $cmd = $_[0]; + # the system {$cmd} avoids some NT shell quoting problems if the $cmd + # needs to be quoted e.g. contains spaces; the map puts double quotes + # around the arguments on NT which are stripped by the command + # interpreter cmd.exe; but don't quote things which are already quoted + my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @_; + my $rc = 0; + if ($cmd =~ /[.](bat|cmd)$/) { + # we have to pass batch files directly to the NT command interpreter + $cmd = $com_spec; +# print "system $cmd /c \"@fixargs\"\n"; + $rc = system {$cmd} '/c', "\"@fixargs\""; + } else { +# print "system $cmd \"@fixargs\"\n"; + if($isNT) { + $rc = system "\"@fixargs\""; + } else { + $rc = system @fixargs; + } + } + + return $rc; +} + +############################################################################# + +sub GetTime { + my $tm = localtime; + (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900); + $sec = "0$sec" unless $sec > 9 ; + $min = "0$min" unless $min > 9 ; + $hour = "0$hour" unless $hour > 9 ; + $dd = "0$dd" unless $dd > 9 ; + $mm = "0$mm" unless $mm > 9 ; + return ($sec, $min, $hour, $dd, $mm, $yy); +} + +############################################################################# + +sub getVersion { + my $dir = shift; + my $versionstr = shift; + my $version = 0; + my $minor = 0; + my $buildNumber = 0; + my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}"; + + # find the slapd executable + if (!$versionstr) { # version not specified on cmd line - find it + $prog = $dir . $progDir . $slapdExecName; + if (! -f $prog) { + $prog = $dir . $progDir2 . $slapdExecName; + if (-f $prog && $isNT) { + # if slapd is in bin/slapd and we're on NT, just assume version 1; + # apparently, slapd.exe doesn't like the -v argument . . . + return ( '1', $minor ); + } + else{ + die "Could not run slapd program $prog: $!"; + } + } + else { + chdir($dir . $progDir); + } + $preserve_lib_path = $ENV{"$LIB_PATH"}; + $ENV{"$LIB_PATH"}= + "$dir${PATHSEP}lib${SEP}". + "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}". + "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}". + $ENV{"$LIB_PATH"}; + # read the old version from the old slapd program + + open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or + die "Could not run slapd program $prog: $!"; + sleep(1); # allow some data to accumulate in the pipe +# print "Output from $prog -v:\n"; + while (<F>) { + if (/^Netscape-Directory/ || /^iPlanet-Directory/i) { + $versionstr = $_; + last; + } + } + $code = close(F); + # print "$prog returned code=$code status=$?\n"; + $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + } + + if ($versionstr =~ /^Netscape-Directory\/(\d+)\.(\d+)(?:b\d)*\s+(\S+)/) { + $version = $1; + $minor = $2; + $buildNumber = $3; + } + elsif ($versionstr =~ /^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ... + $version = $1; + $minor = $2; + $buildNumber = $3; + } + elsif ($versionstr =~ /^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) { + $version = $1; + $minor = $2; + $buildNumber = $3; + } elsif ($versionstr =~ /(\d+)\.(\d+)/) { + $version = $1; + $minor = $2; + } + + if ($version == 0) { + die "\nCould not determine version of the directory server in $dir: \n"; + } + + # distinguish the 4.1 and the 4.11 thanks to the buildNumber + if (($version == 4) && ($minor == 1)){ + if (! ($buildNumber =~ /^B99\.16/)) { + # it's not a 4.1 Netscape Directory Server => it's a 4.11 + $minor = 11 ; + } + } + # Restore the original library path + $ENV{"$LIB_PATH"} = $preserve_lib_path; + chdir($curdir) or die "Could not change directory to $curdir: $!" ; + return ( $version, $minor ); +} + +############################################################################################### +# get current directory + +sub getCwd { + my $command = $isNT ? "cd" : "/bin/pwd"; + open(PWDCMD, "$command 2>&1 |") or + die "Error: could not execute $command: $!"; + # without the following sleep, reading from the pipe will + # return nothing; I guess it gives the pwd command time + # to get some data to read . . . + sleep(1); + my $currentdir; + while (<PWDCMD>) { + if (!$currentdir) { + chomp($currentdir = $_); + } + } + my $code = close(PWDCMD); +# if ($code || $?) { +# print "$command returned code=$code status=$? dir=$curdir\n"; +# } +# print "getCwd curdir=\[$curdir\]\n"; + return $currentdir; +} diff --git a/ldap/admin/src/scripts/template-migrateTo5 b/ldap/admin/src/scripts/template-migrateTo5 new file mode 100755 index 00000000..f02a6279 --- /dev/null +++ b/ldap/admin/src/scripts/template-migrateTo5 @@ -0,0 +1,3094 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# Migrate a 4.0 directory server to a 5.x directory server + +######################################################################################################## +# enable the use of Perldap functions +require DynaLoader; + +use Getopt::Std; +use Mozilla::LDAP::Conn; +use Mozilla::LDAP::Entry; +use Mozilla::LDAP::LDIF; +use Mozilla::LDAP::Utils qw(:all); +use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API +use Time::localtime; + +######################################################################################################## +use Class::Struct ; # load struct-building module + +struct S_index => { + names => '@' , + types => '@' , + oids => '@' , + specific => '$' + }; + + +struct S_plugin => { + name => '$' , + type => '$' , + enable => '$' , + args => '@' + }; +##################################################################################################### + +sub usage { + print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n"); + print(STDERR " -o 4.xInstancePath -n 5.xInstancePath [-t tracelevel] [-L logfile]\n"); + print(STDERR "************** parameters in brackets are optionals, others are required **************\n"); + print(STDERR " Opts: -D rootdn - 5.x Directory Manager\n"); + print(STDERR " : -w password - 5.x Directory Manager's password\n"); + print(STDERR " : -w - - Prompt for 5.x Directory Manager's password\n"); + print(STDERR " : -j filename - Read 5.x Directory Manager's password from file\n"); + print(STDERR " : -p port - 5.x Directory Server port\n"); + print(STDERR " : -o 4.xInstancePath - Path of the 4.x instance to migrate \n"); + print(STDERR " : -n 5.xInstancePath - Path of the new 5.x instance\n"); + print(STDERR " : [-t tracelevel] - specify the level of trace (0..3)\n"); + print(STDERR " : [-L logfile] - specify the file to log the migration report \n"); + + + } + + + +############# +BEGIN { + + require 'uname.lib' ; + $isNT = -d '\\'; + $PATHSEP = $isNT ? "\\" : "/"; + ${SEP} = $isNT ? ";" : ":" ; + @INC = ( '.', '../../../admin/admin/bin'); + grep { s@/@\\@g } @INC if $isNT; + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + # NT needs quotes around some things unix doesn't + $quote = $isNT ? "\"" : ""; + + # If this variable is set, all file/directory creation will make sure the mode + # and ownership of the destination is the same as the source + $PRESERVE = 1 if (!$isNT); + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + if ($isNT) { + $os = "WINNT"; + } else { + $os = &uname("-s"); + } + if ($isNT) { + # we have to pass batch files directly to the NT command interpreter + $com_spec = $ENV{ComSpec}; + if (!$com_spec) { + $com_spec = $ENV{COMSPEC}; + } + if (!$com_spec || ! -f $com_spec) { + # find the first available command interpreter + foreach $drive (c..z) { + $com_spec = "$drive:\\winnt\\system32\\cmd.exe"; + last if (-f $com_spec); + $com_spec = undef; + } + if (! $com_spec) { + # punt and pray + $com_spec = 'c:\winnt\system32\cmd.exe'; + } + } + } + if ( $os eq "AIX" ) { + $dll_suffix = "_shr.a"; + } + elsif ( $os eq "HP-UX" ) { + $dll_suffix = ".sl"; + } + elsif ( $os eq "WINNT" ) { + $dll_suffix = ".dll"; + } + else { + $dll_suffix = ".so"; + } + $slapdExecName = $isNT ? 'slapd.exe' : 'ns-slapd'; + # if this flag is set, we will migrate the 4.x database + # by doing a db2ldif -> ldif2db; + $convertToLDIF = 1; + select STDERR; + $| = 1; + select STDOUT; + $| = 1; + # if the old value for dbcachesize is less than this, make it this + $MIN_DBCACHESIZE = '500000'; +} + +SWITCH: { + if ($os eq "AIX") { + $LIB_PATH = "LIBPATH" ; + last SWITCH ; + } + if ($os eq "HP-UX") { + $LIB_PATH = "SHLIB_PATH" ; + last SWITCH ; + } + if ($isNT) { + $LIB_PATH = "PATH" ; + last SWITCH ; + } + else { + $LIB_PATH = "LD_LIBRARY_PATH" ; + last SWITCH ; + } + } + + # 4.x parameters + ${oldDir} = "" ; + ${oldname} = "" ; + ${oldHome} = "" ; + ${oldConfDir} = "" ; + ${oldlocaluser} ; + ${olduid} ; + ${oldgid} ; + + # 5.x parameters + ${root} = "{{DS-ROOT}}" ; + ${type} = "" ; + ${newname} = "" ; + ${newport} = "" ; + ${rootDN} = "" ; + ${rootpwd} = "" ; + ${localhost} = "" ; + ${LogFileReport} = "" ; + ${newuid} ; + ${localuser} ; + ${newgid} ; + $NO_INPUT_USER = 0 ; # by default user can give inputs during the migration process + ${curdir} = getCwd(); + ${slapdExecDir} = "${root}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + + # specify the level of trace + $TRACELEVEL=1; + + # get input users + &getParameters() ; + ${oldDir} = &normalizeDir("${oldDir}"); + ${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ; + ${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ; + ${oldSlapdConf} = "${oldConfDir}slapd.conf" ; + ${oldDSEldif} = "${oldConfDir}dse.ldif" ; + ${serverHome} = "${root}${PATHSEP}$type-$newname" ; + ${DSEldif} = "$serverHome${PATHSEP}config${PATHSEP}dse.ldif"; + ${ldif_rep} = "${oldConfDir}${PATHSEP}ldif${PATHSEP}" ; + ${oldSlapdExecDir} = "${oldDir}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + + + + + open(LOGFILE, ">> $LogFileReport"); + + printTrace("\noldDir: $oldDir, oldHome: $oldHome, \noldConfDir: $oldConfDir, \noldSlapdConf: $oldSlapdConf, \nldif_rep: $ldif_rep, \nrootDN: $rootDN, \nPwd: ******, \nPort: $newport, \nNewname: $newname\n",3); + printTrace("\nLIB_PATH: $LIB_PATH",4); + + if (!(-d $serverHome)) { + printMsg("\n$serverHome doesn't exist\n"); + exit(1); + } + if (!(-d $oldHome)) { + printMsg("\n$oldHome doesn't exist\n"); + exit(1); + } + +#define CONFIG_DATABASE_DIRECTIVE "database" +#define CONFIG_DATABASE_ATTRIBUTE "nsslapd-database" +#define CONFIG_PLUGIN_DIRECTIVE "plugin" +#define CONFIG_PLUGIN_ATTRIBUTE "nsslapd-plugin" +#define CONFIG_SIZELIMIT_DIRECTIVE "sizelimit" +#define CONFIG_SIZELIMIT_ATTRIBUTE "nsslapd-sizelimit" +#define CONFIG_ORCAUTO_DIRECTIVE "orcauto" +#define CONFIG_ORCAUTO_ATTRIBUTE "nsslapd-orcauto" +#define CONFIG_TIMELIMIT_DIRECTIVE "timelimit" +#define CONFIG_TIMELIMIT_ATTRIBUTE "nsslapd-timelimit" +#define CONFIG_SUFFIX_DIRECTIVE "suffix" +#define CONFIG_SUFFIX_ATTRIBUTE "nsslapd-suffix" +#define CONFIG_READONLY_DIRECTIVE "readonly" +#define CONFIG_READONLY_ATTRIBUTE "nsslapd-readonly" +#define CONFIG_REFERRAL_DIRECTIVE "referral" +#define CONFIG_REFERRAL_ATTRIBUTE "nsslapd-referral" +#define CONFIG_OBJECTCLASS_DIRECTIVE "objectclass" +#define CONFIG_OBJECTCLASS_ATTRIBUTE "nsslapd-objectclass" +#define CONFIG_ATTRIBUTE_DIRECTIVE "attribute" +#define CONFIG_ATTRIBUTE_ATTRIBUTE "nsslapd-attribute" +#define CONFIG_SCHEMACHECK_DIRECTIVE "schemacheck" +#define CONFIG_SCHEMACHECK_ATTRIBUTE "nsslapd-schemacheck" +#define CONFIG_LOGLEVEL_DIRECTIVE "loglevel" +#define CONFIG_LOGLEVEL_ATTRIBUTE "nsslapd-errorlog-level" +#define CONFIG_ACCESSLOGLEVEL_DIRECTIVE "accessloglevel" +#define CONFIG_ACCESSLOGLEVEL_ATTRIBUTE "nsslapd-accesslog-level" +#define CONFIG_ACCESSLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "accesslog-maxNumOfLogsPerDir" +#define CONFIG_ACCESSLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-accesslog-maxlogsperdir" +#define CONFIG_ERRORLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "errorlog-maxNumOfLogsPerDir" +#define CONFIG_ERRORLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-errorlog-maxlogsperdir" +#define CONFIG_AUDITLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "auditlog-maxNumOfLogsPerDir" +#define CONFIG_AUDITLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-auditlog-maxlogsperdir" +#define CONFIG_ACCESSLOG_MAXLOGSIZE_DIRECTIVE "accesslog-maxlogsize" +#define CONFIG_ACCESSLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-accesslog-maxlogsize" +#define CONFIG_ERRORLOG_MAXLOGSIZE_DIRECTIVE "errorlog-maxlogsize" +#define CONFIG_ERRORLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-errorlog-maxlogsize" +#define CONFIG_AUDITLOG_MAXLOGSIZE_DIRECTIVE "auditlog-maxlogsize" +#define CONFIG_AUDITLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-auditlog-maxlogsize" +#define CONFIG_ACCESSLOG_LOGROTATIONTIME_DIRECTIVE "accesslog-logrotationtime" +#define CONFIG_ACCESSLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-accesslog-logrotationtime" +#define CONFIG_ERRORLOG_LOGROTATIONTIME_DIRECTIVE "errorlog-logrotationtime" +#define CONFIG_ERRORLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-errorlog-logrotationtime" +#define CONFIG_AUDITLOG_LOGROTATIONTIME_DIRECTIVE "auditlog-logrotationtime" +#define CONFIG_AUDITLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-auditlog-logrotationtime" +#define CONFIG_ACCESSLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "accesslog-logrotationtimeunit" +#define CONFIG_ACCESSLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-accesslog-logrotationtimeunit" +#define CONFIG_ERRORLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "errorlog-logrotationtimeunit" +#define CONFIG_ERRORLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-errorlog-logrotationtimeunit" +#define CONFIG_AUDITLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "auditlog-logrotationtimeunit" +#define CONFIG_AUDITLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-auditlog-logrotationtimeunit" +#define CONFIG_ACCESSLOG_MAXLOGDISKSPACE_DIRECTIVE "accesslog-maxlogdiskspace" +#define CONFIG_ACCESSLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-accesslog-logmaxdiskspace" +#define CONFIG_ERRORLOG_MAXLOGDISKSPACE_DIRECTIVE "errorlog-maxlogdiskspace" +#define CONFIG_ERRORLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-errorlog-logmaxdiskspace" +#define CONFIG_AUDITLOG_MAXLOGDISKSPACE_DIRECTIVE "auditlog-maxlogdiskspace" +#define CONFIG_AUDITLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-auditlog-logmaxdiskspace" +#define CONFIG_ACCESSLOG_MINFREEDISKSPACE_DIRECTIVE "accesslog-minfreediskspace" +#define CONFIG_ACCESSLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-accesslog-logminfreediskspace" +#define CONFIG_ERRORLOG_MINFREEDISKSPACE_DIRECTIVE "errorlog-minfreediskspace" +#define CONFIG_ERRORLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-errorlog-logminfreediskspace" +#define CONFIG_AUDITLOG_MINFREEDISKSPACE_DIRECTIVE "auditlog-minfreediskspace" +#define CONFIG_AUDITLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-auditlog-logminfreediskspace" +#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIME_DIRECTIVE "accesslog-logexpirationtime" +#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-accesslog-logexpirationtime" +#define CONFIG_ERRORLOG_LOGEXPIRATIONTIME_DIRECTIVE "errorlog-logexpirationtime" +#define CONFIG_ERRORLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-errorlog-logexpirationtime" +#define CONFIG_AUDITLOG_LOGEXPIRATIONTIME_DIRECTIVE "auditlog-logexpirationtime" +#define CONFIG_AUDITLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-auditlog-logexpirationtime" +#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "accesslog-logexpirationtimeunit" +#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-accesslog-logexpirationtimeunit" +#define CONFIG_ERRORLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "errorlog-logexpirationtimeunit" +#define CONFIG_ERRORLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-errorlog-logexpirationtimeunit" +#define CONFIG_AUDITLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "auditlog-logexpirationtimeunit" +#define CONFIG_AUDITLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-auditlog-logexpirationtimeunit" +#define CONFIG_ACCESSLOG_LOGGING_ENABLED_DIRECTIVE "accesslog-logging-enabled" +#define CONFIG_ACCESSLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-accesslog-logging-enabled" +#define CONFIG_ERRORLOG_LOGGING_ENABLED_DIRECTIVE "errorlog-logging-enabled" +#define CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-errorlog-logging-enabled" +#define CONFIG_AUDITLOG_LOGGING_ENABLED_DIRECTIVE "auditlog-logging-enabled" +#define CONFIG_AUDITLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-auditlog-logging-enabled" +#define CONFIG_ROOTDN_DIRECTIVE "rootdn" +#define CONFIG_ROOTDN_ATTRIBUTE "nsslapd-rootdn" +#define CONFIG_ROOTPW_DIRECTIVE "rootpw" +#define CONFIG_ROOTPW_ATTRIBUTE "nsslapd-rootpw" +#define CONFIG_ROOTPWSTORAGESCHEME_DIRECTIVE "rootpwstoragescheme" +#define CONFIG_ROOTPWSTORAGESCHEME_ATTRIBUTE "nsslapd-rootpwstoragescheme" +#define CONFIG_UPDATEDN_DIRECTIVE "updatedn" +#define CONFIG_UPDATEDN_ATTRIBUTE "nsslapd-updatedn" +#define CONFIG_UPDATEPW_DIRECTIVE "updatepw" +#define CONFIG_UPDATEPW_ATTRIBUTE "nsslapd-updatepw" +#define CONFIG_UPDATESSLCLIENT_DIRECTIVE "updateSSLclient" +#define CONFIG_UPDATESSLCLIENT_ATTRIBUTE "nsslapd-updateSSLclient" +#define CONFIG_AUDITFILE_DIRECTIVE "auditfile" +#define CONFIG_AUDITFILE_ATTRIBUTE "nsslapd-auditlog" +#define CONFIG_LASTMOD_DIRECTIVE "lastmod" +#define CONFIG_LASTMOD_ATTRIBUTE "nsslapd-lastmod" +#define CONFIG_INCLUDE_DIRECTIVE "include" +#define CONFIG_INCLUDE_ATTRIBUTE "nsslapd-include" +#define CONFIG_DYNAMICCONF_DIRECTIVE "dynamicconf" +#define CONFIG_DYNAMICCONF_ATTRIBUTE "nsslapd-dynamicconf" +#define CONFIG_USEROC_DIRECTIVE "useroc" +#define CONFIG_USEROC_ATTRIBUTE "nsslapd-useroc" +#define CONFIG_USERAT_DIRECTIVE "userat" +#define CONFIG_USERAT_ATTRIBUTE "nsslapd-userat" +#define CONFIG_SVRTAB_DIRECTIVE "svrtab" +#define CONFIG_SVRTAB_ATTRIBUTE "nsslapd-svrtab" +#ifndef _WIN32 +#define CONFIG_LOCALUSER_DIRECTIVE "localuser" +#define CONFIG_LOCALUSER_ATTRIBUTE "nsslapd-localuser" +#endif /* !_WIN32 */ +#define CONFIG_LOCALHOST_DIRECTIVE "localhost" +#define CONFIG_LOCALHOST_ATTRIBUTE "nsslapd-localhost" +#define CONFIG_PORT_DIRECTIVE "port" +#define CONFIG_PORT_ATTRIBUTE "nsslapd-port" +#define CONFIG_LISTENHOST_DIRECTIVE "listenhost" +#define CONFIG_LISTENHOST_ATTRIBUTE "nsslapd-listenhost" +#define CONFIG_SECURITY_DIRECTIVE "security" +#define CONFIG_SECURITY_ATTRIBUTE "nsslapd-security" +#define CONFIG_SSL3CIPHERS_DIRECTIVE "SSL3ciphers" +#define CONFIG_SSL3CIPHERS_ATTRIBUTE "nsslapd-SSL3ciphers" +#define CONFIG_ACCESSLOG_DIRECTIVE "accesslog" +#define CONFIG_ACCESSLOG_ATTRIBUTE "nsslapd-accesslog" +#define CONFIG_ERRORLOG_DIRECTIVE "errorlog" +#define CONFIG_ERRORLOG_ATTRIBUTE "nsslapd-errorlog" +#define CONFIG_INSTANCEDIR_DIRECTIVE "instancedir" +#define CONFIG_INSTANCEDIR_ATTRIBUTE "nsslapd-instancedir" +#define CONFIG_SECUREPORT_DIRECTIVE "secure-port" +#define CONFIG_SECUREPORT_ATTRIBUTE "nsslapd-securePort" +#define CONFIG_SECURELISTENHOST_DIRECTIVE "secure-listenhost" +#define CONFIG_SECURELISTENHOST_ATTRIBUTE "nsslapd-securelistenhost" +#define CONFIG_THREADNUMBER_DIRECTIVE "threadnumber" +#define CONFIG_THREADNUMBER_ATTRIBUTE "nsslapd-threadnumber" +#define CONFIG_MAXTHREADSPERCONN_DIRECTIVE "maxthreadsperconn" +#define CONFIG_MAXTHREADSPERCONN_ATTRIBUTE "nsslapd-maxthreadsperconn" +#if !defined(_WIN32) && !defined(AIX) +#define CONFIG_MAXDESCRIPTORS_DIRECTIVE "maxdescriptors" +#define CONFIG_MAXDESCRIPTORS_ATTRIBUTE "nsslapd-maxdescriptors" +#endif /* !_WIN32 && ! AIX */ +#define CONFIG_RESERVEDESCRIPTORS_DIRECTIVE "reservedescriptors" +#define CONFIG_RESERVEDESCRIPTORS_ATTRIBUTE "nsslapd-reservedescriptors" +#define CONFIG_IDLETIMEOUT_DIRECTIVE "idletimeout" +#define CONFIG_IDLETIMEOUT_ATTRIBUTE "nsslapd-idletimeout" +#define CONFIG_IOBLOCKTIMEOUT_DIRECTIVE "ioblocktimeout" +#define CONFIG_IOBLOCKTIMEOUT_ATTRIBUTE "nsslapd-ioblocktimeout" +#define CONFIG_NTSYNCH_DIRECTIVE "ntsynch" +#define CONFIG_NTSYNCH_ATTRIBUTE "nsslapd-NTSynch" +#define CONFIG_NTSYNCHUSESSL_DIRECTIVE "ntsynchusessl" +#define CONFIG_NTSYNCHUSESSL_ATTRIBUTE "nsslapd-NTSynch-SSL" +#define CONFIG_NTSYNCHPORT_DIRECTIVE "ntsynch-port" +#define CONFIG_NTSYNCHPORT_ATTRIBUTE "nsslapd-NTSynch-port" +#define CONFIG_ACCESSCONTROL_DIRECTIVE "accesscontrol" +#define CONFIG_ACCESSCONTROL_ATTRIBUTE "nsslapd-accesscontrol" +#define CONFIG_GROUPEVALNESTLEVEL_DIRECTIVE "groupevalnestlevel" +#define CONFIG_GROUPEVALNESTLEVEL_ATTRIBUTE "nsslapd-groupevalnestlevel" +#define CONFIG_NAGLE_DIRECTIVE "nagle" +#define CONFIG_NAGLE_ATTRIBUTE "nsslapd-nagle" +#define CONFIG_PW_CHANGE_DIRECTIVE "pw_change" +#define CONFIG_PW_CHANGE_ATTRIBUTE "passwordChange" +#define CONFIG_PW_MUSTCHANGE_DIRECTIVE "pw_must_change" +#define CONFIG_PW_MUSTCHANGE_ATTRIBUTE "passwordMustChange" +#define CONFIG_PW_SYNTAX_DIRECTIVE "pw_syntax" +#define CONFIG_PW_SYNTAX_ATTRIBUTE "passwordCheckSyntax" +#define CONFIG_PW_MINLENGTH_DIRECTIVE "pw_minlength" +#define CONFIG_PW_MINLENGTH_ATTRIBUTE "passwordMinLength" +#define CONFIG_PW_EXP_DIRECTIVE "pw_exp" +#define CONFIG_PW_EXP_ATTRIBUTE "passwordExp" +#define CONFIG_PW_MAXAGE_DIRECTIVE "pw_maxage" +#define CONFIG_PW_MAXAGE_ATTRIBUTE "passwordMaxAge" +#define CONFIG_PW_MINAGE_DIRECTIVE "pw_minage" +#define CONFIG_PW_MINAGE_ATTRIBUTE "passwordMinAge" +#define CONFIG_PW_WARNING_DIRECTIVE "pw_warning" +#define CONFIG_PW_WARNING_ATTRIBUTE "passwordWarning" +#define CONFIG_PW_HISTORY_DIRECTIVE "pw_history" +#define CONFIG_PW_HISTORY_ATTRIBUTE "passwordHistory" +#define CONFIG_PW_INHISTORY_DIRECTIVE "pw_inhistory" +#define CONFIG_PW_INHISTORY_ATTRIBUTE "passwordInHistory" +#define CONFIG_PW_LOCKOUT_DIRECTIVE "pw_lockout" +#define CONFIG_PW_LOCKOUT_ATTRIBUTE "passwordLockout" +#define CONFIG_PW_STORAGESCHEME_DIRECTIVE "pw_storagescheme" +#define CONFIG_PW_STORAGESCHEME_ATTRIBUTE "passwordStorageScheme" +#define CONFIG_PW_MAXFAILURE_DIRECTIVE "pw_maxfailure" +#define CONFIG_PW_MAXFAILURE_ATTRIBUTE "passwordMaxFailure" +#define CONFIG_PW_UNLOCK_DIRECTIVE "pw_unlock" +#define CONFIG_PW_UNLOCK_ATTRIBUTE "passwordUnlock" +#define CONFIG_PW_LOCKDURATION_DIRECTIVE "pw_lockduration" +#define CONFIG_PW_LOCKDURATION_ATTRIBUTE "passwordLockoutDuration" +#define CONFIG_PW_RESETFAILURECOUNT_DIRECTIVE "pw_resetfailurecount" +#define CONFIG_PW_RESETFAILURECOUNT_ATTRIBUTE "passwordResetFailureCount" +#define CONFIG_ACCESSLOG_BUFFERING_DIRECTIVE "logbuffering" +#define CONFIG_ACCESSLOG_BUFFERING_ATTRIBUTE "nsslapd-accesslog-logbuffering" +#define CONFIG_CHANGELOG_DIR_DIRECTIVE "changelogdir" +#define CONFIG_CHANGELOG_DIR_ATTRIBUTE "nsslapd-changelogdir" +#define CONFIG_CHANGELOG_SUFFIX_DIRECTIVE "changelogsuffix" +#define CONFIG_CHANGELOG_SUFFIX_ATTRIBUTE "nsslapd-changelogsuffix" +#define CONFIG_CHANGELOG_MAXENTRIES_DIRECTIVE "changelogmaxextries" +#define CONFIG_CHANGELOG_MAXENTRIES_ATTRIBUTE "nsslapd-changelogmaxentries" +#define CONFIG_CHANGELOG_MAXAGE_DIRECTIVE "changelogmaxage" +#define CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE "nsslapd-changelogmaxage" +#define CONFIG_RETURN_EXACT_CASE_DIRECTIVE "return_exact_case" +#define CONFIG_RESULT_TWEAK_DIRECTIVE "result_tweak" +#define CONFIG_REFERRAL_MODE_DIRECTIVE "referralmode" +#define CONFIG_ATTRIBUTE_NAME_EXCEPTION_DIRECTIVE "attribute_name_exceptions" +#define CONFIG_MAXBERSIZE_DIRECTIVE "maxbersize" +#define CONFIG_VERSIONSTRING_DIRECTIVE "versionstring" +#define CONFIG_ENQUOTE_SUP_OC_DIRECTIVE "enquote_sup_oc" +#define CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE "nsslapd-enquote_sup_oc" +#define CONFIG_BASEDN_DIRECTIVE "certmap-basedn" +#define CONFIG_BASEDN_ATTRIBUTE "nsslapd-certmap-basedn" + +%HashParametersName = (); + +# The following hash displays only general server parameters to migrate under cn=config +%GeneralSrvParamToMigrate = ( + 'accesscontrol' => 'nsslapd-accesscontrol', + 'errorlog-logging-enabled' => 'nsslapd-errorlog-logging-enabled', + 'accesslog-logging-enabled' => 'nsslapd-accesslog-logging-enabled', + 'auditlog-logging-enabled' => 'nsslapd-auditlog-logging-enabled', + 'logbuffering' => 'nsslapd-accesslog-logbuffering', + 'accesslog-logexpirationtime' => 'nsslapd-accesslog-logexpirationtime', + 'accesslog-logexpirationtimeunit' => 'nsslapd-accesslog-logexpirationtimeunit', + 'accesslog-maxlogdiskspace' => 'nsslapd-accesslog-logmaxdiskspace', + 'accesslog-minfreediskspace' => 'nsslapd-accesslog-logminfreediskspace', + 'accesslog-logrotationtime' => 'nsslapd-accesslog-logrotationtime', + 'accesslog-logrotationtimeunit' => 'nsslapd-accesslog-logrotationtimeunit', + 'accesslog-maxlogsize' => 'nsslapd-accesslog-maxlogsize', + 'accesslog-maxnumoflogsperdir' => 'nsslapd-accesslog-maxLogsPerDir', + 'auditlog-logexpirationtime' => 'nsslapd-auditlog-logexpirationtime', + 'auditlog-logexpirationtimeunit' => 'nsslapd-auditlog-logexpirationtimeunit', + 'auditlog-maxlogdiskspace' => 'nsslapd-auditlog-logmaxdiskspace', + 'auditlog-minfreediskspace' => 'nsslapd-auditlog-logminfreediskspace', + 'auditlog-logrotationtime' => 'nsslapd-auditlog-logrotationtime', + 'auditlog-logrotationtimeunit' => 'nsslapd-auditlog-logrotationtimeunit', + 'auditlog-maxlogsize' => 'nsslapd-auditlog-maxlogsize', + 'auditlog-maxnumoflogsperdir' => 'nsslapd-auditlog-maxLogsPerDir', + 'certmap-basedn' => 'nsslapd-certmap-basedn', + 'enquote_sup_oc' => 'nsslapd-enquote-sup-oc', + 'loglevel' => 'nsslapd-errorlog-level', + 'errorlog-logexpirationtime' => 'nsslapd-errorlog-logexpirationtime', + 'errorlog-logexpirationtimeunit' => 'nsslapd-errorlog-logexpirationtimeunit', + 'errorlog-maxlogdiskspace' => 'nsslapd-errorlog-logmaxdiskspace', + 'errorlog-minfreediskspace' => 'nsslapd-errorlog-logminfreediskspace', + 'errorlog-logrotationtime' => 'nsslapd-errorlog-logrotationtime', + 'errorlog-logrotationtimeunit' => 'nsslapd-errorlog-logrotationtimeunit', + 'errorlog-maxlogsize' => 'nsslapd-errorlog-maxlogsize', + 'errorlog-maxnumoflogsperdir' => 'nsslapd-errorlog-maxlogsperdir', + 'idletimeout' => 'nsslapd-idletimeout', + 'ioblocktimeout' => 'nsslapd-ioblocktimeout', + 'lastmod' => 'nsslapd-lastmod', + 'listenhost' => 'nsslapd-listenhost', + 'maxdescriptors' => 'nsslapd-maxdescriptors', + 'referral' => 'nsslapd-referral', + 'reservedescriptors' => 'nsslapd-reservedescriptors', + 'rootpwstoragescheme' => 'nsslapd-rootpwstoragescheme', + 'schemacheck' => 'nsslapd-schemacheck', + 'secure-port' => 'nsslapd-securePort', + 'security' => 'nsslapd-security', + 'sizelimit' => 'nsslapd-sizelimit', + 'SSL3ciphers' => 'nsslapd-SSL3ciphers', + 'timelimit' => 'nsslapd-timelimit', + 'pw_change' => 'passwordChange', + 'pw_syntax' => 'passwordCheckSyntax', + 'pw_exp' => 'passwordExp', + 'pw_history' => 'passwordHistory', + 'pw_inhistory' => 'passwordInHistory', + 'pw_lockout' => 'passwordLockout', + 'pw_lockduration' => 'passwordLockoutDuration', + 'pw_maxage' => 'passwordMaxAge', + 'pw_maxfailure' => 'passwordMaxFailure', + 'pw_minage' => 'passwordMinAge', + 'pw_minlength' => 'passwordMinLength', + 'pw_must_change' => 'passwordMustChange', + 'pw_resetfailurecount' => 'passwordResetFailureCount', + 'pw_storagescheme' => 'passwordStorageScheme', + 'pw_unlock' => 'passwordUnlock', + 'pw_warning' => 'passwordWarning' +); + +# the following hash displays global parameters related to database stored under cn=config,cn=ldbm database,cn=plugins,cn=config +%GlobalConfigLDBMparamToMigrate = ( + 'allidsthreshold' => 'nsslapd-allidsthreshold', + 'lookthroughlimit' => 'nsslapd-lookthroughlimit', + 'mode' => 'nsslapd-mode', + 'dbcachesize' => 'nsslapd-dbcachesize' +); + +# the following hash displays specific parameters to each backends and stored under cn=DBname,cn=ldbm database,cn=plugins,cn=config +%LDBMparamToMigrate = ( + 'cachesize' => 'nsslapd-cachesize', + 'readonly' => 'nsslapd-readonly' +); + +%stdIncludes = ( + "${oldConfDir}slapd.at.conf", "\n", + "${oldConfDir}slapd.oc.conf", "\n", + "${oldConfDir}java-object-schema.conf", "\n", + "${oldConfDir}ns-admin-schema.conf", "\n", + "${oldConfDir}ns-calendar-schema.conf", "\n", + "${oldConfDir}ns-certificate-schema.conf", "\n", + "${oldConfDir}ns-common-schema.conf", "\n", + "${oldConfDir}ns-compass-schema.conf", "\n", + "${oldConfDir}ns-delegated-admin-schema.conf", "\n", + "${oldConfDir}ns-directory-schema.conf", "\n", + "${oldConfDir}ns-legacy-schema.conf", "\n", + "${oldConfDir}ns-mail-schema.conf", "\n", + "${oldConfDir}ns-mcd-browser-schema.conf", "\n", + "${oldConfDir}ns-mcd-config-schema.conf", "\n", + "${oldConfDir}ns-mcd-li-schema.conf", "\n", + "${oldConfDir}ns-mcd-mail-schema.conf", "\n", + "${oldConfDir}ns-media-schema.conf", "\n", + "${oldConfDir}ns-mlm-schema.conf", "\n", + "${oldConfDir}ns-msg-schema.conf", "\n", + "${oldConfDir}ns-netshare-schema.conf", "\n", + "${oldConfDir}ns-news-schema.conf", "\n", + "${oldConfDir}ns-proxy-schema.conf", "\n", + "${oldConfDir}ns-value-schema.conf", "\n", + "${oldConfDir}ns-wcal-schema.conf", "\n", + "${oldConfDir}ns-cos-schema.conf", "\n", + "${oldConfDir}ns-web-schema.conf", "\n" +); + +%userDefinedConfigFiles = ( + "slapd.conf", "\n", + "slapd.ldbm.conf", "\n", + "slapd.user_at.conf", "\n", + "slapd.user_oc.conf", "\n", + "ns-schema.conf", "\n" + ); + +$CIS_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.15" ; +$TELEPHONE_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.50" ; +$DN_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.12" ; +$CES_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.26" ; +$INT_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.27" ; +$BIN_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.5" ; + +%allowedPlugins = ( + "cis", $CIS_SYNTAX_OID, + "tel", $TELEPHONE_SYNTAX_OID, + "dn", $DN_SYNTAX_OID, + "ces", $CES_SYNTAX_OID, + "int", $INT_SYNTAX_OID, + "bin", $BIN_SYNTAX_OID + ); + +%allowedModifiers = ( + "single", "SINGLE-VALUE" + ); +# "override" is not supported anymore and "operational" cannot be used in user defined attribute. + +@oldSuffixes = () ; # array of 4.x suffixes (with "o=netscaperoot" if presents) + +# link beetwen the name of the suffix and its associated DBname +%DBNAMES = () ; +%DBDirectory = () ; + +%oldhash = () ; + +# list of standard plugin's in version 4 +%stdPlugins = ( + "7-bit check" => "\n", + "binary syntax" => "\n", + "case exact string syntax" => "\n", + "case ignore string syntax" => "\n", + "distinguished name syntax" => "\n", + "integer syntax" => "\n", + "internationalization plugin" => "\n", + "referential integrity postoperation" => "\n", + "telephone syntax" => "\n", + "uid uniqueness" => "\n" + + ); + +# list of standard indexes configured out of the box in version 4 +%stdIndex = ( + 'aci', "\n", + 'changenumber', "\n", + 'copiedfrom', "\n", + 'dncomp', "\n", + 'entrydn', "\n", + 'numsubordinates', "\n", + 'objectclass', "\n", + 'parentid', "\n" +); + +# list of user added Plugin's. In 5.x, they 'll need to be recompiled +@badPlugins = () ; + +%newIndex = () ; + +%User_oc = () ; +# push objectnames as they are encountered in config files. +@User_oc_names = () ; + +%User_at = () ; + + + +#Usage parameters +$USER_OC_FILE_MODIFIED = 0 ; # 0 if user don't want to modify LDIF objectclasses before processing, 1 else +$USER_AT_FILE_MODIFIED = 0 ; +$INDEX_FILE_MODIFIED = 0 ; + +# Shutdown the legacy Directory instance +printTrace("\nShutdown the legacy Directory Server instance: ${oldHome}",0); +&stopServer($oldDir, 'slapd-'.$oldname); + +# compare configuration files with the standard ones +CompareStdConfigFiles() ; +die "\n\n The version of the product you want to migrate is not a 4.x Netscape Directory Server\n" unless ($oldVersion == 4) ; + +FillHashParametersName() ; + +############### Connect to the 5.x LDAP Directory Server ###################### +$ENV{"$LIB_PATH"} = "$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"} ; +my $LDAPservername = &getLDAPservername(); +die "\n Migration aborted. Check your 4.x and 5.x Netscape Directory Server are installed on the same machine \n" if ( $LDAPservername == -1 ); +$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n"; + +# continue if the connection to 5.x LDAP server is successful ! +printTrace("\nConnected to $Version.$Minor LDAP server\n",0) ; + +# get the uid and gid of the 5.x slapd user +($localuser, $newuid, $newgid) = getuid_gid(); +# get the uid and gid of the 4.x slapd user +($oldlocaluser, $olduid, $oldgid) = getolduid_gid(); + +# backup 5.x configuration files in <root_server5>/slapd-instancename/config +printTrace("\nBackup $serverHome${PATHSEP}config on $serverHome${PATHSEP}config_backup ...",0); +&backupConfigFiles(); + +# Parse the main configuration file: slapd.conf +printTrace("\nParse the configuration file: $oldSlapdConf...",0); +ParseSlapdConf("< ${oldSlapdConf}"); + +#migrate key/cert databases +printTrace("\nMigrate key/cert databases...",0); +&MigrateSSL(); + +# Update parameters : general server parameters, global LDBM parameter, specific backend parameters +printTrace("\nUpdate general server parameters...",0); +AddGeneralParameters(); +printTrace("\nUpdate global LDBM parameters...",0); +AddGeneralLDBMParameters(); +printTrace("\nUpdate specific backend parameters...",0); +AddSpecificLDBMParameters(); + +##### FOR TESTING PURPOSE ONLY ######## +# +#testIndexUpdating(); +# +####################################### + +# Migrate some entries contained in the old dse.ldif, and migrate certmap.conf +&MigrateDSE() ; +&MigrateCertmap() ; + +# update 5.x attribute definitions +LDAPmodify_User_at(); + +# update 5.x object classes definitions +LDAPmodify_User_oc(); + +# add new indexes to each backends +LDAPmodify_Indexes(); + +# migrate Plug'ins parameters (enable attribute, and arguments) +LDAPmodify_stdPlugin(); + +################## Close the connection to 5.x LDAP Server ##################### +$conn->close; + + +################## stop the 5.x instance and Export/Import the data, restart the server ################## +if (%DBNAMES) { + &stopServer($root,'slapd-'.$newname); + printTrace("\ndata processing...",0) ; + # migrate data for each suffix: 4.x -> LDIF files + &db2ldif($oldSlapdConf); + + # migrate LDIF data to the 5.x database: LDIF -> 5.x + &manyLdif2db(); + &startServer(); +} +else { + printTrace("\nThere no 4.x non-standard suffixes to migrate",0); +} + +printMsg("\n\n ****** End of migration ******\n\n"); + +close(LOGFILE); + + +########################################################################################### +# get input users +sub getParameters { + my $exit = 0 ; + my $i = 0; + my $pwdfile= ""; + while ($i <= $#ARGV) { + if ( "$ARGV[$i]" eq "-D" ) { # directory manager + if (! $rootDN) { + $rootDN = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-w") { # password + if (! $rootpwd) { + $rootpwd = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-j") { # password file + if (! $pwdfile) { + $pwdfile = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-o") { # 4.x instance path + if (! $oldHome ) { + $oldHome = $ARGV[++$i] ; + grep { s@\\@/@g } $oldHome if $isNT ; + if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; } + if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) { + $oldDir = $1 ; + $type = $2 ; + $oldname = $3 ; + if ($isNT) { + $oldDir = lc($oldDir) ; + $type = lc($type) ; + $oldname = lc($oldname) ; + $oldHome = lc($oldHome) ; + grep { s@/@\\@g } $oldDir ; + grep { s@/@\\@g } $oldHome ; + } + } + else { + print("\nThe 4.x instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-n") { # 5.x instance path + if (! $serverHome ) { + $serverHome = $ARGV[++$i] ; + grep { s@\\@/@g } $root if $isNT ; + grep { s@\\@/@g } $serverHome if $isNT ; + if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; } + if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) { + $root = $1 if ($1); + $type = $2 ; + $newname = $3 ; + if ($isNT) { + $root = lc($root) ; + $type = lc($type) ; + $newname = lc($newname) ; + $serverHome = lc($serverHome) ; + grep { s@/@\\@g } $root ; + grep { s@/@\\@g } $serverHome ; + } + } + else { + print("\nThe 5.x instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-p") { # 5.x DS port + if (! $newport ) { + $newport = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL + my $value = $ARGV[++$i] ; + if ($value =~ /[0-3]/) { + $TRACELEVEL = $value ; + } + else { + print("\nThe tracelevel must belong to 0..3 interval"); + &usage(); + exit(); + } + } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing + $NO_INPUT_USER = 1 ; + } elsif ("$ARGV[$i]" eq "-L") { # migration logfile + $LogFileReport = $ARGV[++$i] ; + } + else { + print("\nThe option $ARGV[$i] is not recognized"); + &usage() ; + exit(1); + } + $i++; + } + if (! $rootDN) { + print("\nThe rootDN is missing"); + $exit = 1; + } + if ($pwdfile ne "") { + # Open file and get the password + unless (open (RPASS, $pwfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $rootpwd = <RPASS>; + chomp($rootpwd); + close(RPASS); + } elsif ($rootpwd eq "-"){ + # Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; + # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $rootpwd = ReadLine(0); +# chomp($rootpwd); +# ReadMode('normal'); + } + if (! $rootpwd) { + print("\nThe rootpwd is missing"); + $exit = 1 ; + } + if (! $newport) { + print("\nThe port is missing"); + $exit = 1; + } + if (! $serverHome) { + print("\nThe 5.x instance path is missing"); + $exit = 1; + } + if (! $oldHome) { + print("\nThe 4.x instance path is missing"); + $exit = 1; + } + if ((! $LogFileReport) && $serverHome) { + ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime(); + $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log"; + } + + if ($exit) { + &usage() ; + exit(1); + } + +} + + +############################################################################### +# This subroutine is used to parse the slapd.conf configuration file and migrate specific parameters contained in it + + +sub ParseSlapdConf { + my $oldsrc = shift; + my $NumLine = 0 ; + # read the old conf file into a hash table + open( OLDSRC, $oldsrc ) || die "Can't open $oldsrc: $!: "; + LINE: while ( <OLDSRC> ) { + $NumLine++ ; + printTrace("\nLine: $_",4) ; + if (/^\s*\#/) { # skip comments + printTrace("\n# ",4) ; + next LINE; + } + if (/^\s*$/) { # skip blank lines + printTrace("\nBLANK LINE",4); + next LINE; + } elsif (/^suffix\s+/i) { + chomp($_) ; + CheckSuffix($_); + } elsif (/^plugin/i) { + printTrace("\nPLUGIN",4); + chomp($_); + if (! &isAStandardPlugin($_)) { + push @badPlugins, $_; + } + else { + my $Plugin = $_ ; + if (! &ParsePlugin($_,$NumLine)) { + printMsg("\nLine $NumLine, syntax error of the plugin:\n$Plugin"); + } + } + } elsif (/^include\s+[\"]?(.*?)[\"]?\s*$/i) { + # strip leading and trailing " + my $include_file = $1 ; + grep { s@/@\\@g } $include_file if $isNT; + if (! &isAStandardInclude($include_file)) { + printTrace("\nFILE: $1 NOT STANDARD",4) ; + &ParseConfigurationFile($include_file); + printTrace("\nEXIT ParseConfigurationFile: $include_file",4) ; + } + } elsif (/^userat\s+[\"]?(.*?)[\"]?\s*$/i) { + printTrace("\nuserat: $1",4); + my $at_file = $1 ; + grep { s@/@\\@g } $at_file if $isNT; + # Parse user defined attributes + &ParseAttributesFile($at_file); + } elsif (/^useroc\s+[\"]?(.*?)[\"]?\s*$/i) { + printTrace("\nuseroc: $1",4); + my $oc_file = $1 ; + grep { s@/@\\@g } $oc_file if $isNT; + # Parse user defined object classes + &ParseObjectClassesFile($oc_file); + } elsif (/^dynamicconf\s+[\"]?(.*?)[\"]?\s*$/i){ + printTrace("\ndynamicconf: $1",4); + my $dynamiconf_file = $1 ; + grep { s@/@\\@g } $dynamiconf_file if $isNT; + # Parse dynamic configuration file (e-g slapd.ldbm.conf) + &ParseConfigurationFile($dynamiconf_file); + } elsif (/^\s*(\S+)\s+[\"]?(.*?)[\"]?\s*$/) { + printTrace("\nParseParameters: $1",4); + # Parse parameters and record the associated value in %oldhash + &ParseParameters($1,$2,$NumLine); + } else { + printTrace("\nUnknown format of configuration data: $_",0); } + } + close(OLDSRC); + + } + + + +############################################################################# +# return 1 if the suffix already exists, 0 else +sub existSuffix { + my $suffixname = shift ; + my $entry = $conn->search("cn=\"$suffixname\",cn=mapping tree,cn=config ", "base","objectclass=*") ; + return 1 if ($entry) ; + return 0 ; +} + +# return the name of the backend if it has been successfully created, 0 else +sub createBackend { + my $suffixname = shift ; + my $backend = "MigratedDB_0" ; + my $NbRetry = 1 ; + my $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ; + while ($entry) { + # try to find another name for the backend + $backend = "MigratedDB_$NbRetry" ; + $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ; + $NbRetry++; + } + # normally I should have a unique name for the backend + my $suffixarg = "nsslapd-suffix" ; + $entry = $conn->newEntry() ; + $entry->setDN("cn=$backend,cn=ldbm database,cn=plugins,cn=config"); + $entry->setValues("objectclass", "top", "extensibleObject", "nsBackendInstance" ); + $entry->setValues("cn", $backend ); + $entry->setValues($suffixarg, $suffixname ); + my $res = $conn->add($entry) ; + if ($res) { + return $backend ; + } + else { + return 0 ; + } +} + +# return 1, if add the new entry in the mapping tree, else 0 +sub AddEntryInMappingTree { + my $backend = shift ; + my $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ; + if ($entry) { + printTrace("\nAddEntry in progress ...",4) ; + my $suffixarg = "nsslapd-suffix" ; + my $statearg = "nsslapd-state" ; + my $backendarg= "nsslapd-backend"; + my $suffixname = $entry->{$suffixarg}[0]; + $entry = $conn->newEntry() ; + $entry->setDN("cn=\"$suffixname\",cn=mapping tree,cn=config") ; + $entry->setValues("objectclass", "top", "extensibleObject", "nsMappingTree" ); + $entry->setValues("cn", "\"$suffixname\""); + $entry->setValues($statearg, "backend"); + $entry->setValues($backendarg, $backend); + return $conn->add($entry); + } + else { + printTrace("\nNo AddEntry processed for $backend",4); + return 0 ; + } +} + + +# Treat the case where the suffix is "o=NetscapeRoot" +sub CheckSuffix { + my $suffix = shift ; + my $suffixname ; + if (!(/^suffix\s+\"?(.*?)\"?\s*$/i)) { + printMsg("Syntax error of the suffix: $suffix"); + return 0 ; + } + else { + $suffixname = $1 ; + } + if (/^suffix\s+\"?\s*o=netscaperoot\s*\"?\s*$/i) { + printTrace("\nFor the suffix o=NetscapeRoot, we do nothing",1); + # treat the case where the suffix is "o=NetscapeRoot" + } + else { + push @oldSuffixes, $_; + # check if the suffix already exists in the 5.x DS target + if (! existSuffix($suffixname)) { + printTrace("\nSuffix $suffixname doesn't exist",1) ; + # create a new backend with the name of the suffix preceded by MigratedDB_ + my $backend = createBackend($suffixname) ; + if ($backend) { + printTrace("\nBackend: $backend has been created !!!",1); + # if the creation of the backend is ok, we add a new entry in the mapping tree + if (AddEntryInMappingTree($backend)) { + # We add the association dbname->suffix in the hash %DBNAMES + $DBNAMES{$suffixname} = $backend ; + # get the db filename + $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ; + my $dirarg = "nsslapd-directory"; + $DBDirectory{$backend} = $entry->{$dirarg}[0]; + printTrace("\nThe relation $backend->$suffixname has been added to the mapping tree",2); + } + else { + printMsg("\nCOULD NOT ADD ENTRY: $backend->$suffixname IN MAPPINGTREE"); + } + } + else { + printMsg("\nCOULD NOT CREATE BACKEND: $backend"); + } + } + else { + printTrace("\nSuffix: $suffixname already exists",1); + # the suffix already exists in the 5.x DS + } + } + return 1 ; +} + +############################################################################# +# Usefull to know the standard configuration +sub isAStandardPlugin { + my $line = shift; + chomp($line); + printTrace("\nStdPlugin?: $line",4); + if ($line =~ /^plugin\s+(database|extendop|preoperation|postoperation|matchingrule|syntax)\s+(on|off)\s+\"(.*?)\"\s+\"(.*?)\"\s+(\S+)(.*)$/i) { + # $1 = <type>, $2 = <on|off>, $3 = <name>, $4 = <pathname>, $5 = <init_function>, $6 = [<arg>]* + printTrace("\nName: $3, pathname: $4, init_function: $5",4); + + my $LC_line = lc($3); + my $Value = $stdPlugins{$LC_line} ; + if ($Value) { + printTrace("\nIS A STANDARD PLUGIN",4); + } + else { + printTrace("\nNOT A STANDARD PLUGIN",4); + } + return $stdPlugins{$LC_line} ; + } + else { + printTrace("\nSYNTAX ERROR PLUGIN",4); + return 0 ; + } +} + +sub isAStandardIndex { + my $line = shift ; + chomp($line); + if ($line =~ /^index\s+(\S+).*/i) { + my $LC_line = lc($1); + my $Value = $stdIndex{$LC_line} ; + printTrace("\nInclude: $LC_line \nValue: $Value", 4); + return $stdIndex{$LC_line}; + } + else { + return 0 ; + } +} + + +sub isAStandardInclude { + my $line = shift; + + chomp($line); + if ($isNT){ + return $stdIncludes{lc($line)}; + } + else { + return $stdIncludes{$line} ; + } +} + +############################################################################# +# +# Execute a Perldap command to update plugins definition in the 5.x schema + +sub LDAPmodify_stdPlugin { + my $Filename = shift ; + my @pluginames = keys(%stdPlugins); + if (! $STDPLUGINS_FILE_MODIFIED) { + printTrace("\nLDAPmodify_plugin",4); + printTrace("\nMigrate plugin's...",1); + foreach $pluginame ( @pluginames ) { + my $update_plugin = 0 ; + my $ref_plugin = $stdPlugins{$pluginame}; + if ($ref_plugin ne "\n") { + my $name = $ref_plugin->name ; + my $entry = $conn->search("cn=$name,cn=plugins,cn=config", "base","objectclass=nsSlapdPlugin") ; + if ($entry) { + my $pluginenabled="nsslapd-pluginenabled" ; + if (($entry->{$pluginenabled}[0]) ne $ref_plugin->enable) { + $update_plugin = 1 ; + my $enable = $ref_plugin->enable ; + printTrace("\n$pluginame, plugin-enable: $enable",3) ; + $entry->setValues($pluginenabled, $enable ); + } + my $ArgNum = 0 ; + foreach $ArgValue (@{$ref_plugin->args}) { + my $Arg="nsslapd-pluginarg$ArgNum"; + printTrace("\n$Arg: $ArgValue",3) ; + if ($entry->{$Arg}[0] ne $ArgValue) { + printTrace("\n$pluginame, $Arg: $ArgValue",3) ; + $update_plugin = 1 ; + $entry->setValues($Arg, $ArgValue) ; + } + $ArgNum++ ; + } + if ($update_plugin) { + printTrace("\n$pluginame is being updated...",2); + my $res = $conn->update($entry) ; + if ($res) { + printTrace("\nupdated !",2); + } + else { + printMsg("\nError during update of plugin: $pluginame") ; + $MigrationErrors .= "\nError during update of plugin: $pluginame"; + } + } + else { + printTrace("\n$pluginame has not changed",4); + } + } + else { + printMsg("\ncan't access the plugin: cn=$name,cn=plugins,cn=config"); + } + } + else { + printTrace("\nPLUGIN NOT RECORDED: $pluginame",4) ; + } + } + } + else { + # treat the case where the user wants to look at these plugins before processing + } +} + +############################################################################# +# Execute Perldap command to add new indexes to the migrated instances + +sub LDAPmodify_Indexes { + my $Filename = shift ; + my @indexnames = keys(%newIndex); + my @suffixnames = keys(%DBNAMES); + if ((! $INDEX_FILE_MODIFIED) && (%DBNAMES)) { + # we update indexes only if there is at least one backend to migrate + printTrace("\nLDAPmodify_indexes",4); + printTrace("\nMigrate indexes...",1); + foreach $indexname ( @indexnames ) { + printTrace("\nIndexName: $indexname",4); + printTrace("\nIndexTypes: .@{$newIndex{$indexname}->types}.", 4) ; + printTrace("\nIndexOIDS: .@{$newIndex{$indexname}->oids}.", 4) ; + foreach $suffixname ( @suffixnames ) { + # check if the index already exists ! + printTrace("\nsearch for cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...", 3); + my $entry = $conn->search("cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex"); + if (! $entry) { + # create a new index + printTrace("index $indexname is being created under cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...",2); + my $entry = $conn->newEntry(); + $entry->setDN("cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config"); + $entry->setValues("objectclass", "top", "nsIndex" ) ; + $entry->setValues("cn", $indexname) ; + $entry->setValues("nssystemindex", "false") ; + my @types = @{$newIndex{$indexname}->types} ; + my @oids = @{$newIndex{$indexname}->oids} ; + $entry->setValues("nsindextype", @types) if (@types) ; + $entry->setValues("nsmatchingrule", @oids ) if (@oids); + my $res = $conn->add($entry) ; + if ($res) { + printTrace("\nAdd index successfully: $indexname for backend: $DBNAMES{$suffixname}",2); + } + else { + printMsg("\n Failed to add the index: $indexname to backend: $DBNAMES{$suffixname}"); + $MigrationErrors .= "\n Failed to add the index: $indexname to backend: $DBNAMES{$suffixname}" ; + } + } + elsif ($entry->{nssystemindex}[0] eq "false") { + # if the index is not a system index, we update it + printTrace("\nindex $indexname is being processed under cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...",2); + my @types = @{$newIndex{$indexname}->types} ; printTrace("\ntypes: .@types.",2) ; + my @oids = @{$newIndex{$indexname}->oids} ; printTrace("\noids: .@oids.",2) ; + my @existing_types = $entry->getValues("nsindextype"); + my @existing_oids = $entry->getValues("nsmatchingrule"); + # get the elements present in @types and not present in @existing_types + my @typesToAdd = &getDiff(\@types, \@existing_types); + # same for matchingrules + my @oidsToAdd = &getDiff(\@oids, \@existing_oids); + foreach $newtype (@typesToAdd) { + $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2); + } + foreach $newoid (@oidsToAdd) { + $entry->addValue("nsmatchingrule", $newoid); + } + if (@typesToAdd || @oidsToAdd) { + my $res = $conn->update($entry) ; + if ($res) { + printTrace("\nUpdate index successfully: $indexname for backend: $DBNAMES{$suffixname}",2); + } + else { + printMsg("\n Failed to update the index: $indexname to backend: $DBNAMES{$suffixname}"); + $MigrationErrors .= "\n Failed to update the index: $indexname to backend: $DBNAMES{$suffixname}" ; + } + } + else { + printTrace("\nNothing to update",2); + } + } + else { + printTrace("\nThe index: $indexname is a system index. It can't be updated",2); + } + } + } + + } + else { + # treat the case where the user wants to look at these indexes before processing + } + +} + +############################################################################# +# +# Execute a Perldap command to add all user defined object classes in the 5.x schema + +sub LDAPmodify_User_oc { + my $Filename = shift ; + if (! $USER_OC_FILE_MODIFIED) { + printTrace("\nLDAPmodify_User_oc",4); + printTrace("\nMigrate objectclasses...",1); + foreach $objectname ( @User_oc_names ) { + my $entry = $conn->search("cn=schema", "base","objectclass=*") ; + die "\ncan't connect to object: cn=schema\n" unless ($entry); + printTrace("\nObjectName: $objectname\nValue: $User_oc{$objectname}",3); + next if ($entry->hasValue("objectclasses",$User_oc{$objectname},1)) ; + $entry->addValue("objectclasses",$User_oc{$objectname},"1") ; + my $res = $conn->update($entry) ; + if (! $res) { + printMsg("\nCan\'t add objectclass to the schema: $User_oc{$objectname}"); + my $msg = $conn->getErrorString(); + printMsg("\nMsg: $msg"); + $MigrationErrors .= "\nCan\'t add objectclass to the schema: $User_oc{$objectname}" ; + } + else { + printTrace("\nobjectclass: $User_oc{$objectname} added",2); + } + } + } + else { + # treat the case where the user wants to look at these objectclasses before processing + } +} + +############################################################################# +# +# Execute a Perldap command to add all user defined attributes in the 5.x schema + +sub LDAPmodify_User_at { + my $Filename = shift ; + my @attributenames = keys(%User_at); + if (! $USER_AT_FILE_MODIFIED) { + + printTrace("\nLDAPmodify_User_at",4); + printTrace("\nMigrate attributes...",1); + foreach $attributename ( @attributenames ) { + my $entry = $conn->search("cn=schema", "base","objectclass=*") ; + printTrace("\nAtributeName: $attributename, Value: $User_at{$attributename}",3); + die "\nentry not found cn=schema\n" unless $entry ; + next if ($entry->hasValue("attributetypes",$User_at{$attributename},1) ) ; + my $res = $entry->addValue("attributetypes",$User_at{$attributename},"1") ; + if (! $res) { + printMsg("\nCan\'t add attribute to the schema: $User_at{$attributename}"); + $MigrationErrors .= "\nCan\'t add attribute to the schema: $User_at{$attributename}" ; + } + my $res = $conn->update($entry) ; + if ($res) { + printTrace("\nattribute: $attributename added",2); + } + else { + printMsg("\nCan\'t add attribute to the schema: $User_at{$attributename}"); + my $msg = $conn->getErrorString(); + printMsg("\nMsg: $msg"); + $MigrationErrors .= "\nCan\'t add attribute to the schema: $User_at{$attributename}" ; + } + } + } + else { + # treat the case where the user wants to look at these attributes before processing + } +} + +############################################################################# +# Add an object class to the user_oc hash and reset the object !!! +sub AddObjectClass { + my $ObjectClass = shift ; + my $ObjectName = $ObjectClass->{'ObjectName'} ; + my $Object_oid = $ObjectClass->{'Object_oid'} ; + my $Object_superior = $ObjectClass->{'Object_superior'} ; + my $Object_requires = $ObjectClass->{'Object_requires'} ; + my $Object_allows = $ObjectClass->{'Object_allows'} ; + my $ObjectClassDef = "( $Object_oid NAME \'$ObjectName\' DESC \'\' SUP $Object_superior STRUCTURAL MUST ($Object_requires) MAY ($Object_allows) X-ORIGIN \'user defined\' )"; + if ( (!($ObjectName =~ /^top$/i)) && ( ! $User_oc{$ObjectName} )) { + $User_oc{$ObjectName} = $ObjectClassDef ; + push @User_oc_names, $ObjectName ; + printTrace("ObjectName: $ObjectName \nObject_oid: $Object_oid \nObject_superior:$Object_superior \nObject_requires: $Object_requires \nObject_allows: $Object_allows \nObjectClassDefinition: $User_oc{$ObjectName}\n",4); + } + elsif ( ($User_oc{$ObjectName}) && ($User_oc{$ObjectName} ne $ObjectClassDef) ) { + printMsg("\nAttempt to redifine the objectclass: $ObjectName previously defined in your configuration file. Operation not allowed "); + } + else { + printMsg("\nAttempt to redifine the objectclass: top. Operation not allowed"); + } + resetObjectClass($ObjectClass); +} + +############################################################################# +# Build an LDIF attribute and add it to the user_at hash +sub AddAttribute { + my $Attr = shift ; + my $AttributeName = $Attr->{'AttributeName'}; + my $Attribute_oid = $Attr->{'Attribute_oid'}; + my $Attribute_aliases = $Attr->{'Attribute_aliases'}; + my $Attribute_syntax = $Attr->{'Attribute_syntax'}; + my $Attribute_single = $Attr->{'Attribute_single'}; + my $AttributeDef = "( $Attribute_oid NAME ( \'$AttributeName\' $Attribute_aliases) DESC \'User Defined Attribute\' SYNTAX $Attribute_syntax $Attribute_single X-ORIGIN 'user defined' )" ; + printTrace("\nAttributeDef: $AttributeDef",4); + $User_at{$AttributeName} = $AttributeDef ; +} +############################################################################# +# add the index structure to the newIndex hash +sub AddIndex { + my $ref_index = shift ; + my $state = shift ; + printTrace("\nAddIndex, last state: $state",4) ; + if ($state == 1) { + $ref_index->specific("ALL") ; + return 1 ; + } + elsif ($state == 6) { + $ref_index->specific("NONE") ; + return 1 ; + } + if (($state == 1) || ($state == 3) || ($state == 5) || ($state == 6)) { + foreach $name (@{$ref_index->names}) { + $newIndex{$name} = $ref_index ; # record the ref to the index struct in the newIndex hash + } + return 1 ; + } + else { + return 0 ; + } +} + +############################################################################# +# add the plugin structure to the stdPlugin hash + +sub AddPlugin { + my $ref_plugin = shift ; + printTrace("\nAddPlugin",4) ; + $stdPlugins{lc($ref_plugin->name)} = $ref_plugin ; + my $name = $ref_plugin->name ; + my $type = $ref_plugin->type ; + my $enable = $ref_plugin->enable ; + + printTrace("\nPluginName: $name",4); + printTrace("\nPluginType: $type",4); + printTrace("\nPluginEnable: $enable",4); + printTrace("\nPluginArgs: @{$ref_plugin->args}",4); + return 1 ; +} + + +############################################################################# +# parse a plugin definition and call the addindex + +sub ParsePlugin { + my $Plugin = shift ; + my $NumLine = shift ; + my $state = 0 ; + my $ErrorMsg = "Syntax error of a plugin definition. \n line parsed:"; + my $ref_plugin = S_plugin->new(); + printTrace("\nParsePlugin: $_",4); + if (/^plugin\s+(database|extendop|preoperation|postoperation|matchingrule|syntax)\s+(on|off)\s+\"(.*?)\"\s+\"(.*?)\"\s+(\S+)(.*)$/i) { + # $1 = <type>, $2 = <on|off>, $3 = <name>, $4 = <pathname>, $5 = <init_function>, $6 = [<arg>]* + $ref_plugin->name($3); + $ref_plugin->type($1); + $ref_plugin->enable($2); + $_ = $6 ; + my $ArgNb = 0 ; + my $prec ; + my $arg ; + my $Unix_oldDir = $oldDir ; + my $Unix_root = $root ; + grep { s@\\@/@g } $Unix_oldDir if $isNT; + grep { s@\\@/@g } $Unix_root if $isNT; + while (!(/^\s*$/)) { + if (/^\s*\".*?\"/) { + s/^\s*\"(.*?)\"(.*)/$2/i ; + $arg = $1 ; + } + elsif (/^\s*[^\"\s]+/) { + s/^\s*([^\"\s]+)(.*)/$2/i ; + $arg = $1 ; + } + $prec = $_ ; + $_ = $arg ; + + s@$Unix_oldDir@$Unix_root@ig ; + s/$type-$oldname/$type-$newname/ig ; + @{$ref_plugin->args}[$ArgNb++] = $_ ; + $_ = $prec ; + } + if (/^\s*$/) { + return AddPlugin($ref_plugin); + } + else { + return 0 ; + } + } + return 0 ; +} + +############################################################################# +# parse an index definition and call the addindex + +sub ParseIndex { + my $index = shift ; + my $NumLine = shift ; + my $ref_index = S_index->new() ; + my $Value ; + my $state = 0 ; + my $ErrorMsg = "Syntax error of an index definition.\nline parsed:"; + printTrace("\nParseIndex: $_",4) ; + s/,/, /g ; + s/\s+,/,/g ; + s/^index\s+//i ; # substitute the token index + while (!(/^\s*$/)) { + s/^\s*(\S+)(.*)$/$2/ ; + $Value = $1 ; + printTrace("\nValue: $Value",4); + printTrace("\nState: $state",4) ; + SWITCH: { + if ($state == 0) { + if ($Value =~ /[^\.]/) { + if ($Value =~ /(\S+),$/) { + push @{$ref_index->names}, $1 ; + } + else { + $state = 1 ; + push @{$ref_index->names}, $Value ; + } + } + else { + return 0 ; + } + last SWITCH ; + } + if ($state == 1) { + if ($Value =~ /^none$/i) { + $state = 6 ; # end of the index definition + } + elsif ($Value =~ /^\"\"$/) { + $state = 4 ; # we expect to have at least one OID + } + elsif ($Value =~ /(\S+),$/) { + $state = 2 ; + push @{$ref_index->types}, $1 ; + } + else { + $state = 3 ; + push @{$ref_index->types}, $Value ; + } + last SWITCH ; + } + if ($state == 2) { + if ($Value =~ /(\S+),$/) { + push @{$ref_index->types}, $1 ; + } + else { + $state = 3 ; + push @{$ref_index->types}, $Value ; + } + last SWITCH ; + } + if ($state == 3) { + if ($Value =~ /(\S+),$/) { + $state = 4 ; + push @{$ref_index->oids}, $1 ; + } + else { + $state = 5 ; + push @{$ref_index->oids}, $Value ; + } + last SWITCH ; + } + if ($state == 4) { + if ($Value =~ /(\S+),$/) { + push @{$ref_index->oids}, $1 ; + } + else { + $state = 5 ; + push @{$ref_index->oids}, $Value ; + } + last SWITCH ; + } + } + } +return AddIndex($ref_index,$state) ; + +} + +############################################################################# + +sub ParseAttribute { + + + my $Attr = shift ; + my $NumLine = shift ; + my $state = 1 ; + my $ErrorMsg = "Syntax error of an attribute definition.\nline parsed:"; + my %Attribute = ( + 'AttributeName' => "", + 'Attribute_oid' => "", + 'Attribute_aliases' => "", + 'Attribute_syntax' => "", + 'Attribute_single' => "" + ); + my $AttributeName = " "; + printTrace("\nParseAttribute",4); + while (!(/^\s*$/)) { + s/^(.*?)(\S+)\s*$/$1/ ; + printTrace("\nValue: $2",4); + printTrace("\nState: $state",4) ; + my $Value = $2 ; + SWITCH: { + if ($state == 1) { + if (isAllowedModifier($Value)) { + $state = 1 ; + $modifier = lc($Value); + $AttrVar = 'Attribute_' . $modifier ; + $Attribute{$AttrVar} = &getModifierValue($Value) ; + } + elsif (&isAllowedPlugin($Value)) { + $state = 2 ; + $Attribute{'Attribute_syntax'} = &getSyntaxOid($Value) ; + } + else { + return 0 ; + } + last SWITCH ; + } + if ($state == 2) { + if ($Value =~ /[\.]|-oid$/) { + $Attribute{'Attribute_oid'} = "$Value" ; + printTrace("\nAttribute-oid: $Attribute{'Attribute_oid'}",3); + $state = 3 ; + } + elsif ($Value =~ /[^\.]/) { + $AttributeName = $Attribute{'AttributeName'} ; + if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;} + $Attribute{'AttributeName'} = $Value ; + $state = 4 ; + } + else { + return 0 ; + } + last SWITCH ; + } + if ($state == 3) { + if ($Value =~ /[^\.]/) { + $AttributeName = $Attribute{'AttributeName'} ; + if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;} + $Attribute{'AttributeName'} = $Value ; + $state = 4 ; } + else { + return 0 ; + } + last SWITCH ; + } + if ($state == 4) { + if ($Value =~/^attribute$/i){ + $state = 5; + } + elsif ($Value =~/[^\.]/i) { + $AttributeName = $Attribute{'AttributeName'} ; + if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;} + $Attribute{'AttributeName'} = $Value ; + } + else { + return 0 ; + } + last SWITCH ; + } + if ($state == 5) { + return 0 ; + last SWITCH ; + } + } + } + $Attribute{'Attribute_oid'} = $Attribute{'AttributeName'} . '-oid' unless ($Attribute{'Attribute_oid'}) ; + return AddAttribute(\%Attribute) ; +} + + +############################################################################# +# fill in the hash HashParametersName + +sub FillHashParametersName { + my @paramnames = ( keys(%GeneralSrvParamToMigrate), keys(%GlobalConfigLDBMparamToMigrate), keys(%LDBMparamToMigrate)); + foreach $param (@paramnames) { + $HashParametersName{$param} = '\n'; + } +} + + +# Parse parameters +sub ParseParameters { + my $param = shift ; + my $value = shift ; + my $NumLine = shift ; + my $ErrorMsg = "parameter unknown, or not to be migrated: "; + if ($HashParametersName{lc($param)} && ($value !~ /^\s*$/)) { + $HashParametersName{lc($param)} = $value ; + printTrace("\nParam: $param is present",4); + } + else { + printTrace("\n$NumLine, $ErrorMsg,$param",4); + } + +} + +# add general server parameters +sub AddGeneralParameters { + my @paramnames = keys(%GeneralSrvParamToMigrate); + my $entry = $conn->search("cn=config","base","objectclass=*"); + die "\ncan't access to object: cn=config. \nMigration stopped\n" unless ($entry); + printTrace("\nAddGeneralParameters",4); + foreach $param (@paramnames) { + my $LDAPparam = $GeneralSrvParamToMigrate{$param} ; + my $Value = $HashParametersName{$param} ; + if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) { + printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4); + $entry->setValues($LDAPparam, $Value); + my $res = $conn->update($entry); + if ($res) { + printTrace("\nUpdate successfully $LDAPparam ",0); + } + else { + printMsg("\nCan't update parameter: $LDAPparam"); + } + } + } +} + + +# add general LDBM parameters +sub AddGeneralLDBMParameters { + my @paramnames = keys(%GlobalConfigLDBMparamToMigrate); + my $entry = $conn->search("cn=config,cn=ldbm database,cn=plugins,cn=config","base","objectclass=*"); + die "\ncan't access to object: cn=config,cn=ldbm database,cn=plugins,cn=config. \nMigration stopped\n" unless ($entry); + printTrace("\nAddGeneralLDBMParameters",4); + foreach $param (@paramnames) { + my $LDAPparam = $GlobalConfigLDBMparamToMigrate{$param} ; + my $Value = $HashParametersName{$param} ; + if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) { + printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4); + $entry->setValues($LDAPparam, $Value); + my $res = $conn->update($entry); + if ($res) { + printTrace("\nUpdate successfully $LDAPparam ",0); + } + else { + printMsg("\nCan't update parameter: $LDAPparam"); + } + } + } +} + +# add specific LDBM parameters +sub AddSpecificLDBMParameters { + my @paramnames = keys(%LDBMparamToMigrate); + my %REV_DBNAMES = reverse %DBNAMES ; + my @dbnames = keys(%REV_DBNAMES); + printTrace("\nAddSpecificLDBMParameters",4); + foreach $dbname (@dbnames) { + my $entry = $conn->search("cn=$dbname,cn=ldbm database,cn=plugins,cn=config","base","objectclass=*"); + die "\ncan't access to object: cn=$dbname,cn=ldbm database,cn=plugins,cn=config. \nMigration stopped\n" unless ($entry); + foreach $param (@paramnames) { + my $LDAPparam = $LDBMparamToMigrate{$param} ; + my $Value = $HashParametersName{$param} ; + if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) { + printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4); + $entry->setValues($LDAPparam, $Value); + my $res = $conn->update($entry); + if ($res) { + printTrace("\nUpdate successfully $LDAPparam",2); + } + else { + printMsg("\nCan't update parameter: $LDAPparam"); + } + } + } + } +} + +############################################################################# +# Parse a configuration file potentialy tuned by the user (different from slapd.user_oc.conf and slapd.user_at.conf) + +sub ParseConfigurationFile { + + my $FileToParse = shift; + my $NumLine = 0; + my $PARSE_OBJECTCLASSES = 0 ; # 1 if there are objectclass definitions in the file + printTrace("\nParseConfigurationFile: $FileToParse",4) ; + printTrace("\nParse $FileToParse",2); + # read each line of the configuration file + my $CONFIGFILE = "CONFIGFILE.$FileToParse" ; + open( $CONFIGFILE, $FileToParse ) || die "Can't open $FileToParsec: $!: "; + LINE: while ( <$CONFIGFILE> ) { + $NumLine++ ; + if (/^\s*\#/) { # skip comments + next LINE; + } + if (/^\s*$/) { # skip blank lines + next LINE; + } elsif (/^suffix\s+/i) { + chomp($_) ; + CheckSuffix($_) ; + } elsif (/^plugin/i) { + chomp($_); + if (! &isAStandardPlugin($_)) { + push @badPlugins, $_; + } + else { + my $Plugin = $_ ; + if (! &ParsePlugin($_,$NumLine)) { + printMsg("\nLine $NumLine, syntax error of the plugin:\n$Plugin"); + } + } + } elsif (/^index/i) { + chomp($_); + if (! &isAStandardIndex($_)) { + my $Index = $_ ; + if (! &ParseIndex($_,$NumLine)) { + printMsg("\nLine $NumLine, syntax error of index:\n$Index"); + } + } + } elsif (/^include\s+[\"]?(.*?)[\"]?\s*$/i) { + # strip leading and trailing " + my $include_file = $1 ; + grep { s@/@\\@g } $include_file if $isNT; + if (! &isAStandardInclude($include_file)) { + &ParseConfigurationFile($include_file); + } + } elsif (/^attribute\s+\S+/i) { + chomp($_); + my $Attrib = $_ ; + if (! &ParseAttribute($_,$NumLine)) { + printMsg("\nLine $NumLine, syntax error of attribute:\n$Attrib"); + } + } elsif (/^objectclass\s+(\S+)\s*$/i) { + # At least one objectclass is present in the file + $PARSE_OBJECTCLASSES = 1; + } elsif (/^\s*(\S+)\s+[\"]?(.*?)[\"]?\s*$/) { + # Parse parameters and record the associated value in %Oldhash + &ParseParameters($1,$2,$NumLine); + } + } + close($CONFIGFILE); + ParseObjectClassesFile($FileToParse) if ($PARSE_OBJECTCLASSES); # parse objectclass definition + +} + +############################################################################# +# Parse the file specified in the userat attribute + +sub ParseAttributesFile { + my $userat_file=shift ; + my $NumLine = 0; + printTrace("\nParseAttributesFile: $userat_file",4); + printTrace("\nParse user defined attributes file: $userat_file",2); + # read each line of the configuration file + open( ATTRFILE, $userat_file ) || die "Can't open $FileToParsec: $!: "; + LINE: while ( <ATTRFILE> ) { + $NumLine++ ; + if (/^\s*\#/) { # skip comments + next LINE; + } + if (/^\s*$/) { # skip blank lines + next LINE; + } elsif (/^attribute\s+\S+/i) { + chomp($_); + my $Attrib = $_ ; + if (! &ParseAttribute($_, $NumLine)) { + printMsg("\nLine $NumLine, syntax error of attribute:\n$Attrib"); + } + } + } + close(ATTRFILE); +} + +############################################################################# +# Parse the file specified in the useroc token + +sub ParseObjectClassesFile { + my $useroc_file = shift ; + my %ObjectClass = ( + 'ObjectName' => " ", + 'Object_oid' => " ", + 'Object_superior' => "top", + 'Object_requires' => " ", + 'Object_allows' => " " + ); + + my $state = 0; + my $ErrorMsg = "Syntax error of an object class definition.\nline parsed:"; + my $LineNb = 0 ; # Number of the current line parsed in the file + printTrace("ParseObjectClassesFile: $useroc_file\n",4) ; + # read each line of the configuration file + open( OBJCLASSFILE, $useroc_file ) || die "Can't open $FileToParsec: $!: "; + printTrace("Begin the parsing of the file: $useroc_file",4); + LINE: while ( <OBJCLASSFILE> ) { + printTrace("Current Line: $_",4); + $LineNb++ ; + if (/^\s*\#/) { # skip comments + next LINE; + } + if (/^\s*$/) { # skip blank lines + next LINE; + } + SWITCH: { + if ($state == 0) { resetObjectClass(\%ObjectClass); + if (/^objectclass\s+(\S+)\s*$/i) { + $ObjectClass{'ObjectName'} = $1; + $state = 1 ;} + else {} # printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 1) {if (/^\s+oid\s+(\S+)\s*$/i) { + $ObjectClass{'Object_oid'} = $1; + $state = 2 ;} + elsif (/^\s+superior\s+(\S+)\s*$/i) { + $ObjectClass{'Object_superior'} = $1; + $state = 3 ; + } + elsif (/^\s+requires\s*$/i) { + $state = 4; + } + elsif (/^\s+allows\s*$/i) { + $state = 5; + } + else {$state=0; printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 2) {if (/^\s+superior\s+(\S+)\s*$/i) { + $ObjectClass{'Object_superior'} = $1; + $state = 3 ;} + elsif (/^\s+requires\s*$/i) { + $state = 4; + } + elsif (/^\s+allows\s*$/i) { + $state = 5; + } + else { $state=0; printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 3) {if (/^\s+requires\s*$/i) + { $state = 4; } + elsif (/^objectclass\s+(\S+)\s*$/i) { + # run an ldap add before to continue + &AddObjectClass(\%ObjectClass); + $ObjectClass{'ObjectName'} = $1; + $state = 1 ;} + elsif (/^\s+allows\s*$/i) + { $state = 5; } + else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 4) {if (/^\s+([^,\s]+),\s*$/i) { + $ObjectClass{'Object_requires'}.=$1." \$ "; } + elsif (/^\s+([^,\s]+)\s*$/i) { + $ObjectClass{'Object_requires'}.=$1." "; + $state = 6; } + else {$state = 0;printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 5) {if (/^\s+([^,\s]+),\s*$/i) { + $ObjectClass{'Object_allows'}.=$1." \$ "; } + elsif (/^\s+([^,\s]+)\s*$/i) { + $ObjectClass{'Object_allows'}.=$1." "; + # run an ldap add before to continue + &AddObjectClass(\%ObjectClass); + $state = 0; } + else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 6) {if (/^objectclass\s+(\S+)\s*$/i) { + # run an ldap add before to continue + &AddObjectClass(\%ObjectClass); + $ObjectClass{'ObjectName'} = $1; + $state = 1 ;} + elsif (/^\s+allows\s*$/i) { + $state = 5;} + else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + } + } + close(OBJCLASSFILE); + if (($state == 3) || ($state == 4) || ($state == 5) || ($state == 6)) { + &AddObjectClass(\%ObjectClass); + } + printTrace("state: $state",4); +} + +############################################################################# +# printMsg print message to the user standard output. + +sub printMsg { + + my $TypeMsg = shift ; + my $Msg = shift ; + my $LineNb = shift ; + if ($LineNb) { + printTrace("Line: $LineNb, $TypeMsg, $Msg"); + } + else { + printTrace("$TypeMsg $Msg"); + } +} + +############################################################################# +# print message error to the user standard output. + +sub printTrace { + + my $Msg = shift ; + my $level = shift ; + if ($level <= $TRACELEVEL) { + print($Msg); + print LOGFILE $Msg ; + } +} + +############################################################################# +# reset an objectclass structure + +sub resetObjectClass { + my $ObjectClass = shift; + $ObjectClass->{'ObjectName'} = " " ; + $ObjectClass->{'Object_oid'} = " " ; + $ObjectClass->{'Object_superior'} = "top" ; + $ObjectClass->{'Object_requires'} = " " ; + $ObjectClass->{'Object_allows'} = " " ; +} + +############################################################################# +# this subroutine implements a very stupid version of diff + +sub diff { + my $f1 = shift; + my $f2 = shift; + my $lineToBeginWith = shift; + my $NULL = "" ; + my $diff_f1 = $NULL ; + my $diff_f2 = $NULL ; + my $retval = $NULL ; + my $ret; + open(F1, "$f1") or die "Could not open file $f1"; + open(F2, "$f2") or close(F1), die "Could not open file $f2"; + + while (defined($l1 = <F1>)) { + if ($lineToBeginWith){ + $lineToBeginWith -- ; + next ; + } + next if ($l1 =~ /^\#/); + $ret = defined($l2 = <F2>); + if ($ret) { + $ret = defined($l2 = <F2>) while ($ret && ($l2 =~ /^\#/)) ; + if ($ret) { + if (!($l1 eq $l2)) { + + # ignore whitespace + $l1_clean = $l1 ; + $l2_clean = $l2 ; + $l1_clean =~ s/\s//g; + $l2_clean =~ s/\s//g; + + if (!($l1_clean eq $l2_clean)) { + $diff_f1 .= "${l1}" unless ($l1_clean eq $NULL); + $diff_f2 .= "${l2}" unless ($l2_clean eq $NULL); + } + } + } + else { + next if ($l1 =~ /^\s*$/) ; + $diff_f1 .= "${l1}"; + } + } + else { + next if ($l1 =~ /^\s*$/) ; + $diff_f1 .= "${l1}"; + } + } + + while (defined($l2 = <F2>)) { + if (($l2 =~ /^\#/) || ($l2 =~ /^\s*$/)) { + next ; + } + else { + $diff_f2 .= "${l2}" ; + } + } + + close(F1); + close(F2); + + $retval .= "- differences present in your config file but not in standard file:\n\n". "$diff_f1\n" if ($diff_f1) ; + $retval .= "- differences present in standard file but not in your config file:\n\n" . "$diff_f2" if ($diff_f2) ; + return $retval ; +} + +sub CompareStdConfigFiles { + # Compare each configuration file against its default version. If it has changed, + # notify the user that the file has changed and will need to be checked by the + # user. This should be safe to do because there should be no path information + # stored in these conf files, which are just schema stuff. + # printTrace("\nCheck if standard configuration files have changed",3); + + # get the version of the DS to migrate + ($oldVersion, $oldMinor) = &getVersion($oldDir); + # get the version of the new DS + ($Version, $Minor) = &getVersion($root); + + my $origFilePath = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}install${PATHSEP}config${PATHSEP}" ; + my $FilesChanged = ""; + my $AllDiffs = "***********************************************************************"; + my $NoChanges = "" ; + my $lineToBegin = 0 ; + printTrace("\nVersion of the old directory server: $oldVersion.$oldMinor",0); + opendir(CONFDIR, $oldConfDir) or + die "Error: could not open migrated config dir $oldConfDir: $!"; + + foreach $file (readdir(CONFDIR)) { + $origFile = $origFilePath . $file ; + $configFile = $oldConfDir . $file ; + if ((! exists($userDefinedConfigFiles{lc($file)})) && (-f $origFile)) { + my $lineToBegin = 1 if (lc($file) eq "slapd-collations.conf"); # we ignore the first line of slapd-collations + $diffs = &diff($configFile, $origFile, $lineToBegin); + $lineToBegin = 0 if $lineToBegin ; + if ($diffs) { + $FilesChanged .= "\n$configFile"; + $AllDiffs .= "\n$configFile is different than the standard configuration file" ; + $AllDiffs .= "\nYou will need to check this file and make sure its changes are compatible "; + $AllDiffs .= "with the new directory server\nHere are the differences:\n"; + $AllDiffs .= "$diffs \n\n"; + $AllDiffs .= "***********************************************************************"; + } + else { + $NoChanges .= "\n$configFile"; + } + } + } + closedir(CONFDIR); + +if ($FilesChanged) { + printTrace("\nNo changes to old configuration files:$NoChanges",3) ; + printTrace("\n***********************************************************************",3) ; + printMsg("\nThe following standard files have been modified: $FilesChanged"); + if ($NO_INPUT_USER) { + # do nothing + } + else { + printMsg("\nDo you want to see the differences Yes/No [No] ?") ; + my $answer = <STDIN> ; + if ($answer =~ /y|yes/i) { + printMsg("$AllDiffs"); + } + printMsg("\nDo you want to continue the migration Yes/No [No] ?"); + $answer = <STDIN> ; + if (! ($answer =~ /y|yes/i)) { + exit(1); + } + } + } +} + + +############################################################################# + +sub db2ldif { + my ($conf, $ldif_dir) = @_; + $ENV{"$LIB_PATH"}="$oldDir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + if (!$conf) { + $conf = "$oldHome${PATHSEP}config${PATHSEP}slapd.conf"; + } + if (! $ldif_dir) { $ldif_dir = $ldif_rep ;} + if (!(-d $ldif_dir)) { + mkdir($ldif_dir,0777) or die "can't create $ldif_rep to store temporary ldif files"; + } + my $dir = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server"; + chdir($dir) or + die "Error: could not change directory to $dir: $!"; + my @suffixnames = keys(%DBNAMES) ; + foreach $suffixname (@suffixnames) { + my $ldif_file = $ldif_dir.$DBNAMES{$suffixname}.".ldif" ; + # If we are on NT, ${quote} is setup to "\"", else it's setup to "" + # As the suffix can contain some space characters, I write the suffix parameter: "\"$suffixname\"" rather than "${quote}$suffixname${quote}" + my @cmd = + ( "${quote}$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" . + "${PATHSEP}$slapdExecName${quote}", "db2ldif", '-n', '-f', + "${quote}$conf${quote}", '-a', "${quote}$ldif_file${quote}", + '-d', '1','-s',"\"$suffixname\"" ); + open(DB2LDIF, "${quote}@cmd${quote} 2>&1|") or + die "Error: could not execute @cmd: $!"; + sleep(1); # allow pipe to fill with data + $ii = 0; # counter + while (<DB2LDIF>) { + ++$ii; + if (($ii % 250) == 0) { + printMsg(" Processing...\n"); + } + } + close(DB2LDIF); + # set the ownership of the ldif file; should be the same as the 5.x slapd user id + if ((! $isNt) && ($oldlocaluser ne $localuser)) { + if (-f $ldif_file) { + chown( $newuid, $newgid, $ldif_file) or printMsg("\nUnable to change the ownership of $ldif_file to $localuser") ; + } + } + } + print " Done.\n"; + chdir($curdir) or die "Could not change directory to $curdir: $!"; +} + +############################################################################# + +# this is used to run the system() call, capture exit and signal codes, +# and die() upon badness; the first argument is a directory to change +# dir to, if any, and the rest are passed to system() +sub mySystem { + my $rc = &mySystemNoDie(@_); + my ($dir, @args) = @_; + if ($rc == 0) { +# success + } elsif ($rc == 0xff00) { + die "Error executing @args: error code $rc: $!"; + } elsif ($rc > 0x80) { + $rc >>= 8; + die "Error executing @args: error code $rc: $!"; + } else { + if ($rc & 0x80) { + $rc &= ~0x80; + } + die "Error executing @args: received signal $rc: $!"; + } + + # usually won't get return value + return $rc; +} + +# This version does not die but just returns the error code +sub mySystemNoDie { + my ($dir, @args) = @_; + if ($dir && ($dir ne "")) { + chdir($dir) or die "Could not change directory to $dir: $!"; + } + my $cmd = $args[0]; + # the system {$cmd} avoids some NT shell quoting problems if the $cmd + # needs to be quoted e.g. contains spaces; the map puts double quotes + # around the arguments on NT which are stripped by the command + # interpreter cmd.exe; but don't quote things which are already quoted + my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @args; + my $rc = 0; + if ($cmd =~ /[.](bat|cmd)$/) { + # we have to pass batch files directly to the NT command interpreter + $cmd = $com_spec; +# print "system $cmd /c \"@fixargs\"\n"; + $rc = 0xffff & system {$cmd} '/c', "\"@fixargs\""; + } else { +# print "system $cmd @fixargs\n"; + $rc = 0xffff & system {$cmd} @fixargs; + } + chdir(${curdir}) or die "Could not change directory to $curdir: $!"; + return $rc; +} + +############################################################################# +sub manyLdif2db { + my %rev_dbnames = reverse(%DBNAMES); + @backends = keys(%rev_dbnames); + $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + chdir($slapdExecDir) or die "Could not change directory to $slapdExecDir: $!"; + foreach $backend (@backends) { + my $ldif = "${ldif_rep}$backend.ldif" ; + &Ldif2db($ldif, $backend); + } + # remove the empty ldif directory + rmdir($ldif_rep); + chdir($curdir) or die "Could not change directory to $curdir: $!"; +} + + +sub Ldif2db { + my $ldif = shift ; + my $backend = shift ; + my $ldif2db_param = "ldif2db -D $serverHome -n $backend -i $ldif"; + open(LDIF2DB, "${quote}${quote}$slapdExecName${quote} $ldif2db_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n"; + sleep(1); # allow some data to accumulate in the pipe + while (<LDIF2DB>) { + printMsg($_); + } + close(LDIF2DB); + # remove the ldif file after the import + unlink($ldif) ; +} + +############################################################################# + +#sub copyBak { +# opendir( OLDBAK, "$oldHome${PATHSEP}bak" ) || +# die "Can't open directory $oldHome${PATHSEP}bak: $!: "; +# local ( @dirs ) = readdir( OLDBAK ); +# closedir ( OLDBAK ); +# for ( @dirs ) { +# if ( $_ eq "." || $_ eq ".." ) { +# next; +# } elsif ( -d "$oldHome${PATHSEP}bak${PATHSEP}$_" ) { +# $srcDir = "$oldHome${PATHSEP}bak${PATHSEP}$_"; +# $destDir = "$serverHome${PATHSEP}bak${PATHSEP}$_"; +# $srcLDIF = "$oldHome${PATHSEP}ldif${PATHSEP}bak.ldif"; +# $destLDIF = "$serverHome${PATHSEP}ldif${PATHSEP}bak.ldif"; +# mkdir( $destDir , 0755 ) if !( -e $destDir); +# # Converting database +# if ( !$isNT && $newuser ) { +# chown($newuid, $newgid, +# "$serverHome${PATHSEP}bak", $destDir); +# } +# &other_db2ldif($srcDir, $srcLDIF); +# if ($needAclUpg) { +# &mySystem("$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server", +# "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" . +# "${PATHSEP}aclupg$exe_suffix", '-d', '-i', +# $srcLDIF, '-o', $destLDIF); +# } else { +# ©BinFile($srcLDIF, $destLDIF); +# } +# &other_ldif2db($destLDIF, $destDir); +# } +# } +#} +############################################################################# + +sub startServer { + my $instanceDir = ${serverHome} ; + my $errLog = $instanceDir . $PATHSEP . 'logs' . $PATHSEP . 'errors'; + # emulate tail -f + # if the last line we see does not contain "slapd started", try again + my $done = 0; + my $started = 0; + my $code = 0; + my $lastLine = ""; + my $timeout = time + 240; # 4 minutes + $ENV{"$LIB_PATH"}="${root}${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + + my $startCmd = $instanceDir . $PATHSEP . 'start' . $script_suffix; + if (! -f $startCmd) { + $startCmd = $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix; + } + printTrace("\nInstanceDir: $instanceDir\n",4); + $code = &mySystem($instanceDir,$startCmd); + open(IN, $errLog) or die "Could not open error log $errLog: $!"; + my $pos = tell(IN); + while (($done == 0) && (time < $timeout)) { + for (; ($done == 0) && ($_ = <IN>); $pos = tell(IN)) { + $lastLine = $_; + # print; + # the server has already been started and shutdown once . . . + if (/slapd started\./) { + $started++; + if ($started == 2) { + $done = 1; + } + # sometimes the server will fail to come up; in that case, restart it + } elsif (/Initialization Failed/) { + # print "Server failed to start: $_"; + $code = &mySystem($instanceDir, $startCmd); + # sometimes the server will fail to come up; in that case, restart it + } elsif (/exiting\./) { + # print "Server failed to start: $_"; + #$code = &mySystem($startCmd); + + $code = &mySystem($instanceDir, $startCmd); + } + } + if ($lastLine =~ /PR_Bind/) { + # server port conflicts with another one, just report and punt + print $lastLine; + print "This server cannot be started until the other server on this\n"; + print "port is shutdown.\n"; + $done = 1; + } + if ($done == 0) { + # rest a bit, then . . . + sleep(2); + # . . . reset the EOF status of the file desc + seek(IN, $pos, 0); + } + } + close(IN); + + if ($started < 2) { + $! = $code; + # $now = time; + # if ($now > $timeout) { + # print "Possible timeout: timeout=$timeout now=$now\n"; + # } + die "Error: could not start server: $!"; + } + + return 0; +} + +sub stopServer { + my $root = shift; + my $name = shift; + $maxStopIterations = 5; + print "\nShutting down server $name . . .\n"; + + $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop' . $script_suffix . $quote; + if (! -f $stopCmd) { + $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop-slapd' . $script_suffix . $quote; + } + + if (! -f $stopCmd) { + # no stop command, probably a 1.X system; for NT, we'll try net stop + # for unix, we'll get the pid and kill it + if ($isNT) { + $stopCmd = 'net stop ' . $name; + } else { + # see if there is a pid file + $pidfile = $root . $PATHSEP . $name . $PATHSEP . 'logs' . + $PATHSEP . 'pid'; + if (open(PIDFILE, $pidfile)) { + chomp($pid = <PIDFILE>); + close(PIDFILE); + while ($maxStopIterations-- && !$exitCode) { + $exitCode = kill(15, $pid); + } + $stopCmd = undef; + } + } + } + + # keep looping until the stop cmd returns an error code, which usually + # means that what ever we want to stop is stopped, or some other error + # occurred e.g. permission, or no such service + $exitCode = &runAndIgnoreOutput($stopCmd); +# print "stopServer: exitCode=$exitCode\n"; + while ($stopCmd && $maxStopIterations-- && $exitCode) { + $exitCode = &runAndIgnoreOutput($stopCmd); +# print "stopServer: exitCode=$exitCode\n"; + } + + if (!$maxStopIterations) { + print "Warning: could not shutdown the server: $!\n"; + } + + sleep(10) ; + + $exitCode = 0; + +} + + +sub runAndIgnoreOutput { + my $cmd = shift; + printMsg("."); + open(RUNCMD, "${quote}$cmd${quote} 2>&1 |") or die "Error: could not run $cmd: $!"; + printMsg("."); + sleep(1); # allow pipe to fill with data + printMsg("."); + while (<RUNCMD>) { +# print; + } + my $code = close(RUNCMD); +# print "runAndIgnore: code=$code status=$?\n"; + return $?; +} +############################################################################# +# migrate some of entries present in the old DSE.ldif like +# cn=snmp,cn=config +# cn=encryption,cn=config +# all the aci's + +sub MigrateDSE { + printTrace("\nMigrate DSE entries...",1); + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($old_entry = readOneEntry $in) { + my $DN = $old_entry->getDN() ; + SWITCH: { + # migrate the entrie: cn=snmp,cn=config + if ($DN =~ /^cn=SNMP,cn=config$/i) { + my $entry = $conn->search("$DN","base","objectclass=nsSNMP"); + if ($entry) { + my $res = $conn->update($old_entry); + if ($res) { + printTrace("\n$DN updated !",2); + } + else { + printMsg("\nFailed to update $DN"); + } + } + else { + printMsg("\nUnable to get info under $DN"); + } + last SWITCH; + } + # migrate the entrie: cn=encryption,cn=config + if ($DN =~ /cn=encryption,cn=config$/i) { + if ($conn->search("$DN","base","objectclass=*")) { + my $res = $conn->update($old_entry); + if ($res) { + printTrace("\n$DN updated !",2); + } + else { + printMsg("\nFailed to update $DN"); + } + } + else { + my $res = $conn->add($old_entry); + if ($res) { + printTrace("\n$DN added !",2); + } + else { + printMsg("\nFailed to add $DN"); + } + } + last SWITCH; + } + if (@{$old_entry->{aci}} && (! ($DN =~ /^cn=monitor$/i)) && (! ($DN =~ /^cn=schema$/i))) { + # migrate aci's + my $entry = $conn->search("$DN","base","objectclass=*"); + if ($entry) { + my $res = $conn->update($old_entry); + if ($res) { + printTrace("\n$DN updated !",2); + } + else { + printMsg("\nFailed to update $DN"); + } + } + else { + my $res = $conn->add($old_entry); + if ($res) { + printTrace("\n$DN added !",2); + } + else { + printMsg("\nFailed to add $DN"); + } + } + last SWITCH; + } + } + } + close(DSELDIF); +} +############################################################################# +# migrate SSL info + +sub MigrateSSL { + my $secPwd = 'bidon' ; + # copy the SSL directory + ©Dir("$oldHome${PATHSEP}ssl","$serverHome${PATHSEP}ssl"); + # copy the cert db and key files + if ( -d "$oldDir${PATHSEP}alias") { + $aliasDir = "$root${PATHSEP}alias"; + if (! -d $aliasDir) { + mkdir($aliasDir, 0750); + } + my $keydb = "$aliasDir${PATHSEP}slapd-$newname-key3.db" ; + my $certdb = "$aliasDir${PATHSEP}slapd-$newname-cert7.db" ; + my $old_keydb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-key3.db" ; + my $old_certdb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-cert7.db"; + my $keydb_backup = "$aliasDir${PATHSEP}slapd-$newname-key3.db_backup" ; + my $certdb_backup = "$aliasDir${PATHSEP}slapd-$newname-cert7.db_backup" ; + if (-f $old_keydb) { + if (-f $keydb) { + if ($NO_INPUT_USER) { + printMsg("\n$keydb already exists. backup in $keydb_backup ..."); + ©BinFile($keydb,$keydb_backup); + ©BinFile($old_keydb,$keydb); + } + else { + print("\n\n$keydb already exists. Do you want to overwrite it ? [no]: "); + my $answer = <STDIN> ; + if ($answer =~ /^y|yes$/i) { + ©BinFile($old_keydb,$keydb); + } + } + } + else { + ©BinFile($old_keydb,$keydb); + } + } + if (-f $old_certdb) { + if (-f $certdb) { + if ($NO_INPUT_USER) { + printMsg("\n$certdb already exists. backup in $certdb_backup ..."); + ©BinFile($certdb,$certdb_backup); + ©BinFile($old_certdb,$certdb); + } + else { + print("\n\n$certdb already exists. Do you want to overwrite it ? [no]: "); + my $answer = <STDIN> ; + if ($answer =~ /^y|yes$/i) { + ©BinFile($old_certdb,$certdb); + } + } + } + else { + ©BinFile($old_certdb,$certdb); + } + } + # copy the old password file + if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") { + ©BinFile( + "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt", + "$aliasDir${PATHSEP}$type-$newname-pin.txt" + ); + } + } + +} + +sub DisableSSL { + my $entry = $conn->search("cn=config","base","objectclass=*"); + my $LDAPparam = "nsslapd-security" ; + my $Value = "off" ; + if ($entry->{$LDAPparam}[0] ne $Value) { + printTrace("\nDisable SSL...",1); + $entry->setValues($LDAPparam, $Value); + } + my $res = $conn->update($entry); + if ($res) { + printTrace("\nSSL disabled",2); + } + else { + printMsg("\nCan't disabled SSL. The server may have problems to start"); + } +} + +# enable the migration of client authentication informations +sub MigrateCertmap { + # backup the old 5.x certmap.conf and replace it with the 4.x certmap.conf file + my $oldCertmap = "$oldDir${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf"; + my $newCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf" ; + my $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ; + if (&hasChangedoldCertmap($oldCertmap)) { + if ($NO_INPUT_USER) { + printMsg("\n$newCertmap has been backup in $backupCertmap"); + ©BinFile($newCertmap,$backupCertmap); + ©BinFile($oldCertmap,$newCertmap); + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\n\nWhere do you want to back up the file $newCertmap [$backupCertmap] ?") ; + my $Answer = <STDIN> ; + $backupCertmap = $Answer if ($Answer ne "\n"); + chomp($backupCertmap); + printTrace("\nDest: .$backupCertmap.",4); + if (-e $backupCertmap) { + printMsg("\n\n$backupCertmap already exists. Do you want to overwrite it Yes/No [No] ?") ; + if (<STDIN> =~ /yes|y/i) { + $Ask = 0 ; + } + else { + $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ; + } + } + else { + $Ask = 0 ; + } + } + printTrace("\nBackup file: $newCertmap in $backupCertmap",4); + ©BinFile($newCertmap,$backupCertmap); + ©BinFile($oldCertmap,$newCertmap); + } + } + else { + } +} + +sub hasChangedoldCertmap { + my $certmapfile = shift ; + my @reference = ("certmap default default", + "default:DNComps", + "default:FilterComps e") ; + my $cpt = 0 ; + printTrace("\nhasChangedoldCertmap",3); + open(CERTMAP,"< $certmapfile"); + while (<CERTMAP>) { + if ((! /^\s*#/) && (! /^\s*$/)) { + my $ref = $reference[$cpt] ; + printTrace("\nValue: $_, ref: $ref",4); + if (! /^\s*$ref\s*$/) { + return 1 ; + } + else { + $cpt++ ; + } + } + } + close (CERTMAP); + printTrace("\ncpt: $cpt",4); + if ($cpt < $#reference) { + return 1 ; + } + else { + return 0 ; + } +} +############################################################################# +# copy a directory to another + +sub copyDir { + my $src = shift; + my $dest = shift; + my $exclude = shift; + + opendir( SRC, $src ) or die "Can't open directory $src: $!: "; + my $mode; + my $uid; + my $gid; + mkdir ( $dest , 0755 ) or die "\nCan't create directory $dest. \nPlease check you have enough rights to create it and/or check that your parent directory exists.\n" if !( -e $dest ); + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + local ( @files ) = readdir ( SRC ); + closedir( SRC ); + for ( @files ) { + if ( $_ eq "." || $_ eq ".." ) { + next; + } elsif ( $exclude && /$exclude/ ) { + next; + } elsif( -d "$src${PATHSEP}$_") { + ©Dir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" ); + } else { + ©BinFile ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_"); + } + } +} + +sub copyBinFile { + my $src = shift; + my $dest = shift; + my $buf = ""; + my $bufsize = 8192; + + open( SRC, $src ) || die "Can't open $src: $!\n"; + # if we are given a directory destination instead of a file, extract the + # filename portion of the source to use as the destination filename + if (-d $dest) { + $dest = $dest . $PATHSEP . &basename($src); + } + open( DEST, ">$dest" ) || die "Can't create $dest: $!\n"; + binmode SRC; + binmode DEST; + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + while (read(SRC, $buf, $bufsize)) { + print DEST $buf; + } + close( SRC ); + close( DEST ); +} +############################################################################# +# backup 5.x configuration files +# backup the directory <root_server5>/slapd-instance/config dans <root_server5>/slapd-instance/BackupConfig + +sub backupConfigFiles { + # backup the 5.x config files + my $src = "$serverHome${PATHSEP}config" ; + my $dest = "$serverHome${PATHSEP}config_backup" ; + if ($NO_INPUT_USER) { + printMsg("\n$src has been backup in $dest"); + ©Dir($src,$dest); + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\n\nWhere do you want to back up your configuration directory [$dest] ?") ; + my $Answer = <STDIN> ; + $dest = $Answer if ($Answer ne "\n"); + chomp($dest); + printTrace("\nDest: .$dest.",4); + if (-e $dest) { + printMsg("\n\n$dest already exists. Do you want to overwrite it Yes/No [No] ?") ; + if (<STDIN> =~ /yes|y/i) { + $Ask = 0 ; + } + else { + $dest = "$serverHome${PATHSEP}config_backup" ; + } + } + else { + $Ask = 0 ; + } + } + printTrace("\nBackup Directory: $src in $dest",4); + ©Dir($src,$dest); + } +} +############################################################################# + +sub getLDAPservername { + my $oldLDAPservername; + my $LDAPservername; + open(OLDSLAPDCONF, $oldSlapdConf) or + die "\nError: could not open old config file $oldSlapdConf \n"; + while(<OLDSLAPDCONF>) { + chop; + if (/^localhost\s+/i) { + ($oldLDAPservername = $') =~ s/^[\"]//;; + $oldLDAPservername =~ s/[\"]$//; + printTrace("\nName of the old LDAP server: $oldLDAPservername",3); + } + } + close(OLDSLAPDCONF); + + open( DSELDIF, "< $DSEldif" ) || die "\nCan't open $DSEldif \n"; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + my $DN = $entry->getDN() ; + if ($DN =~ /^cn=config$/i) { + my $localhost = "nsslapd-localhost"; + my @values = $entry->getValues($localhost); + if ($#values != -1) { + $LDAPservername = $values[0]; + } + break; + } + } + close(DSELDIF); + # check 4.x and 5.x are installed on the same physical machine. + if (lc($oldLDAPservername) ne lc($LDAPservername)) { + # warn the user he tries to migrate a 4.x server installed on a different machine from the 5.x one + printMsg("\n\nYour 4.x server is on $oldLDAPservername, and your 5.x server is on $LDAPservername. We don't support migration on different machines. Do you want to continue ? Yes/No [No]:") ; + if (! (<STDIN> =~ /yes|y/i)) { + return -1; + } + } + return $LDAPservername ; +} + +############################################################################# + +sub getVersion { + my $dir = shift; + my $version = 0; + my $minor = 0; + my $buildNumber = 0; + my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}"; + + # find the slapd executable + $prog = $dir . $progDir . $slapdExecName; + if (! -f $prog) { + $prog = $dir . $progDir2 . $slapdExecName; + if (-f $prog && $isNT) { + # if slapd is in bin/slapd and we're on NT, just assume version 1; + # apparently, slapd.exe doesn't like the -v argument . . . + return ( '1', $minor ); + } + else{ + die "Could not run slapd program $prog: $!"; + } + } + else { + chdir($dir . $progDir); + } + $ENV{"$LIB_PATH"}="$dir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + # read the old version from the old slapd program + + open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or + die "Could not run slapd program $prog: $!"; + sleep(1); # allow some data to accumulate in the pipe +# print "Output from $prog -v:\n"; + while (<F>) { + print; + if (/^Netscape-Directory\/(\d+)\.(\d+)\s+(\S+)/) { + $version = $1; + $minor = $2; + $buildNumber = $3; + last; + } + elsif (/^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ... + $version = $1; + $minor = $2; + $buildNumber = $3; + last; + } + elsif (/^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) { + $version = $1; + $minor = $2; + $buildNumber = $3; + last; + } + } + $code = close(F); +# print "$prog returned code=$code status=$?\n"; + $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + + if ($version == 0) { + printMsg("\nCould not determine version of the directory server in $dir: "); + printMsg("\nBe careful, this script is designed to migrate only from 4.x Netscape Directory Server to 5.x. Do you want to continue ? [no]: "); + my $answer = <STDIN> ; + if (! ($answer =~ /y|yes/i)) { + exit(1); + } + $version = 4 ; # setup to 4 and pray ... + } + + # distinguish the 4.1 and the 4.11 thanks to the buildNumber + if (($version == 4) && ($minor == 1)){ + if (! ($buildNumber =~ /^B99\.16/)) { + # it's not a 4.1 Netscape Directory Server => it's a 4.11 + $minor = 11 ; + } + } + return ( $version, $minor ); +} + +############################################################################# + +sub getDiff { + # we get references to arrays + my $elements = shift ; + my $existing_elements = shift ; + my %count = () ; + my %countEE = () ; + @diff = () ; + foreach $e (@{$elements}, @{$existing_elements}) { $count{$e}++ ;} + foreach $e (@{existing_elements}) { $countEE{$e}++ ;} + foreach $e (@{$elements}) { + # if $e is only present in @$elements, we push it to the diff array + if (($count{$e} == 1) && ($countEE{$e} == 0)) { + push @diff, $e ; + } + } + return @diff ; +} + +############################################################################################### +sub testIndexUpdating { + #my $entry = $conn->newEntry(); + #$entry->setDN("cn=djeattribute,cn=index,cn=MigratedDB_5,cn=ldbm database,cn=plugins,cn=config"); + my $entry = $conn->search("cn=mail,cn=index,cn=MigratedDB_2,cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex"); + my @types = ("pres", "sub", "eq") ; + my @existing_types = $entry->getValues("nsindextype"); + my @typesToAdd = &getDiff(\@types, \@existing_types); + foreach $newtype (@typesToAdd) { + $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2); + } + my $res = $conn->update($entry) ; + if ($res) {print("\nUpdate index mail\n");} + else { print("\ncan't update index mail");} + + $entry = $conn->search("cn=givenName,cn=index,cn=MigratedDB_2,cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex"); + @types = ("pres", "sub", "eq") ; + @existing_types = $entry->getValues("nsindextype"); print("\ngivenName, existing_types: @existing_types"); + @typesToAdd = &getDiff(\@types, \@existing_types); print("\nTypesToAdd: @typesToAdd"); + foreach $newtype (@typesToAdd) { + $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2); + } + my $res = $conn->update($entry) ; + if ($res) {print("\nUpdate index givenName\n");} + else { print("\ncan't update index givenName");} + } + + +############################################################################################### +sub normalizeDir { + my $dir = shift ; + my $dir_prec = "" ; + while ($dir_prec ne $dir) { + $dir_prec = $dir ; + if ($isNT) { + grep { s@\\\\@\\@g } $dir ; + } + else { + grep { s@//@/@g } $dir ; + } + } + return $dir ; +} + + +############################################################################################### +# return 1 if the value parameters is +sub isAllowedPlugin { + my $Value = lc(shift) ; + if ($allowedPlugins{$Value}) { + return 1 ; + } + else { + return 0 ; + } + +} + + +sub getSyntaxOid { + my $Value = lc(shift) ; + return $allowedPlugins{$Value} ; +} + +############################################################################################### +# return 1 if the value given in parameters is an allowed modifier +sub isAllowedModifier { + my $Value = lc(shift) ; + if ($allowedModifiers{$Value}) { + return 1 ; + } + else { + return 0 ; + } +} + +sub getModifierValue { + my $Value = lc(shift) ; + return $allowedModifiers{$Value} ; +} + +############################################################################################### + +sub GetTime { + my $tm = localtime; + (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900); + $sec = "0$sec" unless $sec > 9 ; + $min = "0$min" unless $min > 9 ; + $hour = "0$hour" unless $hour > 9 ; + $dd = "0$dd" unless $dd > 9 ; + $mm = "0$mm" unless $mm > 9 ; + return ($sec, $min, $hour, $dd, $mm, $yy); +} + +############################################################################################### +# get uid and group id of the 5.x slapd server. +# The uid is done through the nsslapd-localuser attribute + +sub getuid_gid { + my $newuid ; + my $newgid ; + my $localuser ; + my $localuser_attr = "nsslapd-localuser" ; + if (! $isNT) { + my $entry = $conn->search("cn=config ", "base","objectclass=*", 0, ($localuser_attr)) ; + # Tests wether we succeed to get the entry cn=config + die "\nCan't get the entry cn=config \n" unless ($entry); + my @values = $entry->getValues($localuser_attr); + if ($#values == -1 || ($values[0] eq "") ) { # tests wether the nsslapd-localuser attribute has a value + printMsg("\nNo localuser has been found in the configuration of the directory. "); + if ($NO_INPUT_USER) { + printMsg("\nWe considered nobody as the localuser"); + $localuser = "nobody" ; + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\nUnder what user does your $Version.$Minor directory server run [nobody] ? ") ; + $localuser = <STDIN> ; + chomp($localuser); + $localuser = "nobody" if ($localuser eq ""); + ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ; + if ($newuid) { + $Ask = 0 ; + } + else { + printMsg("\nError: $localuser is unknown from the system "); + } + } + } + } + else { + $localuser = $values[0]; # returns the first value (we should only have one localuser) + my $size = $#values ; + } + ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ; + return ($localuser, $newuid, $newgid) ; + } + else { + return () ; + } +} + + +############################################################################################### +# get uid and group id of the 4.x slapd server. + +sub getolduid_gid { + my $oldlocaluser ; + if (! $isNT) { + open(CONF, $oldSlapdConf) or die "\nError: cannot open $oldSlapdConf: $!\n"; + while (<CONF>) { + if (/^localuser\s+/i) { + chomp($oldlocaluser = $'); + last; + } + } + close(CONF); + ($olduid, $oldgid) = (getpwnam("$oldlocaluser"))[2..3] ; + return ($oldlocaluser, $olduid, $oldgid) ; + } + else { + return (); + } +} + +############################################################################################### +# get current directory + +sub getCwd { + my $command = $isNT ? "cd" : "/bin/pwd"; + open(PWDCMD, "$command 2>&1 |") or + die "Error: could not execute $command: $!"; + # without the following sleep, reading from the pipe will + # return nothing; I guess it gives the pwd command time + # to get some data to read . . . + sleep(1); + my $currentdir; + while (<PWDCMD>) { + if (!$currentdir) { + chomp($currentdir = $_); + } + } + my $code = close(PWDCMD); +# if ($code || $?) { +# print "$command returned code=$code status=$? dir=$curdir\n"; +# } +# print "getCwd curdir=\[$curdir\]\n"; + return $currentdir; +} diff --git a/ldap/admin/src/scripts/template-migrateTo6 b/ldap/admin/src/scripts/template-migrateTo6 new file mode 100644 index 00000000..91174b41 --- /dev/null +++ b/ldap/admin/src/scripts/template-migrateTo6 @@ -0,0 +1,3268 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# Migrate a old directory server to a 6.2 directory server + +######################################################################################################## +# enable the use of Perldap functions +require DynaLoader; + +use Getopt::Std; +use Mozilla::LDAP::Conn; +use Mozilla::LDAP::Entry; +use Mozilla::LDAP::LDIF; +use Mozilla::LDAP::Utils qw(:all); +use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API +use Time::localtime; + +######################################################################################################## +use Class::Struct ; # load struct-building module + +struct S_index => { + names => '@' , + types => '@' , + oids => '@' , + specific => '$' + }; + + +struct S_plugin => { + name => '$' , + type => '$' , + enable => '$' , + args => '@' + }; +##################################################################################################### + +sub usage { + print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n"); + print(STDERR " -o OldInstancePath -n NewInstancePath [-t tracelevel] [-L logfile]\n"); + print(STDERR "************** parameters in brackets are optionals, others are required **************\n"); + print(STDERR " Opts: -D rootdn - New Directory Manager\n"); + print(STDERR " : -w password - New Directory Manager's password\n"); + print(STDERR " : -w - - Prompt for New Directory Manager's password\n"); + print(STDERR " : -j filename - Read New Directory Manager's password from file\n"); + print(STDERR " : -p port - New Directory Server port\n"); + print(STDERR " : -o OldInstancePath - Path of the Old instance to migrate \n"); + print(STDERR " : -n NewInstancePath - Path of the new instance\n"); + print(STDERR " : [-d dataPath] - Path to directory containing data files to import into new instance\n"); + print(STDERR " : [-v oldVersion] - Old version (obtained by running $slapdExecName -v\n"); + print(STDERR " : [-t tracelevel] - specify the level of trace (0..3)\n"); + print(STDERR " : [-L logfile] - specify the file to log the migration report \n"); + + + } + + + +############# +BEGIN { + + require 'uname.lib' ; + $isNT = -d '\\'; + $PATHSEP = $isNT ? "\\" : "/"; + ${SEP} = $isNT ? ";" : ":" ; + @INC = ( '.', '../../../admin/admin/bin'); + grep { s@/@\\@g } @INC if $isNT; + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + # NT needs quotes around some things unix doesn't + $quote = $isNT ? "\"" : ""; + + # If this variable is set, all file/directory creation will make sure the mode + # and ownership of the destination is the same as the source + $PRESERVE = 1 if (!$isNT); + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + if ($isNT) { + $os = "WINNT"; + } else { + $os = &uname("-s"); + } + if ($isNT) { + # we have to pass batch files directly to the NT command interpreter + $com_spec = $ENV{ComSpec}; + if (!$com_spec) { + $com_spec = $ENV{COMSPEC}; + } + if (!$com_spec || ! -f $com_spec) { + # find the first available command interpreter + foreach $drive (c..z) { + $com_spec = "$drive:\\winnt\\system32\\cmd.exe"; + last if (-f $com_spec); + $com_spec = undef; + } + if (! $com_spec) { + # punt and pray + $com_spec = 'c:\winnt\system32\cmd.exe'; + } + } + } + if ( $os eq "AIX" ) { + $dll_suffix = "_shr.a"; + } + elsif ( $os eq "HP-UX" ) { + $dll_suffix = ".sl"; + } + elsif ( $os eq "WINNT" ) { + $dll_suffix = ".dll"; + } + else { + $dll_suffix = ".so"; + } + $slapdExecName = $isNT ? 'slapd.exe' : './ns-slapd'; + # if this flag is set, we will migrate the old database + # by doing a db2ldif -> ldif2db; + $convertToLDIF = 1; + select STDERR; + $| = 1; + select STDOUT; + $| = 1; + # if the old value for dbcachesize is less than this, make it this + $MIN_DBCACHESIZE = '500000'; +} + +SWITCH: { + if ($os eq "AIX") { + $LIB_PATH = "LIBPATH" ; + last SWITCH ; + } + if ($os eq "HP-UX") { + $LIB_PATH = "SHLIB_PATH" ; + last SWITCH ; + } + if ($isNT) { + $LIB_PATH = "PATH" ; + last SWITCH ; + } + else { + $LIB_PATH = "LD_LIBRARY_PATH" ; + last SWITCH ; + } + } + + # Old parameters + ${oldDir} = "" ; + ${oldname} = "" ; + ${oldHome} = "" ; + ${oldConfDir} = "" ; + ${oldlocaluser} ; + ${olduid} ; + ${oldgid} ; + + # New parameters + ${root} = "{{DS-ROOT}}" ; + ${type} = "" ; + ${newname} = "" ; + ${newport} = "" ; + ${rootDN} = "" ; + ${rootpwd} = "" ; + ${localhost} = "" ; + ${LogFileReport} = "" ; + ${newuid} ; + ${localuser} ; + ${newgid} ; + $NO_INPUT_USER = 0 ; # by default user can give inputs during the migration process + ${curdir} = getCwd(); + ${slapdExecDir} = "${root}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + + # specify the level of trace + $TRACELEVEL=1; + + $LDAP_SERVER_UNREACHABLE = 81; + + # get input users + &getParameters() ; + ${oldDir} = &normalizeDir("${oldDir}"); + ${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ; + ${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ; + ${oldSlapdConf} = "${oldConfDir}slapd.conf" ; + ${oldDSEldif} = "${oldConfDir}dse.ldif" ; + ${serverHome} = "${root}${PATHSEP}$type-$newname" ; + ${DSEldif} = "$serverHome${PATHSEP}config${PATHSEP}dse.ldif"; + ${ldif_rep} = "${oldConfDir}${PATHSEP}ldif${PATHSEP}" ; + ${oldSlapdExecDir} = "${oldDir}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + + + + + open(LOGFILE, ">> $LogFileReport"); + + printTrace("\noldDir: $oldDir, oldHome: $oldHome, \noldConfDir: $oldConfDir, \noldSlapdConf: $oldSlapdConf, \nldif_rep: $ldif_rep, \nrootDN: $rootDN, \nPwd: ******, \nPort: $newport, \nNewname: $newname\n",3); + printTrace("\nLIB_PATH: $LIB_PATH",4); + + if (!(-d $serverHome)) { + printMsg("\n$serverHome doesn't exist\n"); + exit(1); + } + if (!(-d $oldHome)) { + printMsg("\n$oldHome doesn't exist\n"); + exit(1); + } + + if ($olddatadir && !(-d $olddatadir)) { + print("\n$olddatadir doesn't exist\n"); + exit(1); + } + +#define CONFIG_DATABASE_DIRECTIVE "database" +#define CONFIG_DATABASE_ATTRIBUTE "nsslapd-database" +#define CONFIG_PLUGIN_DIRECTIVE "plugin" +#define CONFIG_PLUGIN_ATTRIBUTE "nsslapd-plugin" +#define CONFIG_SIZELIMIT_DIRECTIVE "sizelimit" +#define CONFIG_SIZELIMIT_ATTRIBUTE "nsslapd-sizelimit" +#define CONFIG_ORCAUTO_DIRECTIVE "orcauto" +#define CONFIG_ORCAUTO_ATTRIBUTE "nsslapd-orcauto" +#define CONFIG_TIMELIMIT_DIRECTIVE "timelimit" +#define CONFIG_TIMELIMIT_ATTRIBUTE "nsslapd-timelimit" +#define CONFIG_SUFFIX_DIRECTIVE "suffix" +#define CONFIG_SUFFIX_ATTRIBUTE "nsslapd-suffix" +#define CONFIG_READONLY_DIRECTIVE "readonly" +#define CONFIG_READONLY_ATTRIBUTE "nsslapd-readonly" +#define CONFIG_REFERRAL_DIRECTIVE "referral" +#define CONFIG_REFERRAL_ATTRIBUTE "nsslapd-referral" +#define CONFIG_OBJECTCLASS_DIRECTIVE "objectclass" +#define CONFIG_OBJECTCLASS_ATTRIBUTE "nsslapd-objectclass" +#define CONFIG_ATTRIBUTE_DIRECTIVE "attribute" +#define CONFIG_ATTRIBUTE_ATTRIBUTE "nsslapd-attribute" +#define CONFIG_SCHEMACHECK_DIRECTIVE "schemacheck" +#define CONFIG_SCHEMACHECK_ATTRIBUTE "nsslapd-schemacheck" +#define CONFIG_LOGLEVEL_DIRECTIVE "loglevel" +#define CONFIG_LOGLEVEL_ATTRIBUTE "nsslapd-errorlog-level" +#define CONFIG_ACCESSLOGLEVEL_DIRECTIVE "accessloglevel" +#define CONFIG_ACCESSLOGLEVEL_ATTRIBUTE "nsslapd-accesslog-level" +#define CONFIG_ACCESSLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "accesslog-maxNumOfLogsPerDir" +#define CONFIG_ACCESSLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-accesslog-maxlogsperdir" +#define CONFIG_ERRORLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "errorlog-maxNumOfLogsPerDir" +#define CONFIG_ERRORLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-errorlog-maxlogsperdir" +#define CONFIG_AUDITLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "auditlog-maxNumOfLogsPerDir" +#define CONFIG_AUDITLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-auditlog-maxlogsperdir" +#define CONFIG_ACCESSLOG_MAXLOGSIZE_DIRECTIVE "accesslog-maxlogsize" +#define CONFIG_ACCESSLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-accesslog-maxlogsize" +#define CONFIG_ERRORLOG_MAXLOGSIZE_DIRECTIVE "errorlog-maxlogsize" +#define CONFIG_ERRORLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-errorlog-maxlogsize" +#define CONFIG_AUDITLOG_MAXLOGSIZE_DIRECTIVE "auditlog-maxlogsize" +#define CONFIG_AUDITLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-auditlog-maxlogsize" +#define CONFIG_ACCESSLOG_LOGROTATIONTIME_DIRECTIVE "accesslog-logrotationtime" +#define CONFIG_ACCESSLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-accesslog-logrotationtime" +#define CONFIG_ERRORLOG_LOGROTATIONTIME_DIRECTIVE "errorlog-logrotationtime" +#define CONFIG_ERRORLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-errorlog-logrotationtime" +#define CONFIG_AUDITLOG_LOGROTATIONTIME_DIRECTIVE "auditlog-logrotationtime" +#define CONFIG_AUDITLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-auditlog-logrotationtime" +#define CONFIG_ACCESSLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "accesslog-logrotationtimeunit" +#define CONFIG_ACCESSLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-accesslog-logrotationtimeunit" +#define CONFIG_ERRORLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "errorlog-logrotationtimeunit" +#define CONFIG_ERRORLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-errorlog-logrotationtimeunit" +#define CONFIG_AUDITLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "auditlog-logrotationtimeunit" +#define CONFIG_AUDITLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-auditlog-logrotationtimeunit" +#define CONFIG_ACCESSLOG_MAXLOGDISKSPACE_DIRECTIVE "accesslog-maxlogdiskspace" +#define CONFIG_ACCESSLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-accesslog-logmaxdiskspace" +#define CONFIG_ERRORLOG_MAXLOGDISKSPACE_DIRECTIVE "errorlog-maxlogdiskspace" +#define CONFIG_ERRORLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-errorlog-logmaxdiskspace" +#define CONFIG_AUDITLOG_MAXLOGDISKSPACE_DIRECTIVE "auditlog-maxlogdiskspace" +#define CONFIG_AUDITLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-auditlog-logmaxdiskspace" +#define CONFIG_ACCESSLOG_MINFREEDISKSPACE_DIRECTIVE "accesslog-minfreediskspace" +#define CONFIG_ACCESSLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-accesslog-logminfreediskspace" +#define CONFIG_ERRORLOG_MINFREEDISKSPACE_DIRECTIVE "errorlog-minfreediskspace" +#define CONFIG_ERRORLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-errorlog-logminfreediskspace" +#define CONFIG_AUDITLOG_MINFREEDISKSPACE_DIRECTIVE "auditlog-minfreediskspace" +#define CONFIG_AUDITLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-auditlog-logminfreediskspace" +#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIME_DIRECTIVE "accesslog-logexpirationtime" +#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-accesslog-logexpirationtime" +#define CONFIG_ERRORLOG_LOGEXPIRATIONTIME_DIRECTIVE "errorlog-logexpirationtime" +#define CONFIG_ERRORLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-errorlog-logexpirationtime" +#define CONFIG_AUDITLOG_LOGEXPIRATIONTIME_DIRECTIVE "auditlog-logexpirationtime" +#define CONFIG_AUDITLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-auditlog-logexpirationtime" +#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "accesslog-logexpirationtimeunit" +#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-accesslog-logexpirationtimeunit" +#define CONFIG_ERRORLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "errorlog-logexpirationtimeunit" +#define CONFIG_ERRORLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-errorlog-logexpirationtimeunit" +#define CONFIG_AUDITLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "auditlog-logexpirationtimeunit" +#define CONFIG_AUDITLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-auditlog-logexpirationtimeunit" +#define CONFIG_ACCESSLOG_LOGGING_ENABLED_DIRECTIVE "accesslog-logging-enabled" +#define CONFIG_ACCESSLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-accesslog-logging-enabled" +#define CONFIG_ERRORLOG_LOGGING_ENABLED_DIRECTIVE "errorlog-logging-enabled" +#define CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-errorlog-logging-enabled" +#define CONFIG_AUDITLOG_LOGGING_ENABLED_DIRECTIVE "auditlog-logging-enabled" +#define CONFIG_AUDITLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-auditlog-logging-enabled" +#define CONFIG_ROOTDN_DIRECTIVE "rootdn" +#define CONFIG_ROOTDN_ATTRIBUTE "nsslapd-rootdn" +#define CONFIG_ROOTPW_DIRECTIVE "rootpw" +#define CONFIG_ROOTPW_ATTRIBUTE "nsslapd-rootpw" +#define CONFIG_ROOTPWSTORAGESCHEME_DIRECTIVE "rootpwstoragescheme" +#define CONFIG_ROOTPWSTORAGESCHEME_ATTRIBUTE "nsslapd-rootpwstoragescheme" +#define CONFIG_UPDATEDN_DIRECTIVE "updatedn" +#define CONFIG_UPDATEDN_ATTRIBUTE "nsslapd-updatedn" +#define CONFIG_UPDATEPW_DIRECTIVE "updatepw" +#define CONFIG_UPDATEPW_ATTRIBUTE "nsslapd-updatepw" +#define CONFIG_UPDATESSLCLIENT_DIRECTIVE "updateSSLclient" +#define CONFIG_UPDATESSLCLIENT_ATTRIBUTE "nsslapd-updateSSLclient" +#define CONFIG_AUDITFILE_DIRECTIVE "auditfile" +#define CONFIG_AUDITFILE_ATTRIBUTE "nsslapd-auditlog" +#define CONFIG_LASTMOD_DIRECTIVE "lastmod" +#define CONFIG_LASTMOD_ATTRIBUTE "nsslapd-lastmod" +#define CONFIG_INCLUDE_DIRECTIVE "include" +#define CONFIG_INCLUDE_ATTRIBUTE "nsslapd-include" +#define CONFIG_DYNAMICCONF_DIRECTIVE "dynamicconf" +#define CONFIG_DYNAMICCONF_ATTRIBUTE "nsslapd-dynamicconf" +#define CONFIG_USEROC_DIRECTIVE "useroc" +#define CONFIG_USEROC_ATTRIBUTE "nsslapd-useroc" +#define CONFIG_USERAT_DIRECTIVE "userat" +#define CONFIG_USERAT_ATTRIBUTE "nsslapd-userat" +#define CONFIG_SVRTAB_DIRECTIVE "svrtab" +#define CONFIG_SVRTAB_ATTRIBUTE "nsslapd-svrtab" +#ifndef _WIN32 +#define CONFIG_LOCALUSER_DIRECTIVE "localuser" +#define CONFIG_LOCALUSER_ATTRIBUTE "nsslapd-localuser" +#endif /* !_WIN32 */ +#define CONFIG_LOCALHOST_DIRECTIVE "localhost" +#define CONFIG_LOCALHOST_ATTRIBUTE "nsslapd-localhost" +#define CONFIG_PORT_DIRECTIVE "port" +#define CONFIG_PORT_ATTRIBUTE "nsslapd-port" +#define CONFIG_LISTENHOST_DIRECTIVE "listenhost" +#define CONFIG_LISTENHOST_ATTRIBUTE "nsslapd-listenhost" +#define CONFIG_SECURITY_DIRECTIVE "security" +#define CONFIG_SECURITY_ATTRIBUTE "nsslapd-security" +#define CONFIG_SSL3CIPHERS_DIRECTIVE "SSL3ciphers" +#define CONFIG_SSL3CIPHERS_ATTRIBUTE "nsslapd-SSL3ciphers" +#define CONFIG_ACCESSLOG_DIRECTIVE "accesslog" +#define CONFIG_ACCESSLOG_ATTRIBUTE "nsslapd-accesslog" +#define CONFIG_ERRORLOG_DIRECTIVE "errorlog" +#define CONFIG_ERRORLOG_ATTRIBUTE "nsslapd-errorlog" +#define CONFIG_INSTANCEDIR_DIRECTIVE "instancedir" +#define CONFIG_INSTANCEDIR_ATTRIBUTE "nsslapd-instancedir" +#define CONFIG_SECUREPORT_DIRECTIVE "secure-port" +#define CONFIG_SECUREPORT_ATTRIBUTE "nsslapd-securePort" +#define CONFIG_SECURELISTENHOST_DIRECTIVE "secure-listenhost" +#define CONFIG_SECURELISTENHOST_ATTRIBUTE "nsslapd-securelistenhost" +#define CONFIG_THREADNUMBER_DIRECTIVE "threadnumber" +#define CONFIG_THREADNUMBER_ATTRIBUTE "nsslapd-threadnumber" +#define CONFIG_MAXTHREADSPERCONN_DIRECTIVE "maxthreadsperconn" +#define CONFIG_MAXTHREADSPERCONN_ATTRIBUTE "nsslapd-maxthreadsperconn" +#if !defined(_WIN32) && !defined(AIX) +#define CONFIG_MAXDESCRIPTORS_DIRECTIVE "maxdescriptors" +#define CONFIG_MAXDESCRIPTORS_ATTRIBUTE "nsslapd-maxdescriptors" +#endif /* !_WIN32 && ! AIX */ +#define CONFIG_RESERVEDESCRIPTORS_DIRECTIVE "reservedescriptors" +#define CONFIG_RESERVEDESCRIPTORS_ATTRIBUTE "nsslapd-reservedescriptors" +#define CONFIG_IDLETIMEOUT_DIRECTIVE "idletimeout" +#define CONFIG_IDLETIMEOUT_ATTRIBUTE "nsslapd-idletimeout" +#define CONFIG_IOBLOCKTIMEOUT_DIRECTIVE "ioblocktimeout" +#define CONFIG_IOBLOCKTIMEOUT_ATTRIBUTE "nsslapd-ioblocktimeout" +#define CONFIG_NTSYNCH_DIRECTIVE "ntsynch" +#define CONFIG_NTSYNCH_ATTRIBUTE "nsslapd-NTSynch" +#define CONFIG_NTSYNCHUSESSL_DIRECTIVE "ntsynchusessl" +#define CONFIG_NTSYNCHUSESSL_ATTRIBUTE "nsslapd-NTSynch-SSL" +#define CONFIG_NTSYNCHPORT_DIRECTIVE "ntsynch-port" +#define CONFIG_NTSYNCHPORT_ATTRIBUTE "nsslapd-NTSynch-port" +#define CONFIG_ACCESSCONTROL_DIRECTIVE "accesscontrol" +#define CONFIG_ACCESSCONTROL_ATTRIBUTE "nsslapd-accesscontrol" +#define CONFIG_GROUPEVALNESTLEVEL_DIRECTIVE "groupevalnestlevel" +#define CONFIG_GROUPEVALNESTLEVEL_ATTRIBUTE "nsslapd-groupevalnestlevel" +#define CONFIG_NAGLE_DIRECTIVE "nagle" +#define CONFIG_NAGLE_ATTRIBUTE "nsslapd-nagle" +#define CONFIG_PW_CHANGE_DIRECTIVE "pw_change" +#define CONFIG_PW_CHANGE_ATTRIBUTE "passwordChange" +#define CONFIG_PW_MUSTCHANGE_DIRECTIVE "pw_must_change" +#define CONFIG_PW_MUSTCHANGE_ATTRIBUTE "passwordMustChange" +#define CONFIG_PW_SYNTAX_DIRECTIVE "pw_syntax" +#define CONFIG_PW_SYNTAX_ATTRIBUTE "passwordCheckSyntax" +#define CONFIG_PW_MINLENGTH_DIRECTIVE "pw_minlength" +#define CONFIG_PW_MINLENGTH_ATTRIBUTE "passwordMinLength" +#define CONFIG_PW_EXP_DIRECTIVE "pw_exp" +#define CONFIG_PW_EXP_ATTRIBUTE "passwordExp" +#define CONFIG_PW_MAXAGE_DIRECTIVE "pw_maxage" +#define CONFIG_PW_MAXAGE_ATTRIBUTE "passwordMaxAge" +#define CONFIG_PW_MINAGE_DIRECTIVE "pw_minage" +#define CONFIG_PW_MINAGE_ATTRIBUTE "passwordMinAge" +#define CONFIG_PW_WARNING_DIRECTIVE "pw_warning" +#define CONFIG_PW_WARNING_ATTRIBUTE "passwordWarning" +#define CONFIG_PW_HISTORY_DIRECTIVE "pw_history" +#define CONFIG_PW_HISTORY_ATTRIBUTE "passwordHistory" +#define CONFIG_PW_INHISTORY_DIRECTIVE "pw_inhistory" +#define CONFIG_PW_INHISTORY_ATTRIBUTE "passwordInHistory" +#define CONFIG_PW_LOCKOUT_DIRECTIVE "pw_lockout" +#define CONFIG_PW_LOCKOUT_ATTRIBUTE "passwordLockout" +#define CONFIG_PW_STORAGESCHEME_DIRECTIVE "pw_storagescheme" +#define CONFIG_PW_STORAGESCHEME_ATTRIBUTE "passwordStorageScheme" +#define CONFIG_PW_MAXFAILURE_DIRECTIVE "pw_maxfailure" +#define CONFIG_PW_MAXFAILURE_ATTRIBUTE "passwordMaxFailure" +#define CONFIG_PW_UNLOCK_DIRECTIVE "pw_unlock" +#define CONFIG_PW_UNLOCK_ATTRIBUTE "passwordUnlock" +#define CONFIG_PW_LOCKDURATION_DIRECTIVE "pw_lockduration" +#define CONFIG_PW_LOCKDURATION_ATTRIBUTE "passwordLockoutDuration" +#define CONFIG_PW_RESETFAILURECOUNT_DIRECTIVE "pw_resetfailurecount" +#define CONFIG_PW_RESETFAILURECOUNT_ATTRIBUTE "passwordResetFailureCount" +#define CONFIG_ACCESSLOG_BUFFERING_DIRECTIVE "logbuffering" +#define CONFIG_ACCESSLOG_BUFFERING_ATTRIBUTE "nsslapd-accesslog-logbuffering" +#define CONFIG_CHANGELOG_DIR_DIRECTIVE "changelogdir" +#define CONFIG_CHANGELOG_DIR_ATTRIBUTE "nsslapd-changelogdir" +#define CONFIG_CHANGELOG_SUFFIX_DIRECTIVE "changelogsuffix" +#define CONFIG_CHANGELOG_SUFFIX_ATTRIBUTE "nsslapd-changelogsuffix" +#define CONFIG_CHANGELOG_MAXENTRIES_DIRECTIVE "changelogmaxextries" +#define CONFIG_CHANGELOG_MAXENTRIES_ATTRIBUTE "nsslapd-changelogmaxentries" +#define CONFIG_CHANGELOG_MAXAGE_DIRECTIVE "changelogmaxage" +#define CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE "nsslapd-changelogmaxage" +#define CONFIG_RETURN_EXACT_CASE_DIRECTIVE "return_exact_case" +#define CONFIG_RESULT_TWEAK_DIRECTIVE "result_tweak" +#define CONFIG_REFERRAL_MODE_DIRECTIVE "referralmode" +#define CONFIG_ATTRIBUTE_NAME_EXCEPTION_DIRECTIVE "attribute_name_exceptions" +#define CONFIG_MAXBERSIZE_DIRECTIVE "maxbersize" +#define CONFIG_VERSIONSTRING_DIRECTIVE "versionstring" +#define CONFIG_ENQUOTE_SUP_OC_DIRECTIVE "enquote_sup_oc" +#define CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE "nsslapd-enquote_sup_oc" +#define CONFIG_BASEDN_DIRECTIVE "certmap-basedn" +#define CONFIG_BASEDN_ATTRIBUTE "nsslapd-certmap-basedn" + +%HashParametersName = (); + +# The following hash displays only general server parameters to migrate under cn=config +%GeneralSrvParamToMigrate = ( + 'accesscontrol' => 'nsslapd-accesscontrol', + 'errorlog-logging-enabled' => 'nsslapd-errorlog-logging-enabled', + 'accesslog-logging-enabled' => 'nsslapd-accesslog-logging-enabled', + 'auditlog-logging-enabled' => 'nsslapd-auditlog-logging-enabled', + 'logbuffering' => 'nsslapd-accesslog-logbuffering', + 'accesslog-logexpirationtime' => 'nsslapd-accesslog-logexpirationtime', + 'accesslog-logexpirationtimeunit' => 'nsslapd-accesslog-logexpirationtimeunit', + 'accesslog-maxlogdiskspace' => 'nsslapd-accesslog-logmaxdiskspace', + 'accesslog-minfreediskspace' => 'nsslapd-accesslog-logminfreediskspace', + 'accesslog-logrotationtime' => 'nsslapd-accesslog-logrotationtime', + 'accesslog-logrotationtimeunit' => 'nsslapd-accesslog-logrotationtimeunit', + 'accesslog-maxlogsize' => 'nsslapd-accesslog-maxlogsize', + 'accesslog-maxnumoflogsperdir' => 'nsslapd-accesslog-maxLogsPerDir', + 'auditlog-logexpirationtime' => 'nsslapd-auditlog-logexpirationtime', + 'auditlog-logexpirationtimeunit' => 'nsslapd-auditlog-logexpirationtimeunit', + 'auditlog-maxlogdiskspace' => 'nsslapd-auditlog-logmaxdiskspace', + 'auditlog-minfreediskspace' => 'nsslapd-auditlog-logminfreediskspace', + 'auditlog-logrotationtime' => 'nsslapd-auditlog-logrotationtime', + 'auditlog-logrotationtimeunit' => 'nsslapd-auditlog-logrotationtimeunit', + 'auditlog-maxlogsize' => 'nsslapd-auditlog-maxlogsize', + 'auditlog-maxnumoflogsperdir' => 'nsslapd-auditlog-maxLogsPerDir', + 'certmap-basedn' => 'nsslapd-certmap-basedn', + 'enquote_sup_oc' => 'nsslapd-enquote-sup-oc', + 'loglevel' => 'nsslapd-errorlog-level', + 'errorlog-logexpirationtime' => 'nsslapd-errorlog-logexpirationtime', + 'errorlog-logexpirationtimeunit' => 'nsslapd-errorlog-logexpirationtimeunit', + 'errorlog-maxlogdiskspace' => 'nsslapd-errorlog-logmaxdiskspace', + 'errorlog-minfreediskspace' => 'nsslapd-errorlog-logminfreediskspace', + 'errorlog-logrotationtime' => 'nsslapd-errorlog-logrotationtime', + 'errorlog-logrotationtimeunit' => 'nsslapd-errorlog-logrotationtimeunit', + 'errorlog-maxlogsize' => 'nsslapd-errorlog-maxlogsize', + 'errorlog-maxnumoflogsperdir' => 'nsslapd-errorlog-maxlogsperdir', + 'idletimeout' => 'nsslapd-idletimeout', + 'ioblocktimeout' => 'nsslapd-ioblocktimeout', + 'lastmod' => 'nsslapd-lastmod', + 'listenhost' => 'nsslapd-listenhost', + 'maxdescriptors' => 'nsslapd-maxdescriptors', + 'referral' => 'nsslapd-referral', + 'reservedescriptors' => 'nsslapd-reservedescriptors', + 'rootpwstoragescheme' => 'nsslapd-rootpwstoragescheme', + 'schemacheck' => 'nsslapd-schemacheck', + 'secure-port' => 'nsslapd-securePort', + 'security' => 'nsslapd-security', + 'sizelimit' => 'nsslapd-sizelimit', + 'SSL3ciphers' => 'nsslapd-SSL3ciphers', + 'timelimit' => 'nsslapd-timelimit', + 'pw_change' => 'passwordChange', + 'pw_syntax' => 'passwordCheckSyntax', + 'pw_exp' => 'passwordExp', + 'pw_history' => 'passwordHistory', + 'pw_inhistory' => 'passwordInHistory', + 'pw_lockout' => 'passwordLockout', + 'pw_lockduration' => 'passwordLockoutDuration', + 'pw_maxage' => 'passwordMaxAge', + 'pw_maxfailure' => 'passwordMaxFailure', + 'pw_minage' => 'passwordMinAge', + 'pw_minlength' => 'passwordMinLength', + 'pw_must_change' => 'passwordMustChange', + 'pw_resetfailurecount' => 'passwordResetFailureCount', + 'pw_storagescheme' => 'passwordStorageScheme', + 'pw_unlock' => 'passwordUnlock', + 'pw_warning' => 'passwordWarning' +); + +# the following hash displays global parameters related to database stored under cn=config,cn=ldbm database,cn=plugins,cn=config +%GlobalConfigLDBMparamToMigrate = ( + 'allidsthreshold' => 'nsslapd-allidsthreshold', + 'lookthroughlimit' => 'nsslapd-lookthroughlimit', + 'mode' => 'nsslapd-mode', + 'dbcachesize' => 'nsslapd-dbcachesize' +); + +# the following hash displays specific parameters to each backends and stored under cn=DBname,cn=ldbm database,cn=plugins,cn=config +%LDBMparamToMigrate = ( + 'cachesize' => 'nsslapd-cachesize', + 'readonly' => 'nsslapd-readonly' +); + +%stdIncludes = ( + "${oldConfDir}slapd.at.conf", "\n", + "${oldConfDir}slapd.oc.conf", "\n", + "${oldConfDir}java-object-schema.conf", "\n", + "${oldConfDir}ns-admin-schema.conf", "\n", + "${oldConfDir}ns-calendar-schema.conf", "\n", + "${oldConfDir}ns-certificate-schema.conf", "\n", + "${oldConfDir}ns-common-schema.conf", "\n", + "${oldConfDir}ns-compass-schema.conf", "\n", + "${oldConfDir}ns-delegated-admin-schema.conf", "\n", + "${oldConfDir}ns-directory-schema.conf", "\n", + "${oldConfDir}ns-legacy-schema.conf", "\n", + "${oldConfDir}ns-mail-schema.conf", "\n", + "${oldConfDir}ns-mcd-browser-schema.conf", "\n", + "${oldConfDir}ns-mcd-config-schema.conf", "\n", + "${oldConfDir}ns-mcd-li-schema.conf", "\n", + "${oldConfDir}ns-mcd-mail-schema.conf", "\n", + "${oldConfDir}ns-media-schema.conf", "\n", + "${oldConfDir}ns-mlm-schema.conf", "\n", + "${oldConfDir}ns-msg-schema.conf", "\n", + "${oldConfDir}ns-netshare-schema.conf", "\n", + "${oldConfDir}ns-news-schema.conf", "\n", + "${oldConfDir}ns-proxy-schema.conf", "\n", + "${oldConfDir}ns-value-schema.conf", "\n", + "${oldConfDir}ns-wcal-schema.conf", "\n", + "${oldConfDir}ns-cos-schema.conf", "\n", + "${oldConfDir}ns-web-schema.conf", "\n" +); + +%userDefinedConfigFiles = ( + "slapd.conf", "\n", + "slapd.ldbm.conf", "\n", + "slapd.user_at.conf", "\n", + "slapd.user_oc.conf", "\n", + "ns-schema.conf", "\n" + ); + +$CIS_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.15" ; +$TELEPHONE_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.50" ; +$DN_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.12" ; +$CES_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.26" ; +$INT_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.27" ; +$BIN_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.5" ; + +%allowedPlugins = ( + "cis", $CIS_SYNTAX_OID, + "tel", $TELEPHONE_SYNTAX_OID, + "dn", $DN_SYNTAX_OID, + "ces", $CES_SYNTAX_OID, + "int", $INT_SYNTAX_OID, + "bin", $BIN_SYNTAX_OID + ); + +%allowedModifiers = ( + "single", "SINGLE-VALUE" + ); +# "override" is not supported anymore and "operational" cannot be used in user defined attribute. + +@oldSuffixes = () ; # array of old suffixes (with "o=netscaperoot" if presents) + +# link beetwen the name of the suffix and its associated DBname +%DBNAMES = () ; +%DBDirectory = () ; + +%oldhash = () ; + +# list of standard plugin's in version 4 +%stdPlugins = ( + "7-bit check" => "\n", + "binary syntax" => "\n", + "case exact string syntax" => "\n", + "case ignore string syntax" => "\n", + "distinguished name syntax" => "\n", + "integer syntax" => "\n", + "internationalization plugin" => "\n", + "referential integrity postoperation" => "\n", + "telephone syntax" => "\n", + "uid uniqueness" => "\n" + + ); + +# list of standard indexes configured out of the box in version 4 +%stdIndex = ( + 'aci', "\n", + 'changenumber', "\n", + 'copiedfrom', "\n", + 'dncomp', "\n", + 'entrydn', "\n", + 'numsubordinates', "\n", + 'objectclass', "\n", + 'parentid', "\n" +); + +# list of user added Plugin's. In the new version, they 'll need to be recompiled +@badPlugins = () ; + +%newIndex = () ; + +%User_oc = () ; +# push objectnames as they are encountered in config files. +@User_oc_names = () ; + +%User_at = () ; + + + +#Usage parameters +$USER_OC_FILE_MODIFIED = 0 ; # 0 if user don't want to modify LDIF objectclasses before processing, 1 else +$USER_AT_FILE_MODIFIED = 0 ; +$INDEX_FILE_MODIFIED = 0 ; + +# get the version of the DS to migrate +($oldVersion, $oldMinor) = &getVersion($oldDir, $oldversionstr); +# get the version of the new DS +($Version, $Minor) = &getVersion($root); + +# get old LIB_PATH +$old_libpath = &getLibPath($oldDir, $oldVersion, $oldMinor); +# get new LIB_PATH +$new_libpath = &getLibPath($root, $Version, $Minor); + +# Shutdown the legacy Directory instance +printTrace("\nShutdown the legacy Directory Server instance: ${oldHome}",0); +&stopServer($oldDir, 'slapd-'.$oldname); + +# compare configuration files with the standard ones +CompareStdConfigFiles() ; +die "\n\n The version of the product you want to migrate is not a 4.x Netscape Directory Server\n" unless ($oldVersion == 4) ; + +FillHashParametersName() ; + +############### Connect to the New LDAP Directory Server ###################### +$ENV{"$LIB_PATH"} = $new_libpath; +my $LDAPservername = &getLDAPservername(); +die "\n Migration aborted. Make sure your Old and New Directory Servers are installed on the same machine \n" if ( $LDAPservername == -1 ); +$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n"; + +# continue if the connection to new LDAP server is successful ! +printTrace("\nConnected to $Version.$Minor LDAP server\n",0) ; + +# get the uid and gid of the new slapd user +($localuser, $newuid, $newgid) = getuid_gid(); +# get the uid and gid of the old slapd user +($oldlocaluser, $olduid, $oldgid) = getolduid_gid(); + +# backup new configuration files in <new_root_server>/slapd-instancename/config +printTrace("\nBackup $serverHome${PATHSEP}config on $serverHome${PATHSEP}config_backup ...",0); +&backupConfigFiles(); + +# Parse the main configuration file: slapd.conf +printTrace("\nParse the configuration file: $oldSlapdConf...",0); +ParseSlapdConf("< ${oldSlapdConf}"); + +#migrate key/cert databases +printTrace("\nMigrate key/cert databases...",0); +&MigrateSSL(); + +# Update parameters : general server parameters, global LDBM parameter, specific backend parameters +printTrace("\nUpdate general server parameters...",0); +$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n"; +AddGeneralParameters(); +printTrace("\nUpdate global LDBM parameters...",0); +AddGeneralLDBMParameters(); +printTrace("\nUpdate specific backend parameters...",0); +AddSpecificLDBMParameters(); + +##### FOR TESTING PURPOSE ONLY ######## +# +#testIndexUpdating(); +# +####################################### + +# Migrate some entries contained in the old dse.ldif, and migrate certmap.conf +&MigrateDSE() ; +&MigrateCertmap() ; + +# update new attribute definitions +LDAPmodify_User_at(); + +# update new object classes definitions +LDAPmodify_User_oc(); + +# add new indexes to each backends +LDAPmodify_Indexes(); + +# migrate Plug'ins parameters (enable attribute, and arguments) +LDAPmodify_stdPlugin(); + +################## Close the connection to new LDAP Server ##################### +$conn->close; + + +################## stop the new instance and Export/Import the data, restart the server ################## +if (%DBNAMES) { + &stopServer($root,'slapd-'.$newname); + if ($olddatadir) { + printTrace("\nold data directory $olddatadir...",0) ; + $ldif_rep = "$olddatadir${PATHSEP}"; + } else { + printTrace("\ndata processing...",0) ; + # migrate data for each suffix: old -> LDIF files + &db2ldif($oldSlapdConf); + } + + # migrate LDIF data to the new database: LDIF -> new + &manyLdif2db(); + &startServer(); +} +else { + printTrace("\nThere no old non-standard suffixes to migrate",0); +} + +printMsg("\n\n ****** End of migration ******\n\n"); + +close(LOGFILE); + + +########################################################################################### +# get input users +sub getParameters { + my $exit = 0 ; + my $i = 0; + my $pwdfile= ""; + while ($i <= $#ARGV) { + if ( "$ARGV[$i]" eq "-D" ) { # directory manager + if (! $rootDN) { + $rootDN = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-w") { # password + if (! $rootpwd) { + $rootpwd = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-j") { # password file + if (! $pwdfile) { + $pwdfile = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-o") { # old instance path + if (! $oldHome ) { + $oldHome = $ARGV[++$i] ; + grep { s@\\@/@g } $oldHome if $isNT ; + if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; } + if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) { + $oldDir = $1 ; + $type = $2 ; + $oldname = $3 ; + if ($isNT) { + $oldDir = lc($oldDir) ; + $type = lc($type) ; + $oldname = lc($oldname) ; + $oldHome = lc($oldHome) ; + grep { s@/@\\@g } $oldDir ; + grep { s@/@\\@g } $oldHome ; + } + } + else { + print("\nThe old instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-n") { # new instance path + if (! $serverHome ) { + $serverHome = $ARGV[++$i] ; + grep { s@\\@/@g } $root if $isNT ; + grep { s@\\@/@g } $serverHome if $isNT ; + if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; } + if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) { + $root = $1 if ($1); + $type = $2 ; + $newname = $3 ; + if ($isNT) { + $root = lc($root) ; + $type = lc($type) ; + $newname = lc($newname) ; + $serverHome = lc($serverHome) ; + grep { s@/@\\@g } $root ; + grep { s@/@\\@g } $serverHome ; + } + } + else { + print("\nThe new instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-p") { # new DS port + if (! $newport ) { + $newport = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-d") { # old instance LDIF data dir + if (! $olddatadir ) { + $olddatadir = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-v") { # old version + if (! $oldversionstr ) { + $oldversionstr = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL + my $value = $ARGV[++$i] ; + if ($value =~ /[0-3]/) { + $TRACELEVEL = $value ; + } + else { + print("\nThe tracelevel must belong to 0..3 interval"); + &usage(); + exit(); + } + } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing + $NO_INPUT_USER = 1 ; + } elsif ("$ARGV[$i]" eq "-L") { # migration logfile + $LogFileReport = $ARGV[++$i] ; + } + else { + print("\nThe option $ARGV[$i] is not recognized"); + &usage() ; + exit(1); + } + $i++; + } + if (! $rootDN) { + print("\nThe rootDN is missing"); + $exit = 1; + } + if ($pwdfile ne "") { + # Open file and get the password + unless (open (RPASS, $pwfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $rootpwd = <RPASS>; + chomp($rootpwd); + close(RPASS); + } elsif ($rootpwd eq "-"){ + # Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; + # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $rootpwd = ReadLine(0); +# chomp($rootpwd); +# ReadMode('normal'); + } + if (! $rootpwd) { + print("\nThe rootpwd is missing"); + $exit = 1 ; + } + if (! $newport) { + print("\nThe port is missing"); + $exit = 1; + } + if (! $serverHome) { + print("\nThe new instance path is missing"); + $exit = 1; + } + if (! $oldHome) { + print("\nThe old instance path is missing"); + $exit = 1; + } + if ((! $LogFileReport) && $serverHome) { + ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime(); + $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log"; + } + + if ($exit) { + &usage() ; + exit(1); + } + +} + + +############################################################################### +# This subroutine is used to parse the slapd.conf configuration file and migrate specific parameters contained in it + + +sub ParseSlapdConf { + my $oldsrc = shift; + my $NumLine = 0 ; + # read the old conf file into a hash table + open( OLDSRC, $oldsrc ) || die "Can't open $oldsrc: $!: "; + LINE: while ( <OLDSRC> ) { + $NumLine++ ; + printTrace("\nLine: $_",4) ; + if (/^\s*\#/) { # skip comments + printTrace("\n# ",4) ; + next LINE; + } + if (/^\s*$/) { # skip blank lines + printTrace("\nBLANK LINE",4); + next LINE; + } elsif (/^suffix\s+/i) { + chomp($_) ; + CheckSuffix($_); + } elsif (/^plugin/i) { + printTrace("\nPLUGIN",4); + chomp($_); + if (! &isAStandardPlugin($_)) { + push @badPlugins, $_; + } + else { + my $Plugin = $_ ; + if (! &ParsePlugin($_,$NumLine)) { + printMsg("\nLine $NumLine, syntax error of the plugin:\n$Plugin"); + } + } + } elsif (/^include\s+[\"]?(.*?)[\"]?\s*$/i) { + # strip leading and trailing " + my $include_file = $1 ; + grep { s@/@\\@g } $include_file if $isNT; + if (! &isAStandardInclude($include_file)) { + printTrace("\nFILE: $1 NOT STANDARD",4) ; + &ParseConfigurationFile($include_file); + printTrace("\nEXIT ParseConfigurationFile: $include_file",4) ; + } + } elsif (/^userat\s+[\"]?(.*?)[\"]?\s*$/i) { + printTrace("\nuserat: $1",4); + my $at_file = $1 ; + grep { s@/@\\@g } $at_file if $isNT; + # Parse user defined attributes + &ParseAttributesFile($at_file); + } elsif (/^useroc\s+[\"]?(.*?)[\"]?\s*$/i) { + printTrace("\nuseroc: $1",4); + my $oc_file = $1 ; + grep { s@/@\\@g } $oc_file if $isNT; + # Parse user defined object classes + &ParseObjectClassesFile($oc_file); + } elsif (/^dynamicconf\s+[\"]?(.*?)[\"]?\s*$/i){ + printTrace("\ndynamicconf: $1",4); + my $dynamiconf_file = $1 ; + grep { s@/@\\@g } $dynamiconf_file if $isNT; + # Parse dynamic configuration file (e-g slapd.ldbm.conf) + &ParseConfigurationFile($dynamiconf_file); + } elsif (/^\s*(\S+)\s+[\"]?(.*?)[\"]?\s*$/) { + printTrace("\nParseParameters: $1",4); + # Parse parameters and record the associated value in %oldhash + &ParseParameters($1,$2,$NumLine); + } else { + printTrace("\nUnknown format of configuration data: $_",0); } + } + close(OLDSRC); + + } + + + +############################################################################# +# return 1 if the suffix already exists, 0 else +sub existSuffix { + my $suffixname = shift ; + my $nsuffix = normalizeDN($suffixname); + my $entry = $conn->search("cn=mapping tree,cn=config", "one", "(|(cn=\"$suffixname\")(cn=\"$nsuffix\"))"); + return 1 if ($entry) ; + my $cpt = 5; + my $errorCode = $conn->getErrorCode(); + while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && $cpt && (! $entry)) { + printTrace("\ntry to reconnect to search cn=\"$suffixname\",cn=mapping tree,cn=config", 1); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + $entry = $conn->search("cn=mapping tree,cn=config", "one", "(|(cn=\"$suffixname\")(cn=\"$nsuffix\"))"); + $errorCode = $conn->getErrorCode(); + $cpt--; + } + return 1 if ($entry) ; + return 0 ; +} + +# return the name of the backend if it has been successfully created, 0 else +sub createBackend { + my $suffixname = shift ; + my $backend = "MigratedDB_0" ; + my $NbRetry = 1 ; + my $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ; + while ($entry) { + # try to find another name for the backend + $backend = "MigratedDB_$NbRetry" ; + $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ; + $NbRetry++; + } + # normally I should have a unique name for the backend + my $suffixarg = "nsslapd-suffix" ; + $entry = $conn->newEntry() ; + $entry->setDN("cn=$backend,cn=ldbm database,cn=plugins,cn=config"); + $entry->setValues("objectclass", "top", "extensibleObject", "nsBackendInstance" ); + $entry->setValues("cn", $backend ); + $entry->setValues($suffixarg, $suffixname ); + my $res = $conn->add($entry) ; + if ($res) { + return $backend ; + } + else { + return 0 ; + } +} + +# return 1, if add the new entry in the mapping tree, else 0 +sub AddEntryInMappingTree { + my $backend = shift ; + my $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ; + if ($entry) { + printTrace("\nAddEntry in progress ...",4) ; + my $suffixarg = "nsslapd-suffix" ; + my $statearg = "nsslapd-state" ; + my $backendarg= "nsslapd-backend"; + my $suffixname = $entry->{$suffixarg}[0]; + $entry = $conn->newEntry() ; + $entry->setDN("cn=\"$suffixname\",cn=mapping tree,cn=config") ; + $entry->setValues("objectclass", "top", "extensibleObject", "nsMappingTree" ); + $entry->setValues("cn", "\"$suffixname\""); + $entry->setValues($statearg, "backend"); + $entry->setValues($backendarg, $backend); + return $conn->add($entry); + } + else { + printTrace("\nNo AddEntry processed for $backend",4); + return 0 ; + } +} + + +# Treat the case where the suffix is "o=NetscapeRoot" +sub CheckSuffix { + my $suffix = shift ; + my $suffixname ; + my $expLdif; + my $confirm = "No"; + my $dest = "$serverHome${PATHSEP}db_backup" ; + my $newSlapdExecDir = "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server"; + + if (!(/^suffix\s+\"?(.*?)\"?\s*$/i)) { + printMsg("Syntax error of the suffix: $suffix"); + return 0 ; + } + else { + $suffixname = $1 ; + } + if (/^suffix\s+\"?\s*o=netscaperoot\s*\"?\s*$/i) { + printTrace("\nFor the suffix o=NetscapeRoot, we do nothing",1); + # treat the case where the suffix is "o=NetscapeRoot" + } + else { + push @oldSuffixes, $_; + # check if the suffix already exists in the new DS target + if (! existSuffix($suffixname)) { + printTrace("\n\nSuffix $suffixname doesn't exist",1) ; + # create a new backend with the name of the suffix preceded by MigratedDB_ + my $backend = createBackend($suffixname) ; + if ($backend) { + printTrace("\nBackend: $backend has been created !!!",1); + # if the creation of the backend is ok, we add a new entry in the mapping tree + if (AddEntryInMappingTree($backend)) { + # We add the association dbname->suffix in the hash %DBNAMES + $DBNAMES{$suffixname} = $backend ; + # get the db filename + $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ; + my $dirarg = "nsslapd-directory"; + $DBDirectory{$backend} = $entry->{$dirarg}[0]; + printTrace("\nThe relation $backend->$suffixname has been added to the mapping tree",2); + } + else { + printMsg("\nCOULD NOT ADD ENTRY: $backend->$suffixname IN MAPPINGTREE"); + } + } + else { + printMsg("\nCOULD NOT CREATE BACKEND: $backend"); + } + } + else { + printMsg("\n\nSuffix: $suffixname already exists"); + # the suffix already exists in the new DS + printMsg("\nMigration will overwrite existing database"); + printMsg("\nDo you want to continue Yes/No [No] ?") ; + my $answer = <STDIN> ; + if ($answer =~ /y|yes/i) { + my $nsuffix = normalizeDN($suffixname); + my $my_entry = $conn->search("cn=mapping tree,cn=config", "one", "(|(cn=\"$suffixname\")(cn=\"$nsuffix\"))"); + my $backend = $my_entry->{"nsslapd-backend"}[0]; + my $backend_entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ; + printMsg("Do you want to export the existing data Yes/No [Yes] ?"); + my $answer = <STDIN> ; + if (!($answer =~ /n|no/i)) { + mkdir $dest, 0700 unless (-d $dest); + $expLdif = "$dest${PATHSEP}$backend.ldif"; + while (!($confirm =~ /y|yes/i)) { + printMsg("\nEnter the full pathname of the file [$expLdif]:") ; + $answer = <STDIN> ; + chomp($expLdif = $answer) unless ($answer eq "\n"); + printMsg("\nExisting data will be exported under $expLdif"); + printMsg("\nContinue Yes/No [No] ?"); + $confirm = <STDIN>; + } + $ENV{"$LIB_PATH"}=$new_libpath; + chdir($newSlapdExecDir) or die "\nCould not change directory to $newSlapdExecDir: $!\n"; + printTrace("\nNow backing up database $CN in $expLdif\n",0); + &stopServer($root,'slapd-'.$newname); + &newinst_db2ldif($expLdif, $suffixname, $serverHome); + &startServer(); + } + # We add the association dbname->suffix in the hash %DBNAMES + $DBNAMES{$suffixname} = $backend ; + my $dirarg = "nsslapd-directory"; + $DBDirectory{$backend} = $backend_entry->{$dirarg}[0]; + printTrace("\nThe relation $backend->$suffixname has been added to the mapping tree",2); + } + } + return 1 ; +} +} + +############################################################################# +# Usefull to know the standard configuration +sub isAStandardPlugin { + my $line = shift; + chomp($line); + printTrace("\nStdPlugin?: $line",4); + if ($line =~ /^plugin\s+(database|extendop|preoperation|postoperation|matchingrule|syntax)\s+(on|off)\s+\"(.*?)\"\s+\"(.*?)\"\s+(\S+)(.*)$/i) { + # $1 = <type>, $2 = <on|off>, $3 = <name>, $4 = <pathname>, $5 = <init_function>, $6 = [<arg>]* + printTrace("\nName: $3, pathname: $4, init_function: $5",4); + + my $LC_line = lc($3); + my $Value = $stdPlugins{$LC_line} ; + if ($Value) { + printTrace("\nIS A STANDARD PLUGIN",4); + } + else { + printTrace("\nNOT A STANDARD PLUGIN",4); + } + return $stdPlugins{$LC_line} ; + } + else { + printTrace("\nSYNTAX ERROR PLUGIN",4); + return 0 ; + } +} + +sub isAStandardIndex { + my $line = shift ; + chomp($line); + if ($line =~ /^index\s+(\S+).*/i) { + my $LC_line = lc($1); + my $Value = $stdIndex{$LC_line} ; + printTrace("\nInclude: $LC_line \nValue: $Value", 4); + return $stdIndex{$LC_line}; + } + else { + return 0 ; + } +} + + +sub isAStandardInclude { + my $line = shift; + + chomp($line); + if ($isNT){ + return $stdIncludes{lc($line)}; + } + else { + return $stdIncludes{$line} ; + } +} + +############################################################################# +# +# Execute a Perldap command to update plugins definition in the new schema + +sub LDAPmodify_stdPlugin { + my $Filename = shift ; + my @pluginames = keys(%stdPlugins); + if (! $STDPLUGINS_FILE_MODIFIED) { + printTrace("\nLDAPmodify_plugin",4); + printTrace("\nMigrate plugin's...",1); + foreach $pluginame ( @pluginames ) { + my $update_plugin = 0 ; + my $ref_plugin = $stdPlugins{$pluginame}; + if ($ref_plugin ne "\n") { + my $name = $ref_plugin->name ; + # We have a name change of "uid uniqueness plugin" in DS6.x + # to "attribute uniqueness" + $name = "attribute uniqueness" if ($name eq "uid uniqueness"); + my $entry = $conn->search("cn=$name,cn=plugins,cn=config", "base","objectclass=nsSlapdPlugin") ; + if ($entry) { + my $pluginenabled="nsslapd-pluginenabled" ; + if (($entry->{$pluginenabled}[0]) ne $ref_plugin->enable) { + $update_plugin = 1 ; + my $enable = $ref_plugin->enable ; + printTrace("\n$pluginame, plugin-enable: $enable",3) ; + $entry->setValues($pluginenabled, $enable ); + } + my $ArgNum = 0 ; + foreach $ArgValue (@{$ref_plugin->args}) { + my $Arg="nsslapd-pluginarg$ArgNum"; + printTrace("\n$Arg: $ArgValue",3) ; + if ($entry->{$Arg}[0] ne $ArgValue) { + printTrace("\n$pluginame, $Arg: $ArgValue",3) ; + $update_plugin = 1 ; + $entry->setValues($Arg, $ArgValue) ; + } + $ArgNum++ ; + } + if ($update_plugin) { + printTrace("\n$pluginame is being updated...",2); + my $res = $conn->update($entry) ; + if ($res) { + printTrace("\nupdated !",2); + } + else { + printMsg("\nError during update of plugin: $pluginame") ; + $MigrationErrors .= "\nError during update of plugin: $pluginame"; + } + } + else { + printTrace("\n$pluginame has not changed",4); + } + } + else { + printMsg("\ncan't access the plugin: cn=$name,cn=plugins,cn=config"); + } + } + else { + printTrace("\nPLUGIN NOT RECORDED: $pluginame",4) ; + } + } + } + else { + # treat the case where the user wants to look at these plugins before processing + } +} + +############################################################################# +# Execute Perldap command to add new indexes to the migrated instances + +sub LDAPmodify_Indexes { + my $Filename = shift ; + my @indexnames = keys(%newIndex); + my @suffixnames = keys(%DBNAMES); + if ((! $INDEX_FILE_MODIFIED) && (%DBNAMES)) { + # we update indexes only if there is at least one backend to migrate + printTrace("\nLDAPmodify_indexes",4); + printTrace("\nMigrate indexes...",1); + foreach $indexname ( @indexnames ) { + printTrace("\nIndexName: $indexname",4); + printTrace("\nIndexTypes: .@{$newIndex{$indexname}->types}.", 4) ; + printTrace("\nIndexOIDS: .@{$newIndex{$indexname}->oids}.", 4) ; + foreach $suffixname ( @suffixnames ) { + # check if the index already exists ! + printTrace("\nsearch for cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...", 3); + my $entry = $conn->search("cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex"); + if (! $entry) { + # create a new index + printTrace("index $indexname is being created under cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...",2); + my $entry = $conn->newEntry(); + $entry->setDN("cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config"); + $entry->setValues("objectclass", "top", "nsIndex" ) ; + $entry->setValues("cn", $indexname) ; + $entry->setValues("nssystemindex", "false") ; + my @types = @{$newIndex{$indexname}->types} ; + my @oids = @{$newIndex{$indexname}->oids} ; + $entry->setValues("nsindextype", @types) if (@types) ; + $entry->setValues("nsmatchingrule", @oids ) if (@oids); + my $res = $conn->add($entry) ; + if ($res) { + printTrace("\nAdd index successfully: $indexname for backend: $DBNAMES{$suffixname}",2); + } + else { + printMsg("\n Failed to add the index: $indexname to backend: $DBNAMES{$suffixname}"); + $MigrationErrors .= "\n Failed to add the index: $indexname to backend: $DBNAMES{$suffixname}" ; + } + } + elsif ($entry->{nssystemindex}[0] eq "false") { + # if the index is not a system index, we update it + printTrace("\nindex $indexname is being processed under cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...",2); + my @types = @{$newIndex{$indexname}->types} ; printTrace("\ntypes: .@types.",2) ; + my @oids = @{$newIndex{$indexname}->oids} ; printTrace("\noids: .@oids.",2) ; + my @existing_types = $entry->getValues("nsindextype"); + my @existing_oids = $entry->getValues("nsmatchingrule"); + # get the elements present in @types and not present in @existing_types + my @typesToAdd = &getDiff(\@types, \@existing_types); + # same for matchingrules + my @oidsToAdd = &getDiff(\@oids, \@existing_oids); + foreach $newtype (@typesToAdd) { + $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2); + } + foreach $newoid (@oidsToAdd) { + $entry->addValue("nsmatchingrule", $newoid); + } + if (@typesToAdd || @oidsToAdd) { + my $res = $conn->update($entry) ; + if ($res) { + printTrace("\nUpdate index successfully: $indexname for backend: $DBNAMES{$suffixname}",2); + } + else { + printMsg("\n Failed to update the index: $indexname to backend: $DBNAMES{$suffixname}"); + $MigrationErrors .= "\n Failed to update the index: $indexname to backend: $DBNAMES{$suffixname}" ; + } + } + else { + printTrace("\nNothing to update",2); + } + } + else { + printTrace("\nThe index: $indexname is a system index. It can't be updated",2); + } + } + } + + } + else { + # treat the case where the user wants to look at these indexes before processing + } + +} + +############################################################################# +# +# Execute a Perldap command to add all user defined object classes in the new schema + +sub LDAPmodify_User_oc { + my $Filename = shift ; + if (! $USER_OC_FILE_MODIFIED) { + printTrace("\nLDAPmodify_User_oc",4); + printTrace("\nMigrate objectclasses...",1); + foreach $objectname ( @User_oc_names ) { + my $entry = $conn->search("cn=schema", "base","objectclass=*") ; + die "\ncan't connect to object: cn=schema\n" unless ($entry); + printTrace("\nObjectName: $objectname\nValue: $User_oc{$objectname}",3); + next if ($entry->hasValue("objectclasses",$User_oc{$objectname},1)) ; + $entry->addValue("objectclasses",$User_oc{$objectname},"1") ; + my $res = $conn->update($entry) ; + my $err = $conn->getErrorCode(); + if ($res) { + printTrace("\nobjectclass: $User_oc{$objectname} added",2); + } elsif ($err == 20) { # already exists + printTrace("\nobjectclass: $User_oc{$objectname} already exists",1); + } else { + printMsg("\nCan\'t add objectclass to the schema: $User_oc{$objectname}"); + my $msg = $conn->getErrorString(); + printMsg("\nMsg: $msg"); + $MigrationErrors .= "\nCan\'t add objectclass to the schema: $User_oc{$objectname}" ; + } + } + } + else { + # treat the case where the user wants to look at these objectclasses before processing + } +} + +############################################################################# +# +# Execute a Perldap command to add all user defined attributes in the new schema + +sub LDAPmodify_User_at { + my $Filename = shift ; + my @attributenames = keys(%User_at); + if (! $USER_AT_FILE_MODIFIED) { + + printTrace("\nLDAPmodify_User_at",4); + printTrace("\nMigrate attributes...",1); + foreach $attributename ( @attributenames ) { + my $entry = $conn->search("cn=schema", "base","objectclass=*") ; + printTrace("\nAtributeName: $attributename, Value: $User_at{$attributename}",3); + die "\nentry not found cn=schema\n" unless $entry ; + next if ($entry->hasValue("attributetypes",$User_at{$attributename},1) ) ; + my $res = $entry->addValue("attributetypes",$User_at{$attributename},"1") ; + if (! $res) { + printMsg("\nCan\'t add attribute to the schema: $User_at{$attributename}"); + $MigrationErrors .= "\nCan\'t add attribute to the schema: $User_at{$attributename}" ; + } + my $res = $conn->update($entry) ; + my $err = $conn->getErrorCode(); + if ($res) { + printTrace("\nattribute: $attributename added",2); + } elsif ($err == 20) { # already exists + printTrace("\nattribute: $attributename already exists",1); + } + else { + printMsg("\nCan\'t add attribute to the schema: $User_at{$attributename}"); + my $msg = $conn->getErrorString(); + printMsg("\nMsg: $msg"); + $MigrationErrors .= "\nCan\'t add attribute to the schema: $User_at{$attributename}" ; + } + } + } + else { + # treat the case where the user wants to look at these attributes before processing + } +} + +############################################################################# +# Add an object class to the user_oc hash and reset the object !!! +sub AddObjectClass { + my $ObjectClass = shift ; + my $ObjectName = $ObjectClass->{'ObjectName'} ; + my $Object_oid = $ObjectClass->{'Object_oid'} ; + my $Object_superior = $ObjectClass->{'Object_superior'} ; + my $Object_requires = $ObjectClass->{'Object_requires'} ; + my $Object_allows = $ObjectClass->{'Object_allows'} ; + my $ObjectClassDef = "( $Object_oid NAME \'$ObjectName\' DESC \'\' SUP $Object_superior STRUCTURAL MUST ($Object_requires) MAY ($Object_allows) X-ORIGIN \'user defined\' )"; + if ( (!($ObjectName =~ /^top$/i)) && ( ! $User_oc{$ObjectName} )) { + $User_oc{$ObjectName} = $ObjectClassDef ; + push @User_oc_names, $ObjectName ; + printTrace("ObjectName: $ObjectName \nObject_oid: $Object_oid \nObject_superior:$Object_superior \nObject_requires: $Object_requires \nObject_allows: $Object_allows \nObjectClassDefinition: $User_oc{$ObjectName}\n",4); + } + elsif ( ($User_oc{$ObjectName}) && ($User_oc{$ObjectName} ne $ObjectClassDef) ) { + printMsg("\nAttempt to redifine the objectclass: $ObjectName previously defined in your configuration file. Operation not allowed "); + } + else { + printMsg("\nAttempt to redifine the objectclass: top. Operation not allowed"); + } + resetObjectClass($ObjectClass); +} + +############################################################################# +# Build an LDIF attribute and add it to the user_at hash +sub AddAttribute { + my $Attr = shift ; + my $AttributeName = $Attr->{'AttributeName'}; + my $Attribute_oid = $Attr->{'Attribute_oid'}; + my $Attribute_aliases = $Attr->{'Attribute_aliases'}; + my $Attribute_syntax = $Attr->{'Attribute_syntax'}; + my $Attribute_single = $Attr->{'Attribute_single'}; + my $AttributeDef = "( $Attribute_oid NAME ( \'$AttributeName\' $Attribute_aliases) DESC \'User Defined Attribute\' SYNTAX $Attribute_syntax $Attribute_single X-ORIGIN 'user defined' )" ; + printTrace("\nAttributeDef: $AttributeDef",4); + $User_at{$AttributeName} = $AttributeDef ; +} +############################################################################# +# add the index structure to the newIndex hash +sub AddIndex { + my $ref_index = shift ; + my $state = shift ; + printTrace("\nAddIndex, last state: $state",4) ; + if ($state == 1) { + $ref_index->specific("ALL") ; + return 1 ; + } + elsif ($state == 6) { + $ref_index->specific("NONE") ; + return 1 ; + } + if (($state == 1) || ($state == 3) || ($state == 5) || ($state == 6)) { + foreach $name (@{$ref_index->names}) { + $newIndex{$name} = $ref_index ; # record the ref to the index struct in the newIndex hash + } + return 1 ; + } + else { + return 0 ; + } +} + +############################################################################# +# add the plugin structure to the stdPlugin hash + +sub AddPlugin { + my $ref_plugin = shift ; + printTrace("\nAddPlugin",4) ; + $stdPlugins{lc($ref_plugin->name)} = $ref_plugin ; + my $name = $ref_plugin->name ; + my $type = $ref_plugin->type ; + my $enable = $ref_plugin->enable ; + + printTrace("\nPluginName: $name",4); + printTrace("\nPluginType: $type",4); + printTrace("\nPluginEnable: $enable",4); + printTrace("\nPluginArgs: @{$ref_plugin->args}",4); + return 1 ; +} + + +############################################################################# +# parse a plugin definition and call the addindex + +sub ParsePlugin { + my $Plugin = shift ; + my $NumLine = shift ; + my $state = 0 ; + my $ErrorMsg = "Syntax error of a plugin definition. \n line parsed:"; + my $ref_plugin = S_plugin->new(); + printTrace("\nParsePlugin: $_",4); + if (/^plugin\s+(database|extendop|preoperation|postoperation|matchingrule|syntax)\s+(on|off)\s+\"(.*?)\"\s+\"(.*?)\"\s+(\S+)(.*)$/i) { + # $1 = <type>, $2 = <on|off>, $3 = <name>, $4 = <pathname>, $5 = <init_function>, $6 = [<arg>]* + $ref_plugin->name($3); + $ref_plugin->type($1); + $ref_plugin->enable($2); + $_ = $6 ; + my $ArgNb = 0 ; + my $prec ; + my $arg ; + my $Unix_oldDir = $oldDir ; + my $Unix_root = $root ; + grep { s@\\@/@g } $Unix_oldDir if $isNT; + grep { s@\\@/@g } $Unix_root if $isNT; + while (!(/^\s*$/)) { + if (/^\s*\".*?\"/) { + s/^\s*\"(.*?)\"(.*)/$2/i ; + $arg = $1 ; + } + elsif (/^\s*[^\"\s]+/) { + s/^\s*([^\"\s]+)(.*)/$2/i ; + $arg = $1 ; + } + $prec = $_ ; + $_ = $arg ; + + s@$Unix_oldDir@$Unix_root@ig ; + s/$type-$oldname/$type-$newname/ig ; + @{$ref_plugin->args}[$ArgNb++] = $_ ; + $_ = $prec ; + } + if (/^\s*$/) { + return AddPlugin($ref_plugin); + } + else { + return 0 ; + } + } + return 0 ; +} + +############################################################################# +# parse an index definition and call the addindex + +sub ParseIndex { + my $index = shift ; + my $NumLine = shift ; + my $ref_index = S_index->new() ; + my $Value ; + my $state = 0 ; + my $ErrorMsg = "Syntax error of an index definition.\nline parsed:"; + printTrace("\nParseIndex: $_",4) ; + s/,/, /g ; + s/\s+,/,/g ; + s/^index\s+//i ; # substitute the token index + while (!(/^\s*$/)) { + s/^\s*(\S+)(.*)$/$2/ ; + $Value = $1 ; + printTrace("\nValue: $Value",4); + printTrace("\nState: $state",4) ; + SWITCH: { + if ($state == 0) { + if ($Value =~ /[^\.]/) { + if ($Value =~ /(\S+),$/) { + push @{$ref_index->names}, $1 ; + } + else { + $state = 1 ; + push @{$ref_index->names}, $Value ; + } + } + else { + return 0 ; + } + last SWITCH ; + } + if ($state == 1) { + if ($Value =~ /^none$/i) { + $state = 6 ; # end of the index definition + } + elsif ($Value =~ /^\"\"$/) { + $state = 4 ; # we expect to have at least one OID + } + elsif ($Value =~ /(\S+),$/) { + $state = 2 ; + push @{$ref_index->types}, $1 ; + } + else { + $state = 3 ; + push @{$ref_index->types}, $Value ; + } + last SWITCH ; + } + if ($state == 2) { + if ($Value =~ /(\S+),$/) { + push @{$ref_index->types}, $1 ; + } + else { + $state = 3 ; + push @{$ref_index->types}, $Value ; + } + last SWITCH ; + } + if ($state == 3) { + if ($Value =~ /(\S+),$/) { + $state = 4 ; + push @{$ref_index->oids}, $1 ; + } + else { + $state = 5 ; + push @{$ref_index->oids}, $Value ; + } + last SWITCH ; + } + if ($state == 4) { + if ($Value =~ /(\S+),$/) { + push @{$ref_index->oids}, $1 ; + } + else { + $state = 5 ; + push @{$ref_index->oids}, $Value ; + } + last SWITCH ; + } + } + } +return AddIndex($ref_index,$state) ; + +} + +############################################################################# + +sub ParseAttribute { + + + my $Attr = shift ; + my $NumLine = shift ; + my $state = 1 ; + my $ErrorMsg = "Syntax error of an attribute definition.\nline parsed:"; + my %Attribute = ( + 'AttributeName' => "", + 'Attribute_oid' => "", + 'Attribute_aliases' => "", + 'Attribute_syntax' => "", + 'Attribute_single' => "" + ); + my $AttributeName = " "; + printTrace("\nParseAttribute",4); + while (!(/^\s*$/)) { + s/^(.*?)(\S+)\s*$/$1/ ; + printTrace("\nValue: $2",4); + printTrace("\nState: $state",4) ; + my $Value = $2 ; + SWITCH: { + if ($state == 1) { + if (isAllowedModifier($Value)) { + $state = 1 ; + $modifier = lc($Value); + $AttrVar = 'Attribute_' . $modifier ; + $Attribute{$AttrVar} = &getModifierValue($Value) ; + } + elsif (&isAllowedPlugin($Value)) { + $state = 2 ; + $Attribute{'Attribute_syntax'} = &getSyntaxOid($Value) ; + } + else { + return 0 ; + } + last SWITCH ; + } + if ($state == 2) { + if ($Value =~ /[\.]|-oid$/) { + $Attribute{'Attribute_oid'} = "$Value" ; + printTrace("\nAttribute-oid: $Attribute{'Attribute_oid'}",3); + $state = 3 ; + } + elsif ($Value =~ /[^\.]/) { + $AttributeName = $Attribute{'AttributeName'} ; + if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;} + $Attribute{'AttributeName'} = $Value ; + $state = 4 ; + } + else { + return 0 ; + } + last SWITCH ; + } + if ($state == 3) { + if ($Value =~ /[^\.]/) { + $AttributeName = $Attribute{'AttributeName'} ; + if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;} + $Attribute{'AttributeName'} = $Value ; + $state = 4 ; } + else { + return 0 ; + } + last SWITCH ; + } + if ($state == 4) { + if ($Value =~/^attribute$/i){ + $state = 5; + } + elsif ($Value =~/[^\.]/i) { + $AttributeName = $Attribute{'AttributeName'} ; + if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;} + $Attribute{'AttributeName'} = $Value ; + } + else { + return 0 ; + } + last SWITCH ; + } + if ($state == 5) { + return 0 ; + last SWITCH ; + } + } + } + $Attribute{'Attribute_oid'} = $Attribute{'AttributeName'} . '-oid' unless ($Attribute{'Attribute_oid'}) ; + return AddAttribute(\%Attribute) ; +} + + +############################################################################# +# fill in the hash HashParametersName + +sub FillHashParametersName { + my @paramnames = ( keys(%GeneralSrvParamToMigrate), keys(%GlobalConfigLDBMparamToMigrate), keys(%LDBMparamToMigrate)); + foreach $param (@paramnames) { + $HashParametersName{$param} = '\n'; + } +} + + +# Parse parameters +sub ParseParameters { + my $param = shift ; + my $value = shift ; + my $NumLine = shift ; + my $ErrorMsg = "parameter unknown, or not to be migrated: "; + if ($HashParametersName{lc($param)} && ($value !~ /^\s*$/)) { + $HashParametersName{lc($param)} = $value ; + printTrace("\nParam: $param is present",4); + } + else { + printTrace("\n$NumLine, $ErrorMsg,$param",4); + } + +} + +# add general server parameters +sub AddGeneralParameters { + my @paramnames = keys(%GeneralSrvParamToMigrate); + my $entry = $conn->search("cn=config","base","objectclass=*"); + die "\ncan't access to object: cn=config. \nMigration stopped\n" unless ($entry); + printTrace("\nAddGeneralParameters",4); + foreach $param (@paramnames) { + my $LDAPparam = $GeneralSrvParamToMigrate{$param} ; + my $Value = $HashParametersName{$param} ; + if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) { + printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4); + $entry->setValues($LDAPparam, $Value); + my $res = $conn->update($entry); + if ($res) { + printTrace("\nUpdate successfully $LDAPparam ",0); + } + else { + printMsg("\nCan't update parameter: $LDAPparam"); + } + } + } +} + + +# add general LDBM parameters +sub AddGeneralLDBMParameters { + my @paramnames = keys(%GlobalConfigLDBMparamToMigrate); + my $entry = $conn->search("cn=config,cn=ldbm database,cn=plugins,cn=config","base","objectclass=*"); + die "\ncan't access to object: cn=config,cn=ldbm database,cn=plugins,cn=config. \nMigration stopped\n" unless ($entry); + printTrace("\nAddGeneralLDBMParameters",4); + foreach $param (@paramnames) { + my $LDAPparam = $GlobalConfigLDBMparamToMigrate{$param} ; + my $Value = $HashParametersName{$param} ; + if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) { + printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4); + $entry->setValues($LDAPparam, $Value); + my $res = $conn->update($entry); + if ($res) { + printTrace("\nUpdate successfully $LDAPparam ",0); + } + else { + printMsg("\nCan't update parameter: $LDAPparam"); + } + } + } +} + +# add specific LDBM parameters +sub AddSpecificLDBMParameters { + my @paramnames = keys(%LDBMparamToMigrate); + my %REV_DBNAMES = reverse %DBNAMES ; + my @dbnames = keys(%REV_DBNAMES); + printTrace("\nAddSpecificLDBMParameters",4); + foreach $dbname (@dbnames) { + my $entry = $conn->search("cn=$dbname,cn=ldbm database,cn=plugins,cn=config","base","objectclass=*"); + die "\ncan't access to object: cn=$dbname,cn=ldbm database,cn=plugins,cn=config. \nMigration stopped\n" unless ($entry); + foreach $param (@paramnames) { + my $LDAPparam = $LDBMparamToMigrate{$param} ; + my $Value = $HashParametersName{$param} ; + if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) { + printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4); + $entry->setValues($LDAPparam, $Value); + my $res = $conn->update($entry); + if ($res) { + printTrace("\nUpdate successfully $LDAPparam",2); + } + else { + printMsg("\nCan't update parameter: $LDAPparam"); + } + } + } + } +} + +############################################################################# +# Parse a configuration file potentialy tuned by the user (different from slapd.user_oc.conf and slapd.user_at.conf) + +sub ParseConfigurationFile { + + my $FileToParse = shift; + my $NumLine = 0; + my $PARSE_OBJECTCLASSES = 0 ; # 1 if there are objectclass definitions in the file + printTrace("\nParseConfigurationFile: $FileToParse",4) ; + printTrace("\nParse $FileToParse",2); + # read each line of the configuration file + my $CONFIGFILE = "CONFIGFILE.$FileToParse" ; + open( $CONFIGFILE, $FileToParse ) || die "Can't open $FileToParsec: $!: "; + LINE: while ( <$CONFIGFILE> ) { + $NumLine++ ; + if (/^\s*\#/) { # skip comments + next LINE; + } + if (/^\s*$/) { # skip blank lines + next LINE; + } elsif (/^suffix\s+/i) { + chomp($_) ; + CheckSuffix($_) ; + } elsif (/^plugin/i) { + chomp($_); + if (! &isAStandardPlugin($_)) { + push @badPlugins, $_; + } + else { + my $Plugin = $_ ; + if (! &ParsePlugin($_,$NumLine)) { + printMsg("\nLine $NumLine, syntax error of the plugin:\n$Plugin"); + } + } + } elsif (/^index/i) { + chomp($_); + if (! &isAStandardIndex($_)) { + my $Index = $_ ; + if (! &ParseIndex($_,$NumLine)) { + printMsg("\nLine $NumLine, syntax error of index:\n$Index"); + } + } + } elsif (/^include\s+[\"]?(.*?)[\"]?\s*$/i) { + # strip leading and trailing " + my $include_file = $1 ; + grep { s@/@\\@g } $include_file if $isNT; + if (! &isAStandardInclude($include_file)) { + &ParseConfigurationFile($include_file); + } + } elsif (/^attribute\s+\S+/i) { + chomp($_); + my $Attrib = $_ ; + if (! &ParseAttribute($_,$NumLine)) { + printMsg("\nLine $NumLine, syntax error of attribute:\n$Attrib"); + } + } elsif (/^objectclass\s+(\S+)\s*$/i) { + # At least one objectclass is present in the file + $PARSE_OBJECTCLASSES = 1; + } elsif (/^\s*(\S+)\s+[\"]?(.*?)[\"]?\s*$/) { + # Parse parameters and record the associated value in %Oldhash + &ParseParameters($1,$2,$NumLine); + } + } + close($CONFIGFILE); + ParseObjectClassesFile($FileToParse) if ($PARSE_OBJECTCLASSES); # parse objectclass definition + +} + +############################################################################# +# Parse the file specified in the userat attribute + +sub ParseAttributesFile { + my $userat_file=shift ; + my $NumLine = 0; + printTrace("\nParseAttributesFile: $userat_file",4); + printTrace("\nParse user defined attributes file: $userat_file",2); + # read each line of the configuration file + open( ATTRFILE, $userat_file ) || die "Can't open $FileToParsec: $!: "; + LINE: while ( <ATTRFILE> ) { + $NumLine++ ; + if (/^\s*\#/) { # skip comments + next LINE; + } + if (/^\s*$/) { # skip blank lines + next LINE; + } elsif (/^attribute\s+\S+/i) { + chomp($_); + my $Attrib = $_ ; + if (! &ParseAttribute($_, $NumLine)) { + printMsg("\nLine $NumLine, syntax error of attribute:\n$Attrib"); + } + } + } + close(ATTRFILE); +} + +############################################################################# +# Parse the file specified in the useroc token + +sub ParseObjectClassesFile { + my $useroc_file = shift ; + my %ObjectClass = ( + 'ObjectName' => " ", + 'Object_oid' => " ", + 'Object_superior' => "top", + 'Object_requires' => " ", + 'Object_allows' => " " + ); + + my $state = 0; + my $ErrorMsg = "Syntax error of an object class definition.\nline parsed:"; + my $LineNb = 0 ; # Number of the current line parsed in the file + printTrace("ParseObjectClassesFile: $useroc_file\n",4) ; + # read each line of the configuration file + open( OBJCLASSFILE, $useroc_file ) || die "Can't open $FileToParsec: $!: "; + printTrace("Begin the parsing of the file: $useroc_file",4); + LINE: while ( <OBJCLASSFILE> ) { + printTrace("Current Line: $_",4); + $LineNb++ ; + if (/^\s*\#/) { # skip comments + next LINE; + } + if (/^\s*$/) { # skip blank lines + next LINE; + } + SWITCH: { + if ($state == 0) { resetObjectClass(\%ObjectClass); + if (/^objectclass\s+(\S+)\s*$/i) { + $ObjectClass{'ObjectName'} = $1; + $state = 1 ;} + else {} # printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 1) {if (/^\s+oid\s+(\S+)\s*$/i) { + $ObjectClass{'Object_oid'} = $1; + $state = 2 ;} + elsif (/^\s+superior\s+(\S+)\s*$/i) { + $ObjectClass{'Object_superior'} = $1; + $state = 3 ; + } + elsif (/^\s+requires\s*$/i) { + $state = 4; + } + elsif (/^\s+allows\s*$/i) { + $state = 5; + } + else {$state=0; printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 2) {if (/^\s+superior\s+(\S+)\s*$/i) { + $ObjectClass{'Object_superior'} = $1; + $state = 3 ;} + elsif (/^\s+requires\s*$/i) { + $state = 4; + } + elsif (/^\s+allows\s*$/i) { + $state = 5; + } + else { $state=0; printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 3) {if (/^\s+requires\s*$/i) + { $state = 4; } + elsif (/^objectclass\s+(\S+)\s*$/i) { + # run an ldap add before to continue + &AddObjectClass(\%ObjectClass); + $ObjectClass{'ObjectName'} = $1; + $state = 1 ;} + elsif (/^\s+allows\s*$/i) + { $state = 5; } + else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 4) {if (/^\s+([^,\s]+),\s*$/i) { + $ObjectClass{'Object_requires'}.=$1." \$ "; } + elsif (/^\s+([^,\s]+)\s*$/i) { + $ObjectClass{'Object_requires'}.=$1." "; + $state = 6; } + else {$state = 0;printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 5) {if (/^\s+([^,\s]+),\s*$/i) { + $ObjectClass{'Object_allows'}.=$1." \$ "; } + elsif (/^\s+([^,\s]+)\s*$/i) { + $ObjectClass{'Object_allows'}.=$1." "; + # run an ldap add before to continue + &AddObjectClass(\%ObjectClass); + $state = 0; } + else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 6) {if (/^objectclass\s+(\S+)\s*$/i) { + # run an ldap add before to continue + &AddObjectClass(\%ObjectClass); + $ObjectClass{'ObjectName'} = $1; + $state = 1 ;} + elsif (/^\s+allows\s*$/i) { + $state = 5;} + else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + } + } + close(OBJCLASSFILE); + if (($state == 3) || ($state == 4) || ($state == 5) || ($state == 6)) { + &AddObjectClass(\%ObjectClass); + } + printTrace("state: $state",4); +} + +############################################################################# +# printMsg print message to the user standard output. + +sub printMsg { + + my $TypeMsg = shift ; + my $Msg = shift ; + my $LineNb = shift ; + if ($LineNb) { + printTrace("Line: $LineNb, $TypeMsg, $Msg"); + } + else { + printTrace("$TypeMsg $Msg"); + } +} + +############################################################################# +# print message error to the user standard output. + +sub printTrace { + + my $Msg = shift ; + my $level = shift ; + if ($level <= $TRACELEVEL) { + print($Msg); + print LOGFILE $Msg ; + } +} + +############################################################################# +# reset an objectclass structure + +sub resetObjectClass { + my $ObjectClass = shift; + $ObjectClass->{'ObjectName'} = " " ; + $ObjectClass->{'Object_oid'} = " " ; + $ObjectClass->{'Object_superior'} = "top" ; + $ObjectClass->{'Object_requires'} = " " ; + $ObjectClass->{'Object_allows'} = " " ; +} + +############################################################################# +# this subroutine implements a very stupid version of diff + +sub diff { + my $f1 = shift; + my $f2 = shift; + my $lineToBeginWith = shift; + my $NULL = "" ; + my $diff_f1 = $NULL ; + my $diff_f2 = $NULL ; + my $retval = $NULL ; + my $ret; + open(F1, "$f1") or die "Could not open file $f1"; + open(F2, "$f2") or close(F1), die "Could not open file $f2"; + + while (defined($l1 = <F1>)) { + if ($lineToBeginWith){ + $lineToBeginWith -- ; + next ; + } + next if ($l1 =~ /^\#/); + $ret = defined($l2 = <F2>); + if ($ret) { + $ret = defined($l2 = <F2>) while ($ret && ($l2 =~ /^\#/)) ; + if ($ret) { + if (!($l1 eq $l2)) { + + # ignore whitespace + $l1_clean = $l1 ; + $l2_clean = $l2 ; + $l1_clean =~ s/\s//g; + $l2_clean =~ s/\s//g; + + if (!($l1_clean eq $l2_clean)) { + $diff_f1 .= "${l1}" unless ($l1_clean eq $NULL); + $diff_f2 .= "${l2}" unless ($l2_clean eq $NULL); + } + } + } + else { + next if ($l1 =~ /^\s*$/) ; + $diff_f1 .= "${l1}"; + } + } + else { + next if ($l1 =~ /^\s*$/) ; + $diff_f1 .= "${l1}"; + } + } + + while (defined($l2 = <F2>)) { + if (($l2 =~ /^\#/) || ($l2 =~ /^\s*$/)) { + next ; + } + else { + $diff_f2 .= "${l2}" ; + } + } + + close(F1); + close(F2); + + $retval .= "- differences present in your config file but not in standard file:\n\n". "$diff_f1\n" if ($diff_f1) ; + $retval .= "- differences present in standard file but not in your config file:\n\n" . "$diff_f2" if ($diff_f2) ; + return $retval ; +} + +sub CompareStdConfigFiles { + # Compare each configuration file against its default version. If it has changed, + # notify the user that the file has changed and will need to be checked by the + # user. This should be safe to do because there should be no path information + # stored in these conf files, which are just schema stuff. + # printTrace("\nCheck if standard configuration files have changed",3); + + my $origFilePath = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}install${PATHSEP}config${PATHSEP}" ; + my $FilesChanged = ""; + my $AllDiffs = "***********************************************************************"; + my $NoChanges = "" ; + my $lineToBegin = 0 ; + printTrace("\nVersion of the old directory server: $oldVersion.$oldMinor",0); + opendir(CONFDIR, $oldConfDir) or + die "Error: could not open migrated config dir $oldConfDir: $!"; + + foreach $file (readdir(CONFDIR)) { + $origFile = $origFilePath . $file ; + $configFile = $oldConfDir . $file ; + if ((! exists($userDefinedConfigFiles{lc($file)})) && (-f $origFile)) { + my $lineToBegin = 1 if (lc($file) eq "slapd-collations.conf"); # we ignore the first line of slapd-collations + $diffs = &diff($configFile, $origFile, $lineToBegin); + $lineToBegin = 0 if $lineToBegin ; + if ($diffs) { + $FilesChanged .= "\n$configFile"; + $AllDiffs .= "\n$configFile is different than the standard configuration file" ; + $AllDiffs .= "\nYou will need to check this file and make sure its changes are compatible "; + $AllDiffs .= "with the new directory server\nHere are the differences:\n"; + $AllDiffs .= "$diffs \n\n"; + $AllDiffs .= "***********************************************************************"; + } + else { + $NoChanges .= "\n$configFile"; + } + } + } + closedir(CONFDIR); + +if ($FilesChanged) { + printTrace("\nNo changes to old configuration files:$NoChanges",3) ; + printTrace("\n***********************************************************************",3) ; + printMsg("\nThe following standard files have been modified: $FilesChanged"); + if ($NO_INPUT_USER) { + # do nothing + } + else { + printMsg("\nDo you want to see the differences Yes/No [No] ?") ; + my $answer = <STDIN> ; + if ($answer =~ /y|yes/i) { + printMsg("$AllDiffs"); + } + printMsg("\nDo you want to continue the migration Yes/No [No] ?"); + $answer = <STDIN> ; + if (! ($answer =~ /y|yes/i)) { + exit(1); + } + } + } +} + + +############################################################################# + +sub db2ldif { + my ($conf, $ldif_dir) = @_; + $ENV{"$LIB_PATH"}=$old_libpath; + if (!$conf) { + $conf = "$oldHome${PATHSEP}config${PATHSEP}slapd.conf"; + } + if (! $ldif_dir) { $ldif_dir = $ldif_rep ;} + if (!(-d $ldif_dir)) { + mkdir($ldif_dir,0777) or die "can't create $ldif_rep to store temporary ldif files"; + } + my $dir = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server"; + chdir($dir) or + die "Error: could not change directory to $dir: $!"; + my @suffixnames = keys(%DBNAMES) ; + foreach $suffixname (@suffixnames) { + my $ldif_file = $ldif_dir.$DBNAMES{$suffixname}.".ldif" ; + # If we are on NT, ${quote} is setup to "\"", else it's setup to "" + # As the suffix can contain some space characters, I write the suffix parameter: "\"$suffixname\"" rather than "${quote}$suffixname${quote}" + my @cmd = + ( "${quote}$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" . + "${PATHSEP}$slapdExecName${quote}", "db2ldif", '-n', '-f', + "${quote}$conf${quote}", '-a', "${quote}$ldif_file${quote}", + '-d', '1','-s',"\"$suffixname\"" ); + open(DB2LDIF, "${quote}@cmd${quote} 2>&1|") or + die "Error: could not execute @cmd: $!"; + sleep(1); # allow pipe to fill with data + $ii = 0; # counter + while (<DB2LDIF>) { + ++$ii; + if (($ii % 250) == 0) { + printMsg(" Processing...\n"); + } + } + close(DB2LDIF); + # set the ownership of the ldif file; should be the same as the new slapd user id + if ((! $isNt) && ($oldlocaluser ne $localuser)) { + if (-f $ldif_file) { + chown( $newuid, $newgid, $ldif_file) or printMsg("\nUnable to change the ownership of $ldif_file to $localuser") ; + } + } + } + print " Done.\n"; + chdir($curdir) or die "Could not change directory to $curdir: $!"; +} + +############################################################################# +# This db2ldif is used to export database of the new instance + +sub newinst_db2ldif { + my $ldif = shift ; + my $include_suffix = shift ; + my $home = shift ; + my $db2ldif_param = "db2ldif -r -D $home -a $ldif -s \"$include_suffix\""; + + open(DB2LDIF, "${quote}${quote}$slapdExecName${quote} $db2ldif_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n"; + sleep(1); # allow some data to accumulate in the pipe + my $ii = 0; + while (<DB2LDIF>) { + ++$ii; + if (($ii % 250) == 0) { + printMsg(" Processing...\n"); + } + printMsg($_); + } + close(DB2LDIF); + # set the ownership of the ldif file; should be the same as the 5.x slapd user id + if ((! $isNt) && ($oldlocaluser ne $localuser)) { + if (-f $ldif) { + chown( $newuid, $newgid, $ldif) or printMsg("\nUnable to change the ownership of $ldif to $localuser") ; + } + } +} + +############################################################################# + +# this is used to run the system() call, capture exit and signal codes, +# and die() upon badness; the first argument is a directory to change +# dir to, if any, and the rest are passed to system() +sub mySystem { + my $rc = &mySystemNoDie(@_); + my ($dir, @args) = @_; + if ($rc == 0) { +# success + } elsif ($rc == 0xff00) { + die "Error executing @args: error code $rc: $!"; + } elsif ($rc > 0x80) { + $rc >>= 8; + die "Error executing @args: error code $rc: $!"; + } else { + if ($rc & 0x80) { + $rc &= ~0x80; + } + die "Error executing @args: received signal $rc: $!"; + } + + # usually won't get return value + return $rc; +} + +# This version does not die but just returns the error code +sub mySystemNoDie { + my ($dir, @args) = @_; + if ($dir && ($dir ne "")) { + chdir($dir) or die "Could not change directory to $dir: $!"; + } + my $cmd = $args[0]; + # the system {$cmd} avoids some NT shell quoting problems if the $cmd + # needs to be quoted e.g. contains spaces; the map puts double quotes + # around the arguments on NT which are stripped by the command + # interpreter cmd.exe; but don't quote things which are already quoted + my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @args; + my $rc = 0; + if ($cmd =~ /[.](bat|cmd)$/) { + # we have to pass batch files directly to the NT command interpreter + $cmd = $com_spec; +# print "system $cmd /c \"@fixargs\"\n"; + $rc = 0xffff & system {$cmd} '/c', "\"@fixargs\""; + } else { +# print "system $cmd @fixargs\n"; + $rc = 0xffff & system {$cmd} @fixargs; + } + chdir(${curdir}) or die "Could not change directory to $curdir: $!"; + return $rc; +} + +############################################################################# +sub manyLdif2db { + my %rev_dbnames = reverse(%DBNAMES); + @backends = keys(%rev_dbnames); + $ENV{"$LIB_PATH"}=$new_libpath; + chdir($slapdExecDir) or die "Could not change directory to $slapdExecDir: $!"; + foreach $backend (@backends) { + my $ldif = "${ldif_rep}$backend.ldif" ; + if (! -f $ldif) { + $ldif = ${ldif_rep}."data.ldif"; + } + &Ldif2db($ldif, $backend); + } + # remove the empty ldif directory + # but not if using the data dir + if (!$olddatadir) { + rmdir($ldif_rep); + } + chdir($curdir) or die "Could not change directory to $curdir: $!"; +} + + +sub Ldif2db { + my $ldif = shift ; + my $backend = shift ; + my $ldif2db_param = "ldif2db -D $serverHome -n $backend -i $ldif"; + open(LDIF2DB, "${quote}${quote}$slapdExecName${quote} $ldif2db_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n"; + sleep(1); # allow some data to accumulate in the pipe + while (<LDIF2DB>) { + printMsg($_); + } + close(LDIF2DB); + # remove the ldif file after the import + # but not if using the data dir + if (!$olddatadir) { + unlink($ldif) ; + } +} + +############################################################################# + +#sub copyBak { +# opendir( OLDBAK, "$oldHome${PATHSEP}bak" ) || +# die "Can't open directory $oldHome${PATHSEP}bak: $!: "; +# local ( @dirs ) = readdir( OLDBAK ); +# closedir ( OLDBAK ); +# for ( @dirs ) { +# if ( $_ eq "." || $_ eq ".." ) { +# next; +# } elsif ( -d "$oldHome${PATHSEP}bak${PATHSEP}$_" ) { +# $srcDir = "$oldHome${PATHSEP}bak${PATHSEP}$_"; +# $destDir = "$serverHome${PATHSEP}bak${PATHSEP}$_"; +# $srcLDIF = "$oldHome${PATHSEP}ldif${PATHSEP}bak.ldif"; +# $destLDIF = "$serverHome${PATHSEP}ldif${PATHSEP}bak.ldif"; +# mkdir( $destDir , 0755 ) if !( -e $destDir); +# # Converting database +# if ( !$isNT && $newuser ) { +# chown($newuid, $newgid, +# "$serverHome${PATHSEP}bak", $destDir); +# } +# &other_db2ldif($srcDir, $srcLDIF); +# if ($needAclUpg) { +# &mySystem("$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server", +# "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" . +# "${PATHSEP}aclupg$exe_suffix", '-d', '-i', +# $srcLDIF, '-o', $destLDIF); +# } else { +# ©BinFile($srcLDIF, $destLDIF); +# } +# &other_ldif2db($destLDIF, $destDir); +# } +# } +#} +############################################################################# + +sub startServer { + my $instanceDir = ${serverHome} ; + my $errLog = $instanceDir . $PATHSEP . 'logs' . $PATHSEP . 'errors'; + # emulate tail -f + # if the last line we see does not contain "slapd started", try again + my $done = 0; + my $started = 0; + my $code = 0; + my $lastLine = ""; + my $timeout = time + 240; # 4 minutes + $ENV{"$LIB_PATH"}=$new_libpath; + + my $startCmd = $instanceDir . $PATHSEP . 'start' . $script_suffix; + if (! -f $startCmd) { + $startCmd = $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix; + } + printTrace("\nInstanceDir: $instanceDir\n",4); + $code = &mySystem($instanceDir,$startCmd); + open(IN, $errLog) or die "Could not open error log $errLog: $!"; + my $pos = tell(IN); + while (($done == 0) && (time < $timeout)) { + for (; ($done == 0) && ($_ = <IN>); $pos = tell(IN)) { + $lastLine = $_; + # print; + # the server has already been started and shutdown once . . . + if (/slapd started\./) { + $started++; + if ($started == 2) { + $done = 1; + } + # sometimes the server will fail to come up; in that case, restart it + } elsif (/Initialization Failed/) { + # print "Server failed to start: $_"; + $code = &mySystem($instanceDir, $startCmd); + # sometimes the server will fail to come up; in that case, restart it + } elsif (/exiting\./) { + # print "Server failed to start: $_"; + #$code = &mySystem($startCmd); + + $code = &mySystem($instanceDir, $startCmd); + } + } + if ($lastLine =~ /PR_Bind/) { + # server port conflicts with another one, just report and punt + print $lastLine; + print "This server cannot be started until the other server on this\n"; + print "port is shutdown.\n"; + $done = 1; + } + if ($done == 0) { + # rest a bit, then . . . + sleep(2); + # . . . reset the EOF status of the file desc + seek(IN, $pos, 0); + } + } + close(IN); + + if ($started < 2) { + $! = $code; + # $now = time; + # if ($now > $timeout) { + # print "Possible timeout: timeout=$timeout now=$now\n"; + # } + die "Error: could not start server: $!"; + } + + return 0; +} + +sub stopServer { + my $root = shift; + my $name = shift; + $maxStopIterations = 5; + print "\nShutting down server $name . . .\n"; + + $ENV{"$LIB_PATH"}=$new_libpath; + $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop' . $script_suffix . $quote; + if (! -f $stopCmd) { + $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop-slapd' . $script_suffix . $quote; + } + + if (! -f $stopCmd) { + # no stop command, probably a 1.X system; for NT, we'll try net stop + # for unix, we'll get the pid and kill it + if ($isNT) { + $stopCmd = 'net stop ' . $name; + } else { + # see if there is a pid file + $pidfile = $root . $PATHSEP . $name . $PATHSEP . 'logs' . + $PATHSEP . 'pid'; + if (open(PIDFILE, $pidfile)) { + chomp($pid = <PIDFILE>); + close(PIDFILE); + while ($maxStopIterations-- && !$exitCode) { + $exitCode = kill(15, $pid); + } + $stopCmd = undef; + } + } + } + + # keep looping until the stop cmd returns an error code, which usually + # means that what ever we want to stop is stopped, or some other error + # occurred e.g. permission, or no such service + $exitCode = &runAndIgnoreOutput($stopCmd); +# print "stopServer: exitCode=$exitCode\n"; + while ($stopCmd && $maxStopIterations-- && $exitCode) { + $exitCode = &runAndIgnoreOutput($stopCmd); +# print "stopServer: exitCode=$exitCode\n"; + } + + if (!$maxStopIterations) { + print "Warning: could not shutdown the server: $!\n"; + } + + sleep(10) ; + + $exitCode = 0; + +} + + +sub runAndIgnoreOutput { + my $cmd = shift; + printMsg("."); + open(RUNCMD, "${quote}$cmd${quote} 2>&1 |") or die "Error: could not run $cmd: $!"; + printMsg("."); + sleep(1); # allow pipe to fill with data + printMsg("."); + while (<RUNCMD>) { +# print; + } + my $code = close(RUNCMD); +# print "runAndIgnore: code=$code status=$?\n"; + return $?; +} +############################################################################# +# migrate some of entries present in the old DSE.ldif like +# cn=snmp,cn=config +# cn=encryption,cn=config +# all the aci's + +sub MigrateDSE { + printTrace("\nMigrate DSE entries...",1); + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($old_entry = readOneEntry $in) { + my $DN = $old_entry->getDN() ; + SWITCH: { + # migrate the entrie: cn=snmp,cn=config + if ($DN =~ /^cn=SNMP,cn=config$/i) { + my $entry = $conn->search("$DN","base","objectclass=nsSNMP"); + if ($entry) { + my $res = $conn->update($old_entry); + if ($res) { + printTrace("\n$DN updated !",2); + } + else { + printMsg("\nFailed to update $DN"); + } + } + else { + printMsg("\nUnable to get info under $DN"); + } + last SWITCH; + } + # migrate the entrie: cn=encryption,cn=config + if ($DN =~ /cn=encryption,cn=config$/i) { + if ($conn->search("$DN","base","objectclass=*")) { + if ($old_entry->hasValue("objectClass", "nsEncryptionConfig")) { + my $certfile = "alias/slapd-" . $newname . "-cert8.db"; + my $keyfile = "alias/slapd-" . $newname. "-key3.db"; + $old_entry->setValues("nsCertfile",$certfile) if ! $old_entry->hasValue("nsCertfile",$certfile); + $old_entry->setValues("nsKeyfile",$keyfile) if ! $old_entry->hasValue("nsKeyfile",$keyfile); + } + my $res = $conn->update($old_entry); + if ($res) { + printTrace("\n$DN updated !",2); + } + else { + printMsg("\nFailed to update $DN"); + } + } + else { + my $res = $conn->add($old_entry); + if ($res) { + printTrace("\n$DN added !",2); + } + else { + printMsg("\nFailed to add $DN"); + } + } + last SWITCH; + } + if (@{$old_entry->{aci}} && (! ($DN =~ /^cn=monitor$/i)) && (! ($DN =~ /^cn=schema$/i))) { + # migrate aci's + my $entry = $conn->search("$DN","base","objectclass=*"); + if ($entry) { + my $res = $conn->update($old_entry); + if ($res) { + printTrace("\n$DN updated !",2); + } + else { + printMsg("\nFailed to update $DN"); + } + } + else { + my $res = $conn->add($old_entry); + if ($res) { + printTrace("\n$DN added !",2); + } + else { + printMsg("\nFailed to add $DN"); + } + } + last SWITCH; + } + } + } + close(DSELDIF); +} +############################################################################# +# migrate SSL info + +sub MigrateSSL { + my $secPwd = 'bidon' ; + # copy the SSL directory + ©Dir("$oldHome${PATHSEP}ssl","$serverHome${PATHSEP}ssl"); + # copy the cert db and key files + if ( -d "$oldDir${PATHSEP}alias") { + $aliasDir = "$root${PATHSEP}alias"; + if (! -d $aliasDir) { + mkdir($aliasDir, 0750); + } + &stopServer($root,'slapd-'.$newname); + my $keydb = "$aliasDir${PATHSEP}slapd-$newname-key3.db" ; + my $certdb = "$aliasDir${PATHSEP}slapd-$newname-cert8.db" ; + my $certdb7 = "$aliasDir${PATHSEP}slapd-$newname-cert7.db" ; + my $old_keydb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-key3.db" ; + my $old_certdb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-cert7.db"; + my $keydb_backup = "$aliasDir${PATHSEP}slapd-$newname-key3.db_backup" ; + my $certdb_backup = "$aliasDir${PATHSEP}slapd-$newname-cert7.db_backup" ; + if (-f $old_keydb) { + if (-f $keydb) { + if ($NO_INPUT_USER) { + printMsg("\n$keydb already exists. backup in $keydb_backup ..."); + ©BinFile($keydb,$keydb_backup); + ©BinFile($old_keydb,$keydb); + } + else { + print("\n\n$keydb already exists. Do you want to overwrite it ? [no]: "); + my $answer = <STDIN> ; + if ($answer =~ /^y|yes$/i) { + ©BinFile($old_keydb,$keydb); + } + } + } + else { + ©BinFile($old_keydb,$keydb); + } + } + if (-f $old_certdb) { + $mode = (stat($old_certdb))[2] if $PRESERVE; + if (-f $certdb) { + if ($NO_INPUT_USER) { + printMsg("\n$certdb already exists. backup in $certdb_backup ..."); + ©BinFile($certdb,$certdb_backup); + unlink($certdb) || print "Couldn't delete $certdb : $!\n"; + ©BinFile($old_certdb,$certdb7); + } + else { + print("\n\n$certdb already exists. Do you want to overwrite it ? [no]: "); + my $answer = <STDIN> ; + if ($answer =~ /^y|yes$/i) { + unlink($certdb) || print "Couldn't delete $certdb : $!\n"; + ©BinFile($old_certdb,$certdb7); + } + } + } + else { + ©BinFile($old_certdb,$certdb7); + } + } + # copy the old password file + if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") { + ©BinFile( + "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt", + "$aliasDir${PATHSEP}$type-$newname-pin.txt" + ); + } + &startServer(); + if ($PRESERVE) { + chown($newuid,$newgid,$certdb) || print "Failed to set uid $newuid gid $newgid on $certdb : $!\n"; + chmod($mode,$certdb) || print "Failed to set mode $mode on $certdb : $!\n"; + } + } + +} + +sub DisableSSL { + my $entry = $conn->search("cn=config","base","objectclass=*"); + my $LDAPparam = "nsslapd-security" ; + my $Value = "off" ; + if ($entry->{$LDAPparam}[0] ne $Value) { + printTrace("\nDisable SSL...",1); + $entry->setValues($LDAPparam, $Value); + } + my $res = $conn->update($entry); + if ($res) { + printTrace("\nSSL disabled",2); + } + else { + printMsg("\nCan't disable SSL, the server may have problems starting"); + } +} + +# enable the migration of client authentication informations +sub MigrateCertmap { + # backup the old new certmap.conf and replace it with the old certmap.conf file + my $oldCertmap = "$oldDir${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf"; + my $newCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf" ; + my $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ; + if (&hasChangedoldCertmap($oldCertmap)) { + if ($NO_INPUT_USER) { + printMsg("\n$newCertmap has been backup in $backupCertmap"); + ©BinFile($newCertmap,$backupCertmap); + ©BinFile($oldCertmap,$newCertmap); + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\n\nWhere do you want to back up the file $newCertmap [$backupCertmap] ?") ; + my $Answer = <STDIN> ; + $backupCertmap = $Answer if ($Answer ne "\n"); + chomp($backupCertmap); + printTrace("\nDest: .$backupCertmap.",4); + if (-e $backupCertmap) { + printMsg("\n\n$backupCertmap already exists. Do you want to overwrite it Yes/No [No] ?") ; + if (<STDIN> =~ /yes|y/i) { + $Ask = 0 ; + } + else { + $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ; + } + } + else { + $Ask = 0 ; + } + } + printTrace("\nBackup file: $newCertmap in $backupCertmap",4); + ©BinFile($newCertmap,$backupCertmap); + ©BinFile($oldCertmap,$newCertmap); + } + } + else { + } +} + +sub hasChangedoldCertmap { + my $certmapfile = shift ; + my @reference = ("certmap default default", + "default:DNComps", + "default:FilterComps e") ; + my $cpt = 0 ; + printTrace("\nhasChangedoldCertmap",3); + open(CERTMAP,"< $certmapfile"); + while (<CERTMAP>) { + if ((! /^\s*#/) && (! /^\s*$/)) { + my $ref = $reference[$cpt] ; + printTrace("\nValue: $_, ref: $ref",4); + if (! /^\s*$ref\s*$/) { + return 1 ; + } + else { + $cpt++ ; + } + } + } + close (CERTMAP); + printTrace("\ncpt: $cpt",4); + if ($cpt < $#reference) { + return 1 ; + } + else { + return 0 ; + } +} +############################################################################# +# copy a directory to another + +sub copyDir { + my $src = shift; + my $dest = shift; + my $exclude = shift; + + opendir( SRC, $src ) or die "Can't open directory $src: $!: "; + my $mode; + my $uid; + my $gid; + mkdir ( $dest , 0755 ) or die "\nCan't create directory $dest. \nPlease check you have enough rights to create it and/or check that your parent directory exists.\n" if !( -e $dest ); + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + local ( @files ) = readdir ( SRC ); + closedir( SRC ); + for ( @files ) { + if ( $_ eq "." || $_ eq ".." ) { + next; + } elsif ( $exclude && /$exclude/ ) { + next; + } elsif( -d "$src${PATHSEP}$_") { + ©Dir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" ); + } else { + ©BinFile ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_"); + } + } +} + +sub copyBinFile { + my $src = shift; + my $dest = shift; + my $buf = ""; + my $bufsize = 8192; + + open( SRC, $src ) || die "Can't open $src: $!\n"; + # if we are given a directory destination instead of a file, extract the + # filename portion of the source to use as the destination filename + if (-d $dest) { + $dest = $dest . $PATHSEP . &basename($src); + } + open( DEST, ">$dest" ) || die "Can't create $dest: $!\n"; + binmode SRC; + binmode DEST; + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + while (read(SRC, $buf, $bufsize)) { + print DEST $buf; + } + close( SRC ); + close( DEST ); +} +############################################################################# +# backup new configuration files +# backup the directory <new_root_server>/slapd-instance/config in <new_root_server>/slapd-instance/BackupConfig + +sub backupConfigFiles { + # backup the new config files + my $src = "$serverHome${PATHSEP}config" ; + my $dest = "$serverHome${PATHSEP}config_backup" ; + if ($NO_INPUT_USER) { + printMsg("\n$src has been backup in $dest"); + ©Dir($src,$dest); + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\n\nWhere do you want to back up your configuration directory [$dest] ?") ; + my $Answer = <STDIN> ; + $dest = $Answer if ($Answer ne "\n"); + chomp($dest); + printTrace("\nDest: .$dest.",4); + if (-e $dest) { + printMsg("\n\n$dest already exists. Do you want to overwrite it Yes/No [No] ?") ; + if (<STDIN> =~ /yes|y/i) { + $Ask = 0 ; + } + else { + $dest = "$serverHome${PATHSEP}config_backup" ; + } + } + else { + $Ask = 0 ; + } + } + printTrace("\nBackup Directory: $src in $dest",4); + ©Dir($src,$dest); + } +} +############################################################################# + +sub getLDAPservername { + my $oldLDAPservername; + my $LDAPservername; + open(OLDSLAPDCONF, $oldSlapdConf) or + die "\nError: could not open old config file $oldSlapdConf \n"; + while(<OLDSLAPDCONF>) { + chop; + if (/^localhost\s+/i) { + ($oldLDAPservername = $') =~ s/^[\"]//;; + $oldLDAPservername =~ s/[\"]$//; + printTrace("\nName of the old LDAP server: $oldLDAPservername",3); + } + } + close(OLDSLAPDCONF); + + open( DSELDIF, "< $DSEldif" ) || die "\nCan't open $DSEldif \n"; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + my $DN = $entry->getDN() ; + if ($DN =~ /^cn=config$/i) { + my $localhost = "nsslapd-localhost"; + my @values = $entry->getValues($localhost); + if ($#values != -1) { + $LDAPservername = $values[0]; + } + break; + } + } + close(DSELDIF); + # check old and new are installed on the same physical machine. + if (lc($oldLDAPservername) ne lc($LDAPservername)) { + # warn the user he tries to migrate a old server installed on a different machine from the new one + printMsg("\n\nYour old server is on $oldLDAPservername, and your new server is on $LDAPservername. We don't support migration on different machines. Do you want to continue ? Yes/No [No]:") ; + if (! (<STDIN> =~ /yes|y/i)) { + return -1; + } + } + return $LDAPservername ; +} + +############################################################################# + +sub getLibPath { + my $myDir = shift; + my $myVersion = shift; + my $myMinor = shift; + + if ($isNT) { + return $ENV{"$LIB_PATH"}; + } + if (($myVersion >= 6) && ($myMinor >= 2)) { + return + "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}". + "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}". + $ENV{"$LIB_PATH"}; + } else { + return "$myDir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + } +} + +############################################################################# + +sub getVersion { + my $dir = shift; + my $versionstr = shift; + my $version = 0; + my $minor = 0; + my $buildNumber = 0; + my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}"; + + # find the slapd executable + if (!$versionstr) { # version not specified on cmd line - find it + $prog = $dir . $progDir . $slapdExecName; + if (! -f $prog) { + $prog = $dir . $progDir2 . $slapdExecName; + if (-f $prog && $isNT) { + # if slapd is in bin/slapd and we're on NT, just assume version 1; + # apparently, slapd.exe doesn't like the -v argument . . . + return ( '1', $minor ); + } + else{ + die "Could not run slapd program $prog: $!"; + } + } + else { + chdir($dir . $progDir); + } + $cur_libpath=$ENV{"$LIB_PATH"}; + $ENV{"$LIB_PATH"}= + "$dir${PATHSEP}lib${SEP}". + "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}". + "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}". + $ENV{"$LIB_PATH"}; + # read the old version from the old slapd program + + open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or + die "Could not run slapd program $prog: $!"; + sleep(1); # allow some data to accumulate in the pipe +# print "Output from $prog -v:\n"; + while (<F>) { + if (/^Netscape-Directory/ || /^iPlanet-Directory/i) { + $versionstr = $_; + last; + } + } + $code = close(F); + # print "$prog returned code=$code status=$?\n"; + $ENV{"$LIB_PATH"}=$cur_libpath; + } + + if ($versionstr =~ /^Netscape-Directory\/(\d+)\.(\d+)(?:b\d)*\s+(\S+)/) { + $version = $1; + $minor = $2; + $buildNumber = $3; + } + elsif ($versionstr =~ /^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ... + $version = $1; + $minor = $2; + $buildNumber = $3; + } + elsif ($versionstr =~ /^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) { + $version = $1; + $minor = $2; + $buildNumber = $3; + } elsif ($versionstr =~ /(\d+)\.(\d+)/) { + $version = $1; + $minor = $2; + } + + if ($version == 0) { + die "\nCould not determine version of the directory server in $dir: \n"; + } + + # distinguish the 4.1 and the 4.11 thanks to the buildNumber + if (($version == 4) && ($minor == 1)){ + if (! ($buildNumber =~ /^B99\.16/)) { + # it's not a 4.1 Netscape Directory Server => it's a 4.11 + $minor = 11 ; + } + } + chdir($curdir) or die "Could not change directory to $curdir: $!" ; + return ( $version, $minor ); +} + +############################################################################# + +sub getDiff { + # we get references to arrays + my $elements = shift ; + my $existing_elements = shift ; + my %count = () ; + my %countEE = () ; + @diff = () ; + foreach $e (@{$elements}, @{$existing_elements}) { $count{$e}++ ;} + foreach $e (@{existing_elements}) { $countEE{$e}++ ;} + foreach $e (@{$elements}) { + # if $e is only present in @$elements, we push it to the diff array + if (($count{$e} == 1) && ($countEE{$e} == 0)) { + push @diff, $e ; + } + } + return @diff ; +} + +############################################################################################### +sub testIndexUpdating { + #my $entry = $conn->newEntry(); + #$entry->setDN("cn=djeattribute,cn=index,cn=MigratedDB_5,cn=ldbm database,cn=plugins,cn=config"); + my $entry = $conn->search("cn=mail,cn=index,cn=MigratedDB_2,cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex"); + my @types = ("pres", "sub", "eq") ; + my @existing_types = $entry->getValues("nsindextype"); + my @typesToAdd = &getDiff(\@types, \@existing_types); + foreach $newtype (@typesToAdd) { + $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2); + } + my $res = $conn->update($entry) ; + if ($res) {print("\nUpdate index mail\n");} + else { print("\ncan't update index mail");} + + $entry = $conn->search("cn=givenName,cn=index,cn=MigratedDB_2,cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex"); + @types = ("pres", "sub", "eq") ; + @existing_types = $entry->getValues("nsindextype"); print("\ngivenName, existing_types: @existing_types"); + @typesToAdd = &getDiff(\@types, \@existing_types); print("\nTypesToAdd: @typesToAdd"); + foreach $newtype (@typesToAdd) { + $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2); + } + my $res = $conn->update($entry) ; + if ($res) {print("\nUpdate index givenName\n");} + else { print("\ncan't update index givenName");} + } + + +############################################################################################### +sub normalizeDir { + my $dir = shift ; + my $dir_prec = "" ; + while ($dir_prec ne $dir) { + $dir_prec = $dir ; + if ($isNT) { + grep { s@\\\\@\\@g } $dir ; + } + else { + grep { s@//@/@g } $dir ; + } + } + return $dir ; +} + + +############################################################################################### +# return 1 if the value parameters is +sub isAllowedPlugin { + my $Value = lc(shift) ; + if ($allowedPlugins{$Value}) { + return 1 ; + } + else { + return 0 ; + } + +} + + +sub getSyntaxOid { + my $Value = lc(shift) ; + return $allowedPlugins{$Value} ; +} + +############################################################################################### +# return 1 if the value given in parameters is an allowed modifier +sub isAllowedModifier { + my $Value = lc(shift) ; + if ($allowedModifiers{$Value}) { + return 1 ; + } + else { + return 0 ; + } +} + +sub getModifierValue { + my $Value = lc(shift) ; + return $allowedModifiers{$Value} ; +} + +############################################################################################### + +sub GetTime { + my $tm = localtime; + (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900); + $sec = "0$sec" unless $sec > 9 ; + $min = "0$min" unless $min > 9 ; + $hour = "0$hour" unless $hour > 9 ; + $dd = "0$dd" unless $dd > 9 ; + $mm = "0$mm" unless $mm > 9 ; + return ($sec, $min, $hour, $dd, $mm, $yy); +} + +############################################################################################### +# get uid and group id of the new slapd server. +# The uid is done through the nsslapd-localuser attribute + +sub getuid_gid { + my $newuid ; + my $newgid ; + my $localuser ; + my $localuser_attr = "nsslapd-localuser" ; + if (! $isNT) { + my $entry = $conn->search("cn=config ", "base","objectclass=*", 0, ($localuser_attr)) ; + # Tests wether we succeed to get the entry cn=config + die "\nCan't get the entry cn=config \n" unless ($entry); + my @values = $entry->getValues($localuser_attr); + if ($#values == -1 || ($values[0] eq "") ) { # tests wether the nsslapd-localuser attribute has a value + printMsg("\nNo localuser has been found in the configuration of the directory. "); + if ($NO_INPUT_USER) { + printMsg("\nWe considered nobody as the localuser"); + $localuser = "nobody" ; + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\nUnder what user does your $Version.$Minor directory server run [nobody] ? ") ; + $localuser = <STDIN> ; + chomp($localuser); + $localuser = "nobody" if ($localuser eq ""); + ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ; + if ($newuid) { + $Ask = 0 ; + } + else { + printMsg("\nError: $localuser is unknown from the system "); + } + } + } + } + else { + $localuser = $values[0]; # returns the first value (we should only have one localuser) + my $size = $#values ; + } + ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ; + return ($localuser, $newuid, $newgid) ; + } + else { + return () ; + } +} + + +############################################################################################### +# get uid and group id of the old slapd server. + +sub getolduid_gid { + my $oldlocaluser ; + if (! $isNT) { + open(CONF, $oldSlapdConf) or die "\nError: cannot open $oldSlapdConf: $!\n"; + while (<CONF>) { + if (/^localuser\s+/i) { + chomp($oldlocaluser = $'); + last; + } + } + close(CONF); + ($olduid, $oldgid) = (getpwnam("$oldlocaluser"))[2..3] ; + return ($oldlocaluser, $olduid, $oldgid) ; + } + else { + return (); + } +} + +############################################################################################### +# get current directory + +sub getCwd { + my $command = $isNT ? "cd" : "/bin/pwd"; + open(PWDCMD, "$command 2>&1 |") or + die "Error: could not execute $command: $!"; + # without the following sleep, reading from the pipe will + # return nothing; I guess it gives the pwd command time + # to get some data to read . . . + sleep(1); + my $currentdir; + while (<PWDCMD>) { + if (!$currentdir) { + chomp($currentdir = $_); + } + } + my $code = close(PWDCMD); +# if ($code || $?) { +# print "$command returned code=$code status=$? dir=$curdir\n"; +# } +# print "getCwd curdir=\[$curdir\]\n"; + return $currentdir; +} diff --git a/ldap/admin/src/scripts/template-migrateTo7 b/ldap/admin/src/scripts/template-migrateTo7 new file mode 100644 index 00000000..73f71ab9 --- /dev/null +++ b/ldap/admin/src/scripts/template-migrateTo7 @@ -0,0 +1,3268 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# Migrate a old directory server to a 7.0 directory server + +######################################################################################################## +# enable the use of Perldap functions +require DynaLoader; + +use Getopt::Std; +use Mozilla::LDAP::Conn; +use Mozilla::LDAP::Entry; +use Mozilla::LDAP::LDIF; +use Mozilla::LDAP::Utils qw(:all); +use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API +use Time::localtime; + +######################################################################################################## +use Class::Struct ; # load struct-building module + +struct S_index => { + names => '@' , + types => '@' , + oids => '@' , + specific => '$' + }; + + +struct S_plugin => { + name => '$' , + type => '$' , + enable => '$' , + args => '@' + }; +##################################################################################################### + +sub usage { + print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n"); + print(STDERR " -o OldInstancePath -n NewInstancePath [-t tracelevel] [-L logfile]\n"); + print(STDERR "************** parameters in brackets are optionals, others are required **************\n"); + print(STDERR " Opts: -D rootdn - New Directory Manager\n"); + print(STDERR " : -w password - New Directory Manager's password\n"); + print(STDERR " : -w - - Prompt for New Directory Manager's password\n"); + print(STDERR " : -j filename - Read New Directory Manager's password from file\n"); + print(STDERR " : -p port - New Directory Server port\n"); + print(STDERR " : -o OldInstancePath - Path of the Old instance to migrate \n"); + print(STDERR " : -n NewInstancePath - Path of the new instance\n"); + print(STDERR " : [-d dataPath] - Path to directory containing data files to import into new instance\n"); + print(STDERR " : [-v oldVersion] - Old version (obtained by running $slapdExecName -v\n"); + print(STDERR " : [-t tracelevel] - specify the level of trace (0..3)\n"); + print(STDERR " : [-L logfile] - specify the file to log the migration report \n"); + + + } + + + +############# +BEGIN { + + require 'uname.lib' ; + $isNT = -d '\\'; + $PATHSEP = $isNT ? "\\" : "/"; + ${SEP} = $isNT ? ";" : ":" ; + @INC = ( '.', '../../../admin/admin/bin'); + grep { s@/@\\@g } @INC if $isNT; + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + # NT needs quotes around some things unix doesn't + $quote = $isNT ? "\"" : ""; + + # If this variable is set, all file/directory creation will make sure the mode + # and ownership of the destination is the same as the source + $PRESERVE = 1 if (!$isNT); + $script_suffix = $isNT ? ".bat" : ""; + $exe_suffix = $isNT ? ".exe" : ""; + if ($isNT) { + $os = "WINNT"; + } else { + $os = &uname("-s"); + } + if ($isNT) { + # we have to pass batch files directly to the NT command interpreter + $com_spec = $ENV{ComSpec}; + if (!$com_spec) { + $com_spec = $ENV{COMSPEC}; + } + if (!$com_spec || ! -f $com_spec) { + # find the first available command interpreter + foreach $drive (c..z) { + $com_spec = "$drive:\\winnt\\system32\\cmd.exe"; + last if (-f $com_spec); + $com_spec = undef; + } + if (! $com_spec) { + # punt and pray + $com_spec = 'c:\winnt\system32\cmd.exe'; + } + } + } + if ( $os eq "AIX" ) { + $dll_suffix = "_shr.a"; + } + elsif ( $os eq "HP-UX" ) { + $dll_suffix = ".sl"; + } + elsif ( $os eq "WINNT" ) { + $dll_suffix = ".dll"; + } + else { + $dll_suffix = ".so"; + } + $slapdExecName = $isNT ? 'slapd.exe' : './ns-slapd'; + # if this flag is set, we will migrate the old database + # by doing a db2ldif -> ldif2db; + $convertToLDIF = 1; + select STDERR; + $| = 1; + select STDOUT; + $| = 1; + # if the old value for dbcachesize is less than this, make it this + $MIN_DBCACHESIZE = '500000'; +} + +SWITCH: { + if ($os eq "AIX") { + $LIB_PATH = "LIBPATH" ; + last SWITCH ; + } + if ($os eq "HP-UX") { + $LIB_PATH = "SHLIB_PATH" ; + last SWITCH ; + } + if ($isNT) { + $LIB_PATH = "PATH" ; + last SWITCH ; + } + else { + $LIB_PATH = "LD_LIBRARY_PATH" ; + last SWITCH ; + } + } + + # Old parameters + ${oldDir} = "" ; + ${oldname} = "" ; + ${oldHome} = "" ; + ${oldConfDir} = "" ; + ${oldlocaluser} ; + ${olduid} ; + ${oldgid} ; + + # New parameters + ${root} = "{{DS-ROOT}}" ; + ${type} = "" ; + ${newname} = "" ; + ${newport} = "" ; + ${rootDN} = "" ; + ${rootpwd} = "" ; + ${localhost} = "" ; + ${LogFileReport} = "" ; + ${newuid} ; + ${localuser} ; + ${newgid} ; + $NO_INPUT_USER = 0 ; # by default user can give inputs during the migration process + ${curdir} = getCwd(); + ${slapdExecDir} = "${root}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + + # specify the level of trace + $TRACELEVEL=1; + + $LDAP_SERVER_UNREACHABLE = 81; + + # get input users + &getParameters() ; + ${oldDir} = &normalizeDir("${oldDir}"); + ${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ; + ${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ; + ${oldSlapdConf} = "${oldConfDir}slapd.conf" ; + ${oldDSEldif} = "${oldConfDir}dse.ldif" ; + ${serverHome} = "${root}${PATHSEP}$type-$newname" ; + ${DSEldif} = "$serverHome${PATHSEP}config${PATHSEP}dse.ldif"; + ${ldif_rep} = "${oldConfDir}${PATHSEP}ldif${PATHSEP}" ; + ${oldSlapdExecDir} = "${oldDir}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + + + + + open(LOGFILE, ">> $LogFileReport"); + + printTrace("\noldDir: $oldDir, oldHome: $oldHome, \noldConfDir: $oldConfDir, \noldSlapdConf: $oldSlapdConf, \nldif_rep: $ldif_rep, \nrootDN: $rootDN, \nPwd: ******, \nPort: $newport, \nNewname: $newname\n",3); + printTrace("\nLIB_PATH: $LIB_PATH",4); + + if (!(-d $serverHome)) { + printMsg("\n$serverHome doesn't exist\n"); + exit(1); + } + if (!(-d $oldHome)) { + printMsg("\n$oldHome doesn't exist\n"); + exit(1); + } + + if ($olddatadir && !(-d $olddatadir)) { + print("\n$olddatadir doesn't exist\n"); + exit(1); + } + +#define CONFIG_DATABASE_DIRECTIVE "database" +#define CONFIG_DATABASE_ATTRIBUTE "nsslapd-database" +#define CONFIG_PLUGIN_DIRECTIVE "plugin" +#define CONFIG_PLUGIN_ATTRIBUTE "nsslapd-plugin" +#define CONFIG_SIZELIMIT_DIRECTIVE "sizelimit" +#define CONFIG_SIZELIMIT_ATTRIBUTE "nsslapd-sizelimit" +#define CONFIG_ORCAUTO_DIRECTIVE "orcauto" +#define CONFIG_ORCAUTO_ATTRIBUTE "nsslapd-orcauto" +#define CONFIG_TIMELIMIT_DIRECTIVE "timelimit" +#define CONFIG_TIMELIMIT_ATTRIBUTE "nsslapd-timelimit" +#define CONFIG_SUFFIX_DIRECTIVE "suffix" +#define CONFIG_SUFFIX_ATTRIBUTE "nsslapd-suffix" +#define CONFIG_READONLY_DIRECTIVE "readonly" +#define CONFIG_READONLY_ATTRIBUTE "nsslapd-readonly" +#define CONFIG_REFERRAL_DIRECTIVE "referral" +#define CONFIG_REFERRAL_ATTRIBUTE "nsslapd-referral" +#define CONFIG_OBJECTCLASS_DIRECTIVE "objectclass" +#define CONFIG_OBJECTCLASS_ATTRIBUTE "nsslapd-objectclass" +#define CONFIG_ATTRIBUTE_DIRECTIVE "attribute" +#define CONFIG_ATTRIBUTE_ATTRIBUTE "nsslapd-attribute" +#define CONFIG_SCHEMACHECK_DIRECTIVE "schemacheck" +#define CONFIG_SCHEMACHECK_ATTRIBUTE "nsslapd-schemacheck" +#define CONFIG_LOGLEVEL_DIRECTIVE "loglevel" +#define CONFIG_LOGLEVEL_ATTRIBUTE "nsslapd-errorlog-level" +#define CONFIG_ACCESSLOGLEVEL_DIRECTIVE "accessloglevel" +#define CONFIG_ACCESSLOGLEVEL_ATTRIBUTE "nsslapd-accesslog-level" +#define CONFIG_ACCESSLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "accesslog-maxNumOfLogsPerDir" +#define CONFIG_ACCESSLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-accesslog-maxlogsperdir" +#define CONFIG_ERRORLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "errorlog-maxNumOfLogsPerDir" +#define CONFIG_ERRORLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-errorlog-maxlogsperdir" +#define CONFIG_AUDITLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "auditlog-maxNumOfLogsPerDir" +#define CONFIG_AUDITLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-auditlog-maxlogsperdir" +#define CONFIG_ACCESSLOG_MAXLOGSIZE_DIRECTIVE "accesslog-maxlogsize" +#define CONFIG_ACCESSLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-accesslog-maxlogsize" +#define CONFIG_ERRORLOG_MAXLOGSIZE_DIRECTIVE "errorlog-maxlogsize" +#define CONFIG_ERRORLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-errorlog-maxlogsize" +#define CONFIG_AUDITLOG_MAXLOGSIZE_DIRECTIVE "auditlog-maxlogsize" +#define CONFIG_AUDITLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-auditlog-maxlogsize" +#define CONFIG_ACCESSLOG_LOGROTATIONTIME_DIRECTIVE "accesslog-logrotationtime" +#define CONFIG_ACCESSLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-accesslog-logrotationtime" +#define CONFIG_ERRORLOG_LOGROTATIONTIME_DIRECTIVE "errorlog-logrotationtime" +#define CONFIG_ERRORLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-errorlog-logrotationtime" +#define CONFIG_AUDITLOG_LOGROTATIONTIME_DIRECTIVE "auditlog-logrotationtime" +#define CONFIG_AUDITLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-auditlog-logrotationtime" +#define CONFIG_ACCESSLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "accesslog-logrotationtimeunit" +#define CONFIG_ACCESSLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-accesslog-logrotationtimeunit" +#define CONFIG_ERRORLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "errorlog-logrotationtimeunit" +#define CONFIG_ERRORLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-errorlog-logrotationtimeunit" +#define CONFIG_AUDITLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "auditlog-logrotationtimeunit" +#define CONFIG_AUDITLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-auditlog-logrotationtimeunit" +#define CONFIG_ACCESSLOG_MAXLOGDISKSPACE_DIRECTIVE "accesslog-maxlogdiskspace" +#define CONFIG_ACCESSLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-accesslog-logmaxdiskspace" +#define CONFIG_ERRORLOG_MAXLOGDISKSPACE_DIRECTIVE "errorlog-maxlogdiskspace" +#define CONFIG_ERRORLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-errorlog-logmaxdiskspace" +#define CONFIG_AUDITLOG_MAXLOGDISKSPACE_DIRECTIVE "auditlog-maxlogdiskspace" +#define CONFIG_AUDITLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-auditlog-logmaxdiskspace" +#define CONFIG_ACCESSLOG_MINFREEDISKSPACE_DIRECTIVE "accesslog-minfreediskspace" +#define CONFIG_ACCESSLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-accesslog-logminfreediskspace" +#define CONFIG_ERRORLOG_MINFREEDISKSPACE_DIRECTIVE "errorlog-minfreediskspace" +#define CONFIG_ERRORLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-errorlog-logminfreediskspace" +#define CONFIG_AUDITLOG_MINFREEDISKSPACE_DIRECTIVE "auditlog-minfreediskspace" +#define CONFIG_AUDITLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-auditlog-logminfreediskspace" +#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIME_DIRECTIVE "accesslog-logexpirationtime" +#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-accesslog-logexpirationtime" +#define CONFIG_ERRORLOG_LOGEXPIRATIONTIME_DIRECTIVE "errorlog-logexpirationtime" +#define CONFIG_ERRORLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-errorlog-logexpirationtime" +#define CONFIG_AUDITLOG_LOGEXPIRATIONTIME_DIRECTIVE "auditlog-logexpirationtime" +#define CONFIG_AUDITLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-auditlog-logexpirationtime" +#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "accesslog-logexpirationtimeunit" +#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-accesslog-logexpirationtimeunit" +#define CONFIG_ERRORLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "errorlog-logexpirationtimeunit" +#define CONFIG_ERRORLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-errorlog-logexpirationtimeunit" +#define CONFIG_AUDITLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "auditlog-logexpirationtimeunit" +#define CONFIG_AUDITLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-auditlog-logexpirationtimeunit" +#define CONFIG_ACCESSLOG_LOGGING_ENABLED_DIRECTIVE "accesslog-logging-enabled" +#define CONFIG_ACCESSLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-accesslog-logging-enabled" +#define CONFIG_ERRORLOG_LOGGING_ENABLED_DIRECTIVE "errorlog-logging-enabled" +#define CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-errorlog-logging-enabled" +#define CONFIG_AUDITLOG_LOGGING_ENABLED_DIRECTIVE "auditlog-logging-enabled" +#define CONFIG_AUDITLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-auditlog-logging-enabled" +#define CONFIG_ROOTDN_DIRECTIVE "rootdn" +#define CONFIG_ROOTDN_ATTRIBUTE "nsslapd-rootdn" +#define CONFIG_ROOTPW_DIRECTIVE "rootpw" +#define CONFIG_ROOTPW_ATTRIBUTE "nsslapd-rootpw" +#define CONFIG_ROOTPWSTORAGESCHEME_DIRECTIVE "rootpwstoragescheme" +#define CONFIG_ROOTPWSTORAGESCHEME_ATTRIBUTE "nsslapd-rootpwstoragescheme" +#define CONFIG_UPDATEDN_DIRECTIVE "updatedn" +#define CONFIG_UPDATEDN_ATTRIBUTE "nsslapd-updatedn" +#define CONFIG_UPDATEPW_DIRECTIVE "updatepw" +#define CONFIG_UPDATEPW_ATTRIBUTE "nsslapd-updatepw" +#define CONFIG_UPDATESSLCLIENT_DIRECTIVE "updateSSLclient" +#define CONFIG_UPDATESSLCLIENT_ATTRIBUTE "nsslapd-updateSSLclient" +#define CONFIG_AUDITFILE_DIRECTIVE "auditfile" +#define CONFIG_AUDITFILE_ATTRIBUTE "nsslapd-auditlog" +#define CONFIG_LASTMOD_DIRECTIVE "lastmod" +#define CONFIG_LASTMOD_ATTRIBUTE "nsslapd-lastmod" +#define CONFIG_INCLUDE_DIRECTIVE "include" +#define CONFIG_INCLUDE_ATTRIBUTE "nsslapd-include" +#define CONFIG_DYNAMICCONF_DIRECTIVE "dynamicconf" +#define CONFIG_DYNAMICCONF_ATTRIBUTE "nsslapd-dynamicconf" +#define CONFIG_USEROC_DIRECTIVE "useroc" +#define CONFIG_USEROC_ATTRIBUTE "nsslapd-useroc" +#define CONFIG_USERAT_DIRECTIVE "userat" +#define CONFIG_USERAT_ATTRIBUTE "nsslapd-userat" +#define CONFIG_SVRTAB_DIRECTIVE "svrtab" +#define CONFIG_SVRTAB_ATTRIBUTE "nsslapd-svrtab" +#ifndef _WIN32 +#define CONFIG_LOCALUSER_DIRECTIVE "localuser" +#define CONFIG_LOCALUSER_ATTRIBUTE "nsslapd-localuser" +#endif /* !_WIN32 */ +#define CONFIG_LOCALHOST_DIRECTIVE "localhost" +#define CONFIG_LOCALHOST_ATTRIBUTE "nsslapd-localhost" +#define CONFIG_PORT_DIRECTIVE "port" +#define CONFIG_PORT_ATTRIBUTE "nsslapd-port" +#define CONFIG_LISTENHOST_DIRECTIVE "listenhost" +#define CONFIG_LISTENHOST_ATTRIBUTE "nsslapd-listenhost" +#define CONFIG_SECURITY_DIRECTIVE "security" +#define CONFIG_SECURITY_ATTRIBUTE "nsslapd-security" +#define CONFIG_SSL3CIPHERS_DIRECTIVE "SSL3ciphers" +#define CONFIG_SSL3CIPHERS_ATTRIBUTE "nsslapd-SSL3ciphers" +#define CONFIG_ACCESSLOG_DIRECTIVE "accesslog" +#define CONFIG_ACCESSLOG_ATTRIBUTE "nsslapd-accesslog" +#define CONFIG_ERRORLOG_DIRECTIVE "errorlog" +#define CONFIG_ERRORLOG_ATTRIBUTE "nsslapd-errorlog" +#define CONFIG_INSTANCEDIR_DIRECTIVE "instancedir" +#define CONFIG_INSTANCEDIR_ATTRIBUTE "nsslapd-instancedir" +#define CONFIG_SECUREPORT_DIRECTIVE "secure-port" +#define CONFIG_SECUREPORT_ATTRIBUTE "nsslapd-securePort" +#define CONFIG_SECURELISTENHOST_DIRECTIVE "secure-listenhost" +#define CONFIG_SECURELISTENHOST_ATTRIBUTE "nsslapd-securelistenhost" +#define CONFIG_THREADNUMBER_DIRECTIVE "threadnumber" +#define CONFIG_THREADNUMBER_ATTRIBUTE "nsslapd-threadnumber" +#define CONFIG_MAXTHREADSPERCONN_DIRECTIVE "maxthreadsperconn" +#define CONFIG_MAXTHREADSPERCONN_ATTRIBUTE "nsslapd-maxthreadsperconn" +#if !defined(_WIN32) && !defined(AIX) +#define CONFIG_MAXDESCRIPTORS_DIRECTIVE "maxdescriptors" +#define CONFIG_MAXDESCRIPTORS_ATTRIBUTE "nsslapd-maxdescriptors" +#endif /* !_WIN32 && ! AIX */ +#define CONFIG_RESERVEDESCRIPTORS_DIRECTIVE "reservedescriptors" +#define CONFIG_RESERVEDESCRIPTORS_ATTRIBUTE "nsslapd-reservedescriptors" +#define CONFIG_IDLETIMEOUT_DIRECTIVE "idletimeout" +#define CONFIG_IDLETIMEOUT_ATTRIBUTE "nsslapd-idletimeout" +#define CONFIG_IOBLOCKTIMEOUT_DIRECTIVE "ioblocktimeout" +#define CONFIG_IOBLOCKTIMEOUT_ATTRIBUTE "nsslapd-ioblocktimeout" +#define CONFIG_NTSYNCH_DIRECTIVE "ntsynch" +#define CONFIG_NTSYNCH_ATTRIBUTE "nsslapd-NTSynch" +#define CONFIG_NTSYNCHUSESSL_DIRECTIVE "ntsynchusessl" +#define CONFIG_NTSYNCHUSESSL_ATTRIBUTE "nsslapd-NTSynch-SSL" +#define CONFIG_NTSYNCHPORT_DIRECTIVE "ntsynch-port" +#define CONFIG_NTSYNCHPORT_ATTRIBUTE "nsslapd-NTSynch-port" +#define CONFIG_ACCESSCONTROL_DIRECTIVE "accesscontrol" +#define CONFIG_ACCESSCONTROL_ATTRIBUTE "nsslapd-accesscontrol" +#define CONFIG_GROUPEVALNESTLEVEL_DIRECTIVE "groupevalnestlevel" +#define CONFIG_GROUPEVALNESTLEVEL_ATTRIBUTE "nsslapd-groupevalnestlevel" +#define CONFIG_NAGLE_DIRECTIVE "nagle" +#define CONFIG_NAGLE_ATTRIBUTE "nsslapd-nagle" +#define CONFIG_PW_CHANGE_DIRECTIVE "pw_change" +#define CONFIG_PW_CHANGE_ATTRIBUTE "passwordChange" +#define CONFIG_PW_MUSTCHANGE_DIRECTIVE "pw_must_change" +#define CONFIG_PW_MUSTCHANGE_ATTRIBUTE "passwordMustChange" +#define CONFIG_PW_SYNTAX_DIRECTIVE "pw_syntax" +#define CONFIG_PW_SYNTAX_ATTRIBUTE "passwordCheckSyntax" +#define CONFIG_PW_MINLENGTH_DIRECTIVE "pw_minlength" +#define CONFIG_PW_MINLENGTH_ATTRIBUTE "passwordMinLength" +#define CONFIG_PW_EXP_DIRECTIVE "pw_exp" +#define CONFIG_PW_EXP_ATTRIBUTE "passwordExp" +#define CONFIG_PW_MAXAGE_DIRECTIVE "pw_maxage" +#define CONFIG_PW_MAXAGE_ATTRIBUTE "passwordMaxAge" +#define CONFIG_PW_MINAGE_DIRECTIVE "pw_minage" +#define CONFIG_PW_MINAGE_ATTRIBUTE "passwordMinAge" +#define CONFIG_PW_WARNING_DIRECTIVE "pw_warning" +#define CONFIG_PW_WARNING_ATTRIBUTE "passwordWarning" +#define CONFIG_PW_HISTORY_DIRECTIVE "pw_history" +#define CONFIG_PW_HISTORY_ATTRIBUTE "passwordHistory" +#define CONFIG_PW_INHISTORY_DIRECTIVE "pw_inhistory" +#define CONFIG_PW_INHISTORY_ATTRIBUTE "passwordInHistory" +#define CONFIG_PW_LOCKOUT_DIRECTIVE "pw_lockout" +#define CONFIG_PW_LOCKOUT_ATTRIBUTE "passwordLockout" +#define CONFIG_PW_STORAGESCHEME_DIRECTIVE "pw_storagescheme" +#define CONFIG_PW_STORAGESCHEME_ATTRIBUTE "passwordStorageScheme" +#define CONFIG_PW_MAXFAILURE_DIRECTIVE "pw_maxfailure" +#define CONFIG_PW_MAXFAILURE_ATTRIBUTE "passwordMaxFailure" +#define CONFIG_PW_UNLOCK_DIRECTIVE "pw_unlock" +#define CONFIG_PW_UNLOCK_ATTRIBUTE "passwordUnlock" +#define CONFIG_PW_LOCKDURATION_DIRECTIVE "pw_lockduration" +#define CONFIG_PW_LOCKDURATION_ATTRIBUTE "passwordLockoutDuration" +#define CONFIG_PW_RESETFAILURECOUNT_DIRECTIVE "pw_resetfailurecount" +#define CONFIG_PW_RESETFAILURECOUNT_ATTRIBUTE "passwordResetFailureCount" +#define CONFIG_ACCESSLOG_BUFFERING_DIRECTIVE "logbuffering" +#define CONFIG_ACCESSLOG_BUFFERING_ATTRIBUTE "nsslapd-accesslog-logbuffering" +#define CONFIG_CHANGELOG_DIR_DIRECTIVE "changelogdir" +#define CONFIG_CHANGELOG_DIR_ATTRIBUTE "nsslapd-changelogdir" +#define CONFIG_CHANGELOG_SUFFIX_DIRECTIVE "changelogsuffix" +#define CONFIG_CHANGELOG_SUFFIX_ATTRIBUTE "nsslapd-changelogsuffix" +#define CONFIG_CHANGELOG_MAXENTRIES_DIRECTIVE "changelogmaxextries" +#define CONFIG_CHANGELOG_MAXENTRIES_ATTRIBUTE "nsslapd-changelogmaxentries" +#define CONFIG_CHANGELOG_MAXAGE_DIRECTIVE "changelogmaxage" +#define CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE "nsslapd-changelogmaxage" +#define CONFIG_RETURN_EXACT_CASE_DIRECTIVE "return_exact_case" +#define CONFIG_RESULT_TWEAK_DIRECTIVE "result_tweak" +#define CONFIG_REFERRAL_MODE_DIRECTIVE "referralmode" +#define CONFIG_ATTRIBUTE_NAME_EXCEPTION_DIRECTIVE "attribute_name_exceptions" +#define CONFIG_MAXBERSIZE_DIRECTIVE "maxbersize" +#define CONFIG_VERSIONSTRING_DIRECTIVE "versionstring" +#define CONFIG_ENQUOTE_SUP_OC_DIRECTIVE "enquote_sup_oc" +#define CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE "nsslapd-enquote_sup_oc" +#define CONFIG_BASEDN_DIRECTIVE "certmap-basedn" +#define CONFIG_BASEDN_ATTRIBUTE "nsslapd-certmap-basedn" + +%HashParametersName = (); + +# The following hash displays only general server parameters to migrate under cn=config +%GeneralSrvParamToMigrate = ( + 'accesscontrol' => 'nsslapd-accesscontrol', + 'errorlog-logging-enabled' => 'nsslapd-errorlog-logging-enabled', + 'accesslog-logging-enabled' => 'nsslapd-accesslog-logging-enabled', + 'auditlog-logging-enabled' => 'nsslapd-auditlog-logging-enabled', + 'logbuffering' => 'nsslapd-accesslog-logbuffering', + 'accesslog-logexpirationtime' => 'nsslapd-accesslog-logexpirationtime', + 'accesslog-logexpirationtimeunit' => 'nsslapd-accesslog-logexpirationtimeunit', + 'accesslog-maxlogdiskspace' => 'nsslapd-accesslog-logmaxdiskspace', + 'accesslog-minfreediskspace' => 'nsslapd-accesslog-logminfreediskspace', + 'accesslog-logrotationtime' => 'nsslapd-accesslog-logrotationtime', + 'accesslog-logrotationtimeunit' => 'nsslapd-accesslog-logrotationtimeunit', + 'accesslog-maxlogsize' => 'nsslapd-accesslog-maxlogsize', + 'accesslog-maxnumoflogsperdir' => 'nsslapd-accesslog-maxLogsPerDir', + 'auditlog-logexpirationtime' => 'nsslapd-auditlog-logexpirationtime', + 'auditlog-logexpirationtimeunit' => 'nsslapd-auditlog-logexpirationtimeunit', + 'auditlog-maxlogdiskspace' => 'nsslapd-auditlog-logmaxdiskspace', + 'auditlog-minfreediskspace' => 'nsslapd-auditlog-logminfreediskspace', + 'auditlog-logrotationtime' => 'nsslapd-auditlog-logrotationtime', + 'auditlog-logrotationtimeunit' => 'nsslapd-auditlog-logrotationtimeunit', + 'auditlog-maxlogsize' => 'nsslapd-auditlog-maxlogsize', + 'auditlog-maxnumoflogsperdir' => 'nsslapd-auditlog-maxLogsPerDir', + 'certmap-basedn' => 'nsslapd-certmap-basedn', + 'enquote_sup_oc' => 'nsslapd-enquote-sup-oc', + 'loglevel' => 'nsslapd-errorlog-level', + 'errorlog-logexpirationtime' => 'nsslapd-errorlog-logexpirationtime', + 'errorlog-logexpirationtimeunit' => 'nsslapd-errorlog-logexpirationtimeunit', + 'errorlog-maxlogdiskspace' => 'nsslapd-errorlog-logmaxdiskspace', + 'errorlog-minfreediskspace' => 'nsslapd-errorlog-logminfreediskspace', + 'errorlog-logrotationtime' => 'nsslapd-errorlog-logrotationtime', + 'errorlog-logrotationtimeunit' => 'nsslapd-errorlog-logrotationtimeunit', + 'errorlog-maxlogsize' => 'nsslapd-errorlog-maxlogsize', + 'errorlog-maxnumoflogsperdir' => 'nsslapd-errorlog-maxlogsperdir', + 'idletimeout' => 'nsslapd-idletimeout', + 'ioblocktimeout' => 'nsslapd-ioblocktimeout', + 'lastmod' => 'nsslapd-lastmod', + 'listenhost' => 'nsslapd-listenhost', + 'maxdescriptors' => 'nsslapd-maxdescriptors', + 'referral' => 'nsslapd-referral', + 'reservedescriptors' => 'nsslapd-reservedescriptors', + 'rootpwstoragescheme' => 'nsslapd-rootpwstoragescheme', + 'schemacheck' => 'nsslapd-schemacheck', + 'secure-port' => 'nsslapd-securePort', + 'security' => 'nsslapd-security', + 'sizelimit' => 'nsslapd-sizelimit', + 'SSL3ciphers' => 'nsslapd-SSL3ciphers', + 'timelimit' => 'nsslapd-timelimit', + 'pw_change' => 'passwordChange', + 'pw_syntax' => 'passwordCheckSyntax', + 'pw_exp' => 'passwordExp', + 'pw_history' => 'passwordHistory', + 'pw_inhistory' => 'passwordInHistory', + 'pw_lockout' => 'passwordLockout', + 'pw_lockduration' => 'passwordLockoutDuration', + 'pw_maxage' => 'passwordMaxAge', + 'pw_maxfailure' => 'passwordMaxFailure', + 'pw_minage' => 'passwordMinAge', + 'pw_minlength' => 'passwordMinLength', + 'pw_must_change' => 'passwordMustChange', + 'pw_resetfailurecount' => 'passwordResetFailureCount', + 'pw_storagescheme' => 'passwordStorageScheme', + 'pw_unlock' => 'passwordUnlock', + 'pw_warning' => 'passwordWarning' +); + +# the following hash displays global parameters related to database stored under cn=config,cn=ldbm database,cn=plugins,cn=config +%GlobalConfigLDBMparamToMigrate = ( + 'allidsthreshold' => 'nsslapd-allidsthreshold', + 'lookthroughlimit' => 'nsslapd-lookthroughlimit', + 'mode' => 'nsslapd-mode', + 'dbcachesize' => 'nsslapd-dbcachesize' +); + +# the following hash displays specific parameters to each backends and stored under cn=DBname,cn=ldbm database,cn=plugins,cn=config +%LDBMparamToMigrate = ( + 'cachesize' => 'nsslapd-cachesize', + 'readonly' => 'nsslapd-readonly' +); + +%stdIncludes = ( + "${oldConfDir}slapd.at.conf", "\n", + "${oldConfDir}slapd.oc.conf", "\n", + "${oldConfDir}java-object-schema.conf", "\n", + "${oldConfDir}ns-admin-schema.conf", "\n", + "${oldConfDir}ns-calendar-schema.conf", "\n", + "${oldConfDir}ns-certificate-schema.conf", "\n", + "${oldConfDir}ns-common-schema.conf", "\n", + "${oldConfDir}ns-compass-schema.conf", "\n", + "${oldConfDir}ns-delegated-admin-schema.conf", "\n", + "${oldConfDir}ns-directory-schema.conf", "\n", + "${oldConfDir}ns-legacy-schema.conf", "\n", + "${oldConfDir}ns-mail-schema.conf", "\n", + "${oldConfDir}ns-mcd-browser-schema.conf", "\n", + "${oldConfDir}ns-mcd-config-schema.conf", "\n", + "${oldConfDir}ns-mcd-li-schema.conf", "\n", + "${oldConfDir}ns-mcd-mail-schema.conf", "\n", + "${oldConfDir}ns-media-schema.conf", "\n", + "${oldConfDir}ns-mlm-schema.conf", "\n", + "${oldConfDir}ns-msg-schema.conf", "\n", + "${oldConfDir}ns-netshare-schema.conf", "\n", + "${oldConfDir}ns-news-schema.conf", "\n", + "${oldConfDir}ns-proxy-schema.conf", "\n", + "${oldConfDir}ns-value-schema.conf", "\n", + "${oldConfDir}ns-wcal-schema.conf", "\n", + "${oldConfDir}ns-cos-schema.conf", "\n", + "${oldConfDir}ns-web-schema.conf", "\n" +); + +%userDefinedConfigFiles = ( + "slapd.conf", "\n", + "slapd.ldbm.conf", "\n", + "slapd.user_at.conf", "\n", + "slapd.user_oc.conf", "\n", + "ns-schema.conf", "\n" + ); + +$CIS_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.15" ; +$TELEPHONE_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.50" ; +$DN_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.12" ; +$CES_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.26" ; +$INT_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.27" ; +$BIN_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.5" ; + +%allowedPlugins = ( + "cis", $CIS_SYNTAX_OID, + "tel", $TELEPHONE_SYNTAX_OID, + "dn", $DN_SYNTAX_OID, + "ces", $CES_SYNTAX_OID, + "int", $INT_SYNTAX_OID, + "bin", $BIN_SYNTAX_OID + ); + +%allowedModifiers = ( + "single", "SINGLE-VALUE" + ); +# "override" is not supported anymore and "operational" cannot be used in user defined attribute. + +@oldSuffixes = () ; # array of old suffixes (with "o=netscaperoot" if presents) + +# link beetwen the name of the suffix and its associated DBname +%DBNAMES = () ; +%DBDirectory = () ; + +%oldhash = () ; + +# list of standard plugin's in version 4 +%stdPlugins = ( + "7-bit check" => "\n", + "binary syntax" => "\n", + "case exact string syntax" => "\n", + "case ignore string syntax" => "\n", + "distinguished name syntax" => "\n", + "integer syntax" => "\n", + "internationalization plugin" => "\n", + "referential integrity postoperation" => "\n", + "telephone syntax" => "\n", + "uid uniqueness" => "\n" + + ); + +# list of standard indexes configured out of the box in version 4 +%stdIndex = ( + 'aci', "\n", + 'changenumber', "\n", + 'copiedfrom', "\n", + 'dncomp', "\n", + 'entrydn', "\n", + 'numsubordinates', "\n", + 'objectclass', "\n", + 'parentid', "\n" +); + +# list of user added Plugin's. In the new version, they 'll need to be recompiled +@badPlugins = () ; + +%newIndex = () ; + +%User_oc = () ; +# push objectnames as they are encountered in config files. +@User_oc_names = () ; + +%User_at = () ; + + + +#Usage parameters +$USER_OC_FILE_MODIFIED = 0 ; # 0 if user don't want to modify LDIF objectclasses before processing, 1 else +$USER_AT_FILE_MODIFIED = 0 ; +$INDEX_FILE_MODIFIED = 0 ; + +# get the version of the DS to migrate +($oldVersion, $oldMinor) = &getVersion($oldDir, $oldversionstr); +# get the version of the new DS +($Version, $Minor) = &getVersion($root); + +# get old LIB_PATH +$old_libpath = &getLibPath($oldDir, $oldVersion, $oldMinor); +# get new LIB_PATH +$new_libpath = &getLibPath($root, $Version, $Minor); + +# Shutdown the legacy Directory instance +printTrace("\nShutdown the legacy Directory Server instance: ${oldHome}",0); +&stopServer($oldDir, 'slapd-'.$oldname); + +# compare configuration files with the standard ones +CompareStdConfigFiles() ; +die "\n\n The version of the product you want to migrate is not a 4.x Netscape Directory Server\n" unless ($oldVersion == 4) ; + +FillHashParametersName() ; + +############### Connect to the New LDAP Directory Server ###################### +$ENV{"$LIB_PATH"} = $new_libpath; +my $LDAPservername = &getLDAPservername(); +die "\n Migration aborted. Make sure your Old and New Directory Servers are installed on the same machine \n" if ( $LDAPservername == -1 ); +$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n"; + +# continue if the connection to new LDAP server is successful ! +printTrace("\nConnected to $Version.$Minor LDAP server\n",0) ; + +# get the uid and gid of the new slapd user +($localuser, $newuid, $newgid) = getuid_gid(); +# get the uid and gid of the old slapd user +($oldlocaluser, $olduid, $oldgid) = getolduid_gid(); + +# backup new configuration files in <new_root_server>/slapd-instancename/config +printTrace("\nBackup $serverHome${PATHSEP}config on $serverHome${PATHSEP}config_backup ...",0); +&backupConfigFiles(); + +# Parse the main configuration file: slapd.conf +printTrace("\nParse the configuration file: $oldSlapdConf...",0); +ParseSlapdConf("< ${oldSlapdConf}"); + +#migrate key/cert databases +printTrace("\nMigrate key/cert databases...",0); +&MigrateSSL(); + +# Update parameters : general server parameters, global LDBM parameter, specific backend parameters +printTrace("\nUpdate general server parameters...",0); +$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n"; +AddGeneralParameters(); +printTrace("\nUpdate global LDBM parameters...",0); +AddGeneralLDBMParameters(); +printTrace("\nUpdate specific backend parameters...",0); +AddSpecificLDBMParameters(); + +##### FOR TESTING PURPOSE ONLY ######## +# +#testIndexUpdating(); +# +####################################### + +# Migrate some entries contained in the old dse.ldif, and migrate certmap.conf +&MigrateDSE() ; +&MigrateCertmap() ; + +# update new attribute definitions +LDAPmodify_User_at(); + +# update new object classes definitions +LDAPmodify_User_oc(); + +# add new indexes to each backends +LDAPmodify_Indexes(); + +# migrate Plug'ins parameters (enable attribute, and arguments) +LDAPmodify_stdPlugin(); + +################## Close the connection to new LDAP Server ##################### +$conn->close; + + +################## stop the new instance and Export/Import the data, restart the server ################## +if (%DBNAMES) { + &stopServer($root,'slapd-'.$newname); + if ($olddatadir) { + printTrace("\nold data directory $olddatadir...",0) ; + $ldif_rep = "$olddatadir${PATHSEP}"; + } else { + printTrace("\ndata processing...",0) ; + # migrate data for each suffix: old -> LDIF files + &db2ldif($oldSlapdConf); + } + + # migrate LDIF data to the new database: LDIF -> new + &manyLdif2db(); + &startServer(); +} +else { + printTrace("\nThere no old non-standard suffixes to migrate",0); +} + +printMsg("\n\n ****** End of migration ******\n\n"); + +close(LOGFILE); + + +########################################################################################### +# get input users +sub getParameters { + my $exit = 0 ; + my $i = 0; + my $pwdfile= ""; + while ($i <= $#ARGV) { + if ( "$ARGV[$i]" eq "-D" ) { # directory manager + if (! $rootDN) { + $rootDN = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-w") { # password + if (! $rootpwd) { + $rootpwd = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-j") { # password file + if (! $pwdfile) { + $pwdfile = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-o") { # old instance path + if (! $oldHome ) { + $oldHome = $ARGV[++$i] ; + grep { s@\\@/@g } $oldHome if $isNT ; + if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; } + if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) { + $oldDir = $1 ; + $type = $2 ; + $oldname = $3 ; + if ($isNT) { + $oldDir = lc($oldDir) ; + $type = lc($type) ; + $oldname = lc($oldname) ; + $oldHome = lc($oldHome) ; + grep { s@/@\\@g } $oldDir ; + grep { s@/@\\@g } $oldHome ; + } + } + else { + print("\nThe old instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-n") { # new instance path + if (! $serverHome ) { + $serverHome = $ARGV[++$i] ; + grep { s@\\@/@g } $root if $isNT ; + grep { s@\\@/@g } $serverHome if $isNT ; + if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; } + if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) { + $root = $1 if ($1); + $type = $2 ; + $newname = $3 ; + if ($isNT) { + $root = lc($root) ; + $type = lc($type) ; + $newname = lc($newname) ; + $serverHome = lc($serverHome) ; + grep { s@/@\\@g } $root ; + grep { s@/@\\@g } $serverHome ; + } + } + else { + print("\nThe new instance path is not correct. It must be like slapd-instancename"); + &usage(); + exit(1); + } + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-p") { # new DS port + if (! $newport ) { + $newport = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-d") { # old instance LDIF data dir + if (! $olddatadir ) { + $olddatadir = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-v") { # old version + if (! $oldversionstr ) { + $oldversionstr = $ARGV[++$i] ; + } + else { + &usage() ; + exit(1); + } + } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL + my $value = $ARGV[++$i] ; + if ($value =~ /[0-3]/) { + $TRACELEVEL = $value ; + } + else { + print("\nThe tracelevel must belong to 0..3 interval"); + &usage(); + exit(); + } + } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing + $NO_INPUT_USER = 1 ; + } elsif ("$ARGV[$i]" eq "-L") { # migration logfile + $LogFileReport = $ARGV[++$i] ; + } + else { + print("\nThe option $ARGV[$i] is not recognized"); + &usage() ; + exit(1); + } + $i++; + } + if (! $rootDN) { + print("\nThe rootDN is missing"); + $exit = 1; + } + if ($pwdfile ne "") { + # Open file and get the password + unless (open (RPASS, $pwfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $rootpwd = <RPASS>; + chomp($rootpwd); + close(RPASS); + } elsif ($rootpwd eq "-"){ + # Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; + # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $rootpwd = ReadLine(0); +# chomp($rootpwd); +# ReadMode('normal'); + } + if (! $rootpwd) { + print("\nThe rootpwd is missing"); + $exit = 1 ; + } + if (! $newport) { + print("\nThe port is missing"); + $exit = 1; + } + if (! $serverHome) { + print("\nThe new instance path is missing"); + $exit = 1; + } + if (! $oldHome) { + print("\nThe old instance path is missing"); + $exit = 1; + } + if ((! $LogFileReport) && $serverHome) { + ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime(); + $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log"; + } + + if ($exit) { + &usage() ; + exit(1); + } + +} + + +############################################################################### +# This subroutine is used to parse the slapd.conf configuration file and migrate specific parameters contained in it + + +sub ParseSlapdConf { + my $oldsrc = shift; + my $NumLine = 0 ; + # read the old conf file into a hash table + open( OLDSRC, $oldsrc ) || die "Can't open $oldsrc: $!: "; + LINE: while ( <OLDSRC> ) { + $NumLine++ ; + printTrace("\nLine: $_",4) ; + if (/^\s*\#/) { # skip comments + printTrace("\n# ",4) ; + next LINE; + } + if (/^\s*$/) { # skip blank lines + printTrace("\nBLANK LINE",4); + next LINE; + } elsif (/^suffix\s+/i) { + chomp($_) ; + CheckSuffix($_); + } elsif (/^plugin/i) { + printTrace("\nPLUGIN",4); + chomp($_); + if (! &isAStandardPlugin($_)) { + push @badPlugins, $_; + } + else { + my $Plugin = $_ ; + if (! &ParsePlugin($_,$NumLine)) { + printMsg("\nLine $NumLine, syntax error of the plugin:\n$Plugin"); + } + } + } elsif (/^include\s+[\"]?(.*?)[\"]?\s*$/i) { + # strip leading and trailing " + my $include_file = $1 ; + grep { s@/@\\@g } $include_file if $isNT; + if (! &isAStandardInclude($include_file)) { + printTrace("\nFILE: $1 NOT STANDARD",4) ; + &ParseConfigurationFile($include_file); + printTrace("\nEXIT ParseConfigurationFile: $include_file",4) ; + } + } elsif (/^userat\s+[\"]?(.*?)[\"]?\s*$/i) { + printTrace("\nuserat: $1",4); + my $at_file = $1 ; + grep { s@/@\\@g } $at_file if $isNT; + # Parse user defined attributes + &ParseAttributesFile($at_file); + } elsif (/^useroc\s+[\"]?(.*?)[\"]?\s*$/i) { + printTrace("\nuseroc: $1",4); + my $oc_file = $1 ; + grep { s@/@\\@g } $oc_file if $isNT; + # Parse user defined object classes + &ParseObjectClassesFile($oc_file); + } elsif (/^dynamicconf\s+[\"]?(.*?)[\"]?\s*$/i){ + printTrace("\ndynamicconf: $1",4); + my $dynamiconf_file = $1 ; + grep { s@/@\\@g } $dynamiconf_file if $isNT; + # Parse dynamic configuration file (e-g slapd.ldbm.conf) + &ParseConfigurationFile($dynamiconf_file); + } elsif (/^\s*(\S+)\s+[\"]?(.*?)[\"]?\s*$/) { + printTrace("\nParseParameters: $1",4); + # Parse parameters and record the associated value in %oldhash + &ParseParameters($1,$2,$NumLine); + } else { + printTrace("\nUnknown format of configuration data: $_",0); } + } + close(OLDSRC); + + } + + + +############################################################################# +# return 1 if the suffix already exists, 0 else +sub existSuffix { + my $suffixname = shift ; + my $nsuffix = normalizeDN($suffixname); + my $entry = $conn->search("cn=mapping tree,cn=config", "one", "(|(cn=\"$suffixname\")(cn=\"$nsuffix\"))"); + return 1 if ($entry) ; + my $cpt = 5; + my $errorCode = $conn->getErrorCode(); + while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && $cpt && (! $entry)) { + printTrace("\ntry to reconnect to search cn=\"$suffixname\",cn=mapping tree,cn=config", 1); + $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n"; + $entry = $conn->search("cn=mapping tree,cn=config", "one", "(|(cn=\"$suffixname\")(cn=\"$nsuffix\"))"); + $errorCode = $conn->getErrorCode(); + $cpt--; + } + return 1 if ($entry) ; + return 0 ; +} + +# return the name of the backend if it has been successfully created, 0 else +sub createBackend { + my $suffixname = shift ; + my $backend = "MigratedDB_0" ; + my $NbRetry = 1 ; + my $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ; + while ($entry) { + # try to find another name for the backend + $backend = "MigratedDB_$NbRetry" ; + $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ; + $NbRetry++; + } + # normally I should have a unique name for the backend + my $suffixarg = "nsslapd-suffix" ; + $entry = $conn->newEntry() ; + $entry->setDN("cn=$backend,cn=ldbm database,cn=plugins,cn=config"); + $entry->setValues("objectclass", "top", "extensibleObject", "nsBackendInstance" ); + $entry->setValues("cn", $backend ); + $entry->setValues($suffixarg, $suffixname ); + my $res = $conn->add($entry) ; + if ($res) { + return $backend ; + } + else { + return 0 ; + } +} + +# return 1, if add the new entry in the mapping tree, else 0 +sub AddEntryInMappingTree { + my $backend = shift ; + my $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ; + if ($entry) { + printTrace("\nAddEntry in progress ...",4) ; + my $suffixarg = "nsslapd-suffix" ; + my $statearg = "nsslapd-state" ; + my $backendarg= "nsslapd-backend"; + my $suffixname = $entry->{$suffixarg}[0]; + $entry = $conn->newEntry() ; + $entry->setDN("cn=\"$suffixname\",cn=mapping tree,cn=config") ; + $entry->setValues("objectclass", "top", "extensibleObject", "nsMappingTree" ); + $entry->setValues("cn", "\"$suffixname\""); + $entry->setValues($statearg, "backend"); + $entry->setValues($backendarg, $backend); + return $conn->add($entry); + } + else { + printTrace("\nNo AddEntry processed for $backend",4); + return 0 ; + } +} + + +# Treat the case where the suffix is "o=NetscapeRoot" +sub CheckSuffix { + my $suffix = shift ; + my $suffixname ; + my $expLdif; + my $confirm = "No"; + my $dest = "$serverHome${PATHSEP}db_backup" ; + my $newSlapdExecDir = "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server"; + + if (!(/^suffix\s+\"?(.*?)\"?\s*$/i)) { + printMsg("Syntax error of the suffix: $suffix"); + return 0 ; + } + else { + $suffixname = $1 ; + } + if (/^suffix\s+\"?\s*o=netscaperoot\s*\"?\s*$/i) { + printTrace("\nFor the suffix o=NetscapeRoot, we do nothing",1); + # treat the case where the suffix is "o=NetscapeRoot" + } + else { + push @oldSuffixes, $_; + # check if the suffix already exists in the new DS target + if (! existSuffix($suffixname)) { + printTrace("\n\nSuffix $suffixname doesn't exist",1) ; + # create a new backend with the name of the suffix preceded by MigratedDB_ + my $backend = createBackend($suffixname) ; + if ($backend) { + printTrace("\nBackend: $backend has been created !!!",1); + # if the creation of the backend is ok, we add a new entry in the mapping tree + if (AddEntryInMappingTree($backend)) { + # We add the association dbname->suffix in the hash %DBNAMES + $DBNAMES{$suffixname} = $backend ; + # get the db filename + $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ; + my $dirarg = "nsslapd-directory"; + $DBDirectory{$backend} = $entry->{$dirarg}[0]; + printTrace("\nThe relation $backend->$suffixname has been added to the mapping tree",2); + } + else { + printMsg("\nCOULD NOT ADD ENTRY: $backend->$suffixname IN MAPPINGTREE"); + } + } + else { + printMsg("\nCOULD NOT CREATE BACKEND: $backend"); + } + } + else { + printMsg("\n\nSuffix: $suffixname already exists"); + # the suffix already exists in the new DS + printMsg("\nMigration will overwrite existing database"); + printMsg("\nDo you want to continue Yes/No [No] ?") ; + my $answer = <STDIN> ; + if ($answer =~ /y|yes/i) { + my $nsuffix = normalizeDN($suffixname); + my $my_entry = $conn->search("cn=mapping tree,cn=config", "one", "(|(cn=\"$suffixname\")(cn=\"$nsuffix\"))"); + my $backend = $my_entry->{"nsslapd-backend"}[0]; + my $backend_entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ; + printMsg("Do you want to export the existing data Yes/No [Yes] ?"); + my $answer = <STDIN> ; + if (!($answer =~ /n|no/i)) { + mkdir $dest, 0700 unless (-d $dest); + $expLdif = "$dest${PATHSEP}$backend.ldif"; + while (!($confirm =~ /y|yes/i)) { + printMsg("\nEnter the full pathname of the file [$expLdif]:") ; + $answer = <STDIN> ; + chomp($expLdif = $answer) unless ($answer eq "\n"); + printMsg("\nExisting data will be exported under $expLdif"); + printMsg("\nContinue Yes/No [No] ?"); + $confirm = <STDIN>; + } + $ENV{"$LIB_PATH"}=$new_libpath; + chdir($newSlapdExecDir) or die "\nCould not change directory to $newSlapdExecDir: $!\n"; + printTrace("\nNow backing up database $CN in $expLdif\n",0); + &stopServer($root,'slapd-'.$newname); + &newinst_db2ldif($expLdif, $suffixname, $serverHome); + &startServer(); + } + # We add the association dbname->suffix in the hash %DBNAMES + $DBNAMES{$suffixname} = $backend ; + my $dirarg = "nsslapd-directory"; + $DBDirectory{$backend} = $backend_entry->{$dirarg}[0]; + printTrace("\nThe relation $backend->$suffixname has been added to the mapping tree",2); + } + } + return 1 ; +} +} + +############################################################################# +# Usefull to know the standard configuration +sub isAStandardPlugin { + my $line = shift; + chomp($line); + printTrace("\nStdPlugin?: $line",4); + if ($line =~ /^plugin\s+(database|extendop|preoperation|postoperation|matchingrule|syntax)\s+(on|off)\s+\"(.*?)\"\s+\"(.*?)\"\s+(\S+)(.*)$/i) { + # $1 = <type>, $2 = <on|off>, $3 = <name>, $4 = <pathname>, $5 = <init_function>, $6 = [<arg>]* + printTrace("\nName: $3, pathname: $4, init_function: $5",4); + + my $LC_line = lc($3); + my $Value = $stdPlugins{$LC_line} ; + if ($Value) { + printTrace("\nIS A STANDARD PLUGIN",4); + } + else { + printTrace("\nNOT A STANDARD PLUGIN",4); + } + return $stdPlugins{$LC_line} ; + } + else { + printTrace("\nSYNTAX ERROR PLUGIN",4); + return 0 ; + } +} + +sub isAStandardIndex { + my $line = shift ; + chomp($line); + if ($line =~ /^index\s+(\S+).*/i) { + my $LC_line = lc($1); + my $Value = $stdIndex{$LC_line} ; + printTrace("\nInclude: $LC_line \nValue: $Value", 4); + return $stdIndex{$LC_line}; + } + else { + return 0 ; + } +} + + +sub isAStandardInclude { + my $line = shift; + + chomp($line); + if ($isNT){ + return $stdIncludes{lc($line)}; + } + else { + return $stdIncludes{$line} ; + } +} + +############################################################################# +# +# Execute a Perldap command to update plugins definition in the new schema + +sub LDAPmodify_stdPlugin { + my $Filename = shift ; + my @pluginames = keys(%stdPlugins); + if (! $STDPLUGINS_FILE_MODIFIED) { + printTrace("\nLDAPmodify_plugin",4); + printTrace("\nMigrate plugin's...",1); + foreach $pluginame ( @pluginames ) { + my $update_plugin = 0 ; + my $ref_plugin = $stdPlugins{$pluginame}; + if ($ref_plugin ne "\n") { + my $name = $ref_plugin->name ; + # We have a name change of "uid uniqueness plugin" in DS7.0 + # to "attribute uniqueness" + $name = "attribute uniqueness" if ($name eq "uid uniqueness"); + my $entry = $conn->search("cn=$name,cn=plugins,cn=config", "base","objectclass=nsSlapdPlugin") ; + if ($entry) { + my $pluginenabled="nsslapd-pluginenabled" ; + if (($entry->{$pluginenabled}[0]) ne $ref_plugin->enable) { + $update_plugin = 1 ; + my $enable = $ref_plugin->enable ; + printTrace("\n$pluginame, plugin-enable: $enable",3) ; + $entry->setValues($pluginenabled, $enable ); + } + my $ArgNum = 0 ; + foreach $ArgValue (@{$ref_plugin->args}) { + my $Arg="nsslapd-pluginarg$ArgNum"; + printTrace("\n$Arg: $ArgValue",3) ; + if ($entry->{$Arg}[0] ne $ArgValue) { + printTrace("\n$pluginame, $Arg: $ArgValue",3) ; + $update_plugin = 1 ; + $entry->setValues($Arg, $ArgValue) ; + } + $ArgNum++ ; + } + if ($update_plugin) { + printTrace("\n$pluginame is being updated...",2); + my $res = $conn->update($entry) ; + if ($res) { + printTrace("\nupdated !",2); + } + else { + printMsg("\nError during update of plugin: $pluginame") ; + $MigrationErrors .= "\nError during update of plugin: $pluginame"; + } + } + else { + printTrace("\n$pluginame has not changed",4); + } + } + else { + printMsg("\ncan't access the plugin: cn=$name,cn=plugins,cn=config"); + } + } + else { + printTrace("\nPLUGIN NOT RECORDED: $pluginame",4) ; + } + } + } + else { + # treat the case where the user wants to look at these plugins before processing + } +} + +############################################################################# +# Execute Perldap command to add new indexes to the migrated instances + +sub LDAPmodify_Indexes { + my $Filename = shift ; + my @indexnames = keys(%newIndex); + my @suffixnames = keys(%DBNAMES); + if ((! $INDEX_FILE_MODIFIED) && (%DBNAMES)) { + # we update indexes only if there is at least one backend to migrate + printTrace("\nLDAPmodify_indexes",4); + printTrace("\nMigrate indexes...",1); + foreach $indexname ( @indexnames ) { + printTrace("\nIndexName: $indexname",4); + printTrace("\nIndexTypes: .@{$newIndex{$indexname}->types}.", 4) ; + printTrace("\nIndexOIDS: .@{$newIndex{$indexname}->oids}.", 4) ; + foreach $suffixname ( @suffixnames ) { + # check if the index already exists ! + printTrace("\nsearch for cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...", 3); + my $entry = $conn->search("cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex"); + if (! $entry) { + # create a new index + printTrace("index $indexname is being created under cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...",2); + my $entry = $conn->newEntry(); + $entry->setDN("cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config"); + $entry->setValues("objectclass", "top", "nsIndex" ) ; + $entry->setValues("cn", $indexname) ; + $entry->setValues("nssystemindex", "false") ; + my @types = @{$newIndex{$indexname}->types} ; + my @oids = @{$newIndex{$indexname}->oids} ; + $entry->setValues("nsindextype", @types) if (@types) ; + $entry->setValues("nsmatchingrule", @oids ) if (@oids); + my $res = $conn->add($entry) ; + if ($res) { + printTrace("\nAdd index successfully: $indexname for backend: $DBNAMES{$suffixname}",2); + } + else { + printMsg("\n Failed to add the index: $indexname to backend: $DBNAMES{$suffixname}"); + $MigrationErrors .= "\n Failed to add the index: $indexname to backend: $DBNAMES{$suffixname}" ; + } + } + elsif ($entry->{nssystemindex}[0] eq "false") { + # if the index is not a system index, we update it + printTrace("\nindex $indexname is being processed under cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...",2); + my @types = @{$newIndex{$indexname}->types} ; printTrace("\ntypes: .@types.",2) ; + my @oids = @{$newIndex{$indexname}->oids} ; printTrace("\noids: .@oids.",2) ; + my @existing_types = $entry->getValues("nsindextype"); + my @existing_oids = $entry->getValues("nsmatchingrule"); + # get the elements present in @types and not present in @existing_types + my @typesToAdd = &getDiff(\@types, \@existing_types); + # same for matchingrules + my @oidsToAdd = &getDiff(\@oids, \@existing_oids); + foreach $newtype (@typesToAdd) { + $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2); + } + foreach $newoid (@oidsToAdd) { + $entry->addValue("nsmatchingrule", $newoid); + } + if (@typesToAdd || @oidsToAdd) { + my $res = $conn->update($entry) ; + if ($res) { + printTrace("\nUpdate index successfully: $indexname for backend: $DBNAMES{$suffixname}",2); + } + else { + printMsg("\n Failed to update the index: $indexname to backend: $DBNAMES{$suffixname}"); + $MigrationErrors .= "\n Failed to update the index: $indexname to backend: $DBNAMES{$suffixname}" ; + } + } + else { + printTrace("\nNothing to update",2); + } + } + else { + printTrace("\nThe index: $indexname is a system index. It can't be updated",2); + } + } + } + + } + else { + # treat the case where the user wants to look at these indexes before processing + } + +} + +############################################################################# +# +# Execute a Perldap command to add all user defined object classes in the new schema + +sub LDAPmodify_User_oc { + my $Filename = shift ; + if (! $USER_OC_FILE_MODIFIED) { + printTrace("\nLDAPmodify_User_oc",4); + printTrace("\nMigrate objectclasses...",1); + foreach $objectname ( @User_oc_names ) { + my $entry = $conn->search("cn=schema", "base","objectclass=*") ; + die "\ncan't connect to object: cn=schema\n" unless ($entry); + printTrace("\nObjectName: $objectname\nValue: $User_oc{$objectname}",3); + next if ($entry->hasValue("objectclasses",$User_oc{$objectname},1)) ; + $entry->addValue("objectclasses",$User_oc{$objectname},"1") ; + my $res = $conn->update($entry) ; + my $err = $conn->getErrorCode(); + if ($res) { + printTrace("\nobjectclass: $User_oc{$objectname} added",2); + } elsif ($err == 20) { # already exists + printTrace("\nobjectclass: $User_oc{$objectname} already exists",1); + } else { + printMsg("\nCan\'t add objectclass to the schema: $User_oc{$objectname}"); + my $msg = $conn->getErrorString(); + printMsg("\nMsg: $msg"); + $MigrationErrors .= "\nCan\'t add objectclass to the schema: $User_oc{$objectname}" ; + } + } + } + else { + # treat the case where the user wants to look at these objectclasses before processing + } +} + +############################################################################# +# +# Execute a Perldap command to add all user defined attributes in the new schema + +sub LDAPmodify_User_at { + my $Filename = shift ; + my @attributenames = keys(%User_at); + if (! $USER_AT_FILE_MODIFIED) { + + printTrace("\nLDAPmodify_User_at",4); + printTrace("\nMigrate attributes...",1); + foreach $attributename ( @attributenames ) { + my $entry = $conn->search("cn=schema", "base","objectclass=*") ; + printTrace("\nAtributeName: $attributename, Value: $User_at{$attributename}",3); + die "\nentry not found cn=schema\n" unless $entry ; + next if ($entry->hasValue("attributetypes",$User_at{$attributename},1) ) ; + my $res = $entry->addValue("attributetypes",$User_at{$attributename},"1") ; + if (! $res) { + printMsg("\nCan\'t add attribute to the schema: $User_at{$attributename}"); + $MigrationErrors .= "\nCan\'t add attribute to the schema: $User_at{$attributename}" ; + } + my $res = $conn->update($entry) ; + my $err = $conn->getErrorCode(); + if ($res) { + printTrace("\nattribute: $attributename added",2); + } elsif ($err == 20) { # already exists + printTrace("\nattribute: $attributename already exists",1); + } + else { + printMsg("\nCan\'t add attribute to the schema: $User_at{$attributename}"); + my $msg = $conn->getErrorString(); + printMsg("\nMsg: $msg"); + $MigrationErrors .= "\nCan\'t add attribute to the schema: $User_at{$attributename}" ; + } + } + } + else { + # treat the case where the user wants to look at these attributes before processing + } +} + +############################################################################# +# Add an object class to the user_oc hash and reset the object !!! +sub AddObjectClass { + my $ObjectClass = shift ; + my $ObjectName = $ObjectClass->{'ObjectName'} ; + my $Object_oid = $ObjectClass->{'Object_oid'} ; + my $Object_superior = $ObjectClass->{'Object_superior'} ; + my $Object_requires = $ObjectClass->{'Object_requires'} ; + my $Object_allows = $ObjectClass->{'Object_allows'} ; + my $ObjectClassDef = "( $Object_oid NAME \'$ObjectName\' DESC \'\' SUP $Object_superior STRUCTURAL MUST ($Object_requires) MAY ($Object_allows) X-ORIGIN \'user defined\' )"; + if ( (!($ObjectName =~ /^top$/i)) && ( ! $User_oc{$ObjectName} )) { + $User_oc{$ObjectName} = $ObjectClassDef ; + push @User_oc_names, $ObjectName ; + printTrace("ObjectName: $ObjectName \nObject_oid: $Object_oid \nObject_superior:$Object_superior \nObject_requires: $Object_requires \nObject_allows: $Object_allows \nObjectClassDefinition: $User_oc{$ObjectName}\n",4); + } + elsif ( ($User_oc{$ObjectName}) && ($User_oc{$ObjectName} ne $ObjectClassDef) ) { + printMsg("\nAttempt to redifine the objectclass: $ObjectName previously defined in your configuration file. Operation not allowed "); + } + else { + printMsg("\nAttempt to redifine the objectclass: top. Operation not allowed"); + } + resetObjectClass($ObjectClass); +} + +############################################################################# +# Build an LDIF attribute and add it to the user_at hash +sub AddAttribute { + my $Attr = shift ; + my $AttributeName = $Attr->{'AttributeName'}; + my $Attribute_oid = $Attr->{'Attribute_oid'}; + my $Attribute_aliases = $Attr->{'Attribute_aliases'}; + my $Attribute_syntax = $Attr->{'Attribute_syntax'}; + my $Attribute_single = $Attr->{'Attribute_single'}; + my $AttributeDef = "( $Attribute_oid NAME ( \'$AttributeName\' $Attribute_aliases) DESC \'User Defined Attribute\' SYNTAX $Attribute_syntax $Attribute_single X-ORIGIN 'user defined' )" ; + printTrace("\nAttributeDef: $AttributeDef",4); + $User_at{$AttributeName} = $AttributeDef ; +} +############################################################################# +# add the index structure to the newIndex hash +sub AddIndex { + my $ref_index = shift ; + my $state = shift ; + printTrace("\nAddIndex, last state: $state",4) ; + if ($state == 1) { + $ref_index->specific("ALL") ; + return 1 ; + } + elsif ($state == 6) { + $ref_index->specific("NONE") ; + return 1 ; + } + if (($state == 1) || ($state == 3) || ($state == 5) || ($state == 6)) { + foreach $name (@{$ref_index->names}) { + $newIndex{$name} = $ref_index ; # record the ref to the index struct in the newIndex hash + } + return 1 ; + } + else { + return 0 ; + } +} + +############################################################################# +# add the plugin structure to the stdPlugin hash + +sub AddPlugin { + my $ref_plugin = shift ; + printTrace("\nAddPlugin",4) ; + $stdPlugins{lc($ref_plugin->name)} = $ref_plugin ; + my $name = $ref_plugin->name ; + my $type = $ref_plugin->type ; + my $enable = $ref_plugin->enable ; + + printTrace("\nPluginName: $name",4); + printTrace("\nPluginType: $type",4); + printTrace("\nPluginEnable: $enable",4); + printTrace("\nPluginArgs: @{$ref_plugin->args}",4); + return 1 ; +} + + +############################################################################# +# parse a plugin definition and call the addindex + +sub ParsePlugin { + my $Plugin = shift ; + my $NumLine = shift ; + my $state = 0 ; + my $ErrorMsg = "Syntax error of a plugin definition. \n line parsed:"; + my $ref_plugin = S_plugin->new(); + printTrace("\nParsePlugin: $_",4); + if (/^plugin\s+(database|extendop|preoperation|postoperation|matchingrule|syntax)\s+(on|off)\s+\"(.*?)\"\s+\"(.*?)\"\s+(\S+)(.*)$/i) { + # $1 = <type>, $2 = <on|off>, $3 = <name>, $4 = <pathname>, $5 = <init_function>, $6 = [<arg>]* + $ref_plugin->name($3); + $ref_plugin->type($1); + $ref_plugin->enable($2); + $_ = $6 ; + my $ArgNb = 0 ; + my $prec ; + my $arg ; + my $Unix_oldDir = $oldDir ; + my $Unix_root = $root ; + grep { s@\\@/@g } $Unix_oldDir if $isNT; + grep { s@\\@/@g } $Unix_root if $isNT; + while (!(/^\s*$/)) { + if (/^\s*\".*?\"/) { + s/^\s*\"(.*?)\"(.*)/$2/i ; + $arg = $1 ; + } + elsif (/^\s*[^\"\s]+/) { + s/^\s*([^\"\s]+)(.*)/$2/i ; + $arg = $1 ; + } + $prec = $_ ; + $_ = $arg ; + + s@$Unix_oldDir@$Unix_root@ig ; + s/$type-$oldname/$type-$newname/ig ; + @{$ref_plugin->args}[$ArgNb++] = $_ ; + $_ = $prec ; + } + if (/^\s*$/) { + return AddPlugin($ref_plugin); + } + else { + return 0 ; + } + } + return 0 ; +} + +############################################################################# +# parse an index definition and call the addindex + +sub ParseIndex { + my $index = shift ; + my $NumLine = shift ; + my $ref_index = S_index->new() ; + my $Value ; + my $state = 0 ; + my $ErrorMsg = "Syntax error of an index definition.\nline parsed:"; + printTrace("\nParseIndex: $_",4) ; + s/,/, /g ; + s/\s+,/,/g ; + s/^index\s+//i ; # substitute the token index + while (!(/^\s*$/)) { + s/^\s*(\S+)(.*)$/$2/ ; + $Value = $1 ; + printTrace("\nValue: $Value",4); + printTrace("\nState: $state",4) ; + SWITCH: { + if ($state == 0) { + if ($Value =~ /[^\.]/) { + if ($Value =~ /(\S+),$/) { + push @{$ref_index->names}, $1 ; + } + else { + $state = 1 ; + push @{$ref_index->names}, $Value ; + } + } + else { + return 0 ; + } + last SWITCH ; + } + if ($state == 1) { + if ($Value =~ /^none$/i) { + $state = 6 ; # end of the index definition + } + elsif ($Value =~ /^\"\"$/) { + $state = 4 ; # we expect to have at least one OID + } + elsif ($Value =~ /(\S+),$/) { + $state = 2 ; + push @{$ref_index->types}, $1 ; + } + else { + $state = 3 ; + push @{$ref_index->types}, $Value ; + } + last SWITCH ; + } + if ($state == 2) { + if ($Value =~ /(\S+),$/) { + push @{$ref_index->types}, $1 ; + } + else { + $state = 3 ; + push @{$ref_index->types}, $Value ; + } + last SWITCH ; + } + if ($state == 3) { + if ($Value =~ /(\S+),$/) { + $state = 4 ; + push @{$ref_index->oids}, $1 ; + } + else { + $state = 5 ; + push @{$ref_index->oids}, $Value ; + } + last SWITCH ; + } + if ($state == 4) { + if ($Value =~ /(\S+),$/) { + push @{$ref_index->oids}, $1 ; + } + else { + $state = 5 ; + push @{$ref_index->oids}, $Value ; + } + last SWITCH ; + } + } + } +return AddIndex($ref_index,$state) ; + +} + +############################################################################# + +sub ParseAttribute { + + + my $Attr = shift ; + my $NumLine = shift ; + my $state = 1 ; + my $ErrorMsg = "Syntax error of an attribute definition.\nline parsed:"; + my %Attribute = ( + 'AttributeName' => "", + 'Attribute_oid' => "", + 'Attribute_aliases' => "", + 'Attribute_syntax' => "", + 'Attribute_single' => "" + ); + my $AttributeName = " "; + printTrace("\nParseAttribute",4); + while (!(/^\s*$/)) { + s/^(.*?)(\S+)\s*$/$1/ ; + printTrace("\nValue: $2",4); + printTrace("\nState: $state",4) ; + my $Value = $2 ; + SWITCH: { + if ($state == 1) { + if (isAllowedModifier($Value)) { + $state = 1 ; + $modifier = lc($Value); + $AttrVar = 'Attribute_' . $modifier ; + $Attribute{$AttrVar} = &getModifierValue($Value) ; + } + elsif (&isAllowedPlugin($Value)) { + $state = 2 ; + $Attribute{'Attribute_syntax'} = &getSyntaxOid($Value) ; + } + else { + return 0 ; + } + last SWITCH ; + } + if ($state == 2) { + if ($Value =~ /[\.]|-oid$/) { + $Attribute{'Attribute_oid'} = "$Value" ; + printTrace("\nAttribute-oid: $Attribute{'Attribute_oid'}",3); + $state = 3 ; + } + elsif ($Value =~ /[^\.]/) { + $AttributeName = $Attribute{'AttributeName'} ; + if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;} + $Attribute{'AttributeName'} = $Value ; + $state = 4 ; + } + else { + return 0 ; + } + last SWITCH ; + } + if ($state == 3) { + if ($Value =~ /[^\.]/) { + $AttributeName = $Attribute{'AttributeName'} ; + if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;} + $Attribute{'AttributeName'} = $Value ; + $state = 4 ; } + else { + return 0 ; + } + last SWITCH ; + } + if ($state == 4) { + if ($Value =~/^attribute$/i){ + $state = 5; + } + elsif ($Value =~/[^\.]/i) { + $AttributeName = $Attribute{'AttributeName'} ; + if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;} + $Attribute{'AttributeName'} = $Value ; + } + else { + return 0 ; + } + last SWITCH ; + } + if ($state == 5) { + return 0 ; + last SWITCH ; + } + } + } + $Attribute{'Attribute_oid'} = $Attribute{'AttributeName'} . '-oid' unless ($Attribute{'Attribute_oid'}) ; + return AddAttribute(\%Attribute) ; +} + + +############################################################################# +# fill in the hash HashParametersName + +sub FillHashParametersName { + my @paramnames = ( keys(%GeneralSrvParamToMigrate), keys(%GlobalConfigLDBMparamToMigrate), keys(%LDBMparamToMigrate)); + foreach $param (@paramnames) { + $HashParametersName{$param} = '\n'; + } +} + + +# Parse parameters +sub ParseParameters { + my $param = shift ; + my $value = shift ; + my $NumLine = shift ; + my $ErrorMsg = "parameter unknown, or not to be migrated: "; + if ($HashParametersName{lc($param)} && ($value !~ /^\s*$/)) { + $HashParametersName{lc($param)} = $value ; + printTrace("\nParam: $param is present",4); + } + else { + printTrace("\n$NumLine, $ErrorMsg,$param",4); + } + +} + +# add general server parameters +sub AddGeneralParameters { + my @paramnames = keys(%GeneralSrvParamToMigrate); + my $entry = $conn->search("cn=config","base","objectclass=*"); + die "\ncan't access to object: cn=config. \nMigration stopped\n" unless ($entry); + printTrace("\nAddGeneralParameters",4); + foreach $param (@paramnames) { + my $LDAPparam = $GeneralSrvParamToMigrate{$param} ; + my $Value = $HashParametersName{$param} ; + if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) { + printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4); + $entry->setValues($LDAPparam, $Value); + my $res = $conn->update($entry); + if ($res) { + printTrace("\nUpdate successfully $LDAPparam ",0); + } + else { + printMsg("\nCan't update parameter: $LDAPparam"); + } + } + } +} + + +# add general LDBM parameters +sub AddGeneralLDBMParameters { + my @paramnames = keys(%GlobalConfigLDBMparamToMigrate); + my $entry = $conn->search("cn=config,cn=ldbm database,cn=plugins,cn=config","base","objectclass=*"); + die "\ncan't access to object: cn=config,cn=ldbm database,cn=plugins,cn=config. \nMigration stopped\n" unless ($entry); + printTrace("\nAddGeneralLDBMParameters",4); + foreach $param (@paramnames) { + my $LDAPparam = $GlobalConfigLDBMparamToMigrate{$param} ; + my $Value = $HashParametersName{$param} ; + if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) { + printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4); + $entry->setValues($LDAPparam, $Value); + my $res = $conn->update($entry); + if ($res) { + printTrace("\nUpdate successfully $LDAPparam ",0); + } + else { + printMsg("\nCan't update parameter: $LDAPparam"); + } + } + } +} + +# add specific LDBM parameters +sub AddSpecificLDBMParameters { + my @paramnames = keys(%LDBMparamToMigrate); + my %REV_DBNAMES = reverse %DBNAMES ; + my @dbnames = keys(%REV_DBNAMES); + printTrace("\nAddSpecificLDBMParameters",4); + foreach $dbname (@dbnames) { + my $entry = $conn->search("cn=$dbname,cn=ldbm database,cn=plugins,cn=config","base","objectclass=*"); + die "\ncan't access to object: cn=$dbname,cn=ldbm database,cn=plugins,cn=config. \nMigration stopped\n" unless ($entry); + foreach $param (@paramnames) { + my $LDAPparam = $LDBMparamToMigrate{$param} ; + my $Value = $HashParametersName{$param} ; + if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) { + printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4); + $entry->setValues($LDAPparam, $Value); + my $res = $conn->update($entry); + if ($res) { + printTrace("\nUpdate successfully $LDAPparam",2); + } + else { + printMsg("\nCan't update parameter: $LDAPparam"); + } + } + } + } +} + +############################################################################# +# Parse a configuration file potentialy tuned by the user (different from slapd.user_oc.conf and slapd.user_at.conf) + +sub ParseConfigurationFile { + + my $FileToParse = shift; + my $NumLine = 0; + my $PARSE_OBJECTCLASSES = 0 ; # 1 if there are objectclass definitions in the file + printTrace("\nParseConfigurationFile: $FileToParse",4) ; + printTrace("\nParse $FileToParse",2); + # read each line of the configuration file + my $CONFIGFILE = "CONFIGFILE.$FileToParse" ; + open( $CONFIGFILE, $FileToParse ) || die "Can't open $FileToParsec: $!: "; + LINE: while ( <$CONFIGFILE> ) { + $NumLine++ ; + if (/^\s*\#/) { # skip comments + next LINE; + } + if (/^\s*$/) { # skip blank lines + next LINE; + } elsif (/^suffix\s+/i) { + chomp($_) ; + CheckSuffix($_) ; + } elsif (/^plugin/i) { + chomp($_); + if (! &isAStandardPlugin($_)) { + push @badPlugins, $_; + } + else { + my $Plugin = $_ ; + if (! &ParsePlugin($_,$NumLine)) { + printMsg("\nLine $NumLine, syntax error of the plugin:\n$Plugin"); + } + } + } elsif (/^index/i) { + chomp($_); + if (! &isAStandardIndex($_)) { + my $Index = $_ ; + if (! &ParseIndex($_,$NumLine)) { + printMsg("\nLine $NumLine, syntax error of index:\n$Index"); + } + } + } elsif (/^include\s+[\"]?(.*?)[\"]?\s*$/i) { + # strip leading and trailing " + my $include_file = $1 ; + grep { s@/@\\@g } $include_file if $isNT; + if (! &isAStandardInclude($include_file)) { + &ParseConfigurationFile($include_file); + } + } elsif (/^attribute\s+\S+/i) { + chomp($_); + my $Attrib = $_ ; + if (! &ParseAttribute($_,$NumLine)) { + printMsg("\nLine $NumLine, syntax error of attribute:\n$Attrib"); + } + } elsif (/^objectclass\s+(\S+)\s*$/i) { + # At least one objectclass is present in the file + $PARSE_OBJECTCLASSES = 1; + } elsif (/^\s*(\S+)\s+[\"]?(.*?)[\"]?\s*$/) { + # Parse parameters and record the associated value in %Oldhash + &ParseParameters($1,$2,$NumLine); + } + } + close($CONFIGFILE); + ParseObjectClassesFile($FileToParse) if ($PARSE_OBJECTCLASSES); # parse objectclass definition + +} + +############################################################################# +# Parse the file specified in the userat attribute + +sub ParseAttributesFile { + my $userat_file=shift ; + my $NumLine = 0; + printTrace("\nParseAttributesFile: $userat_file",4); + printTrace("\nParse user defined attributes file: $userat_file",2); + # read each line of the configuration file + open( ATTRFILE, $userat_file ) || die "Can't open $FileToParsec: $!: "; + LINE: while ( <ATTRFILE> ) { + $NumLine++ ; + if (/^\s*\#/) { # skip comments + next LINE; + } + if (/^\s*$/) { # skip blank lines + next LINE; + } elsif (/^attribute\s+\S+/i) { + chomp($_); + my $Attrib = $_ ; + if (! &ParseAttribute($_, $NumLine)) { + printMsg("\nLine $NumLine, syntax error of attribute:\n$Attrib"); + } + } + } + close(ATTRFILE); +} + +############################################################################# +# Parse the file specified in the useroc token + +sub ParseObjectClassesFile { + my $useroc_file = shift ; + my %ObjectClass = ( + 'ObjectName' => " ", + 'Object_oid' => " ", + 'Object_superior' => "top", + 'Object_requires' => " ", + 'Object_allows' => " " + ); + + my $state = 0; + my $ErrorMsg = "Syntax error of an object class definition.\nline parsed:"; + my $LineNb = 0 ; # Number of the current line parsed in the file + printTrace("ParseObjectClassesFile: $useroc_file\n",4) ; + # read each line of the configuration file + open( OBJCLASSFILE, $useroc_file ) || die "Can't open $FileToParsec: $!: "; + printTrace("Begin the parsing of the file: $useroc_file",4); + LINE: while ( <OBJCLASSFILE> ) { + printTrace("Current Line: $_",4); + $LineNb++ ; + if (/^\s*\#/) { # skip comments + next LINE; + } + if (/^\s*$/) { # skip blank lines + next LINE; + } + SWITCH: { + if ($state == 0) { resetObjectClass(\%ObjectClass); + if (/^objectclass\s+(\S+)\s*$/i) { + $ObjectClass{'ObjectName'} = $1; + $state = 1 ;} + else {} # printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 1) {if (/^\s+oid\s+(\S+)\s*$/i) { + $ObjectClass{'Object_oid'} = $1; + $state = 2 ;} + elsif (/^\s+superior\s+(\S+)\s*$/i) { + $ObjectClass{'Object_superior'} = $1; + $state = 3 ; + } + elsif (/^\s+requires\s*$/i) { + $state = 4; + } + elsif (/^\s+allows\s*$/i) { + $state = 5; + } + else {$state=0; printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 2) {if (/^\s+superior\s+(\S+)\s*$/i) { + $ObjectClass{'Object_superior'} = $1; + $state = 3 ;} + elsif (/^\s+requires\s*$/i) { + $state = 4; + } + elsif (/^\s+allows\s*$/i) { + $state = 5; + } + else { $state=0; printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 3) {if (/^\s+requires\s*$/i) + { $state = 4; } + elsif (/^objectclass\s+(\S+)\s*$/i) { + # run an ldap add before to continue + &AddObjectClass(\%ObjectClass); + $ObjectClass{'ObjectName'} = $1; + $state = 1 ;} + elsif (/^\s+allows\s*$/i) + { $state = 5; } + else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 4) {if (/^\s+([^,\s]+),\s*$/i) { + $ObjectClass{'Object_requires'}.=$1." \$ "; } + elsif (/^\s+([^,\s]+)\s*$/i) { + $ObjectClass{'Object_requires'}.=$1." "; + $state = 6; } + else {$state = 0;printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 5) {if (/^\s+([^,\s]+),\s*$/i) { + $ObjectClass{'Object_allows'}.=$1." \$ "; } + elsif (/^\s+([^,\s]+)\s*$/i) { + $ObjectClass{'Object_allows'}.=$1." "; + # run an ldap add before to continue + &AddObjectClass(\%ObjectClass); + $state = 0; } + else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + if ($state == 6) {if (/^objectclass\s+(\S+)\s*$/i) { + # run an ldap add before to continue + &AddObjectClass(\%ObjectClass); + $ObjectClass{'ObjectName'} = $1; + $state = 1 ;} + elsif (/^\s+allows\s*$/i) { + $state = 5;} + else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);} + last SWITCH;} + } + } + close(OBJCLASSFILE); + if (($state == 3) || ($state == 4) || ($state == 5) || ($state == 6)) { + &AddObjectClass(\%ObjectClass); + } + printTrace("state: $state",4); +} + +############################################################################# +# printMsg print message to the user standard output. + +sub printMsg { + + my $TypeMsg = shift ; + my $Msg = shift ; + my $LineNb = shift ; + if ($LineNb) { + printTrace("Line: $LineNb, $TypeMsg, $Msg"); + } + else { + printTrace("$TypeMsg $Msg"); + } +} + +############################################################################# +# print message error to the user standard output. + +sub printTrace { + + my $Msg = shift ; + my $level = shift ; + if ($level <= $TRACELEVEL) { + print($Msg); + print LOGFILE $Msg ; + } +} + +############################################################################# +# reset an objectclass structure + +sub resetObjectClass { + my $ObjectClass = shift; + $ObjectClass->{'ObjectName'} = " " ; + $ObjectClass->{'Object_oid'} = " " ; + $ObjectClass->{'Object_superior'} = "top" ; + $ObjectClass->{'Object_requires'} = " " ; + $ObjectClass->{'Object_allows'} = " " ; +} + +############################################################################# +# this subroutine implements a very stupid version of diff + +sub diff { + my $f1 = shift; + my $f2 = shift; + my $lineToBeginWith = shift; + my $NULL = "" ; + my $diff_f1 = $NULL ; + my $diff_f2 = $NULL ; + my $retval = $NULL ; + my $ret; + open(F1, "$f1") or die "Could not open file $f1"; + open(F2, "$f2") or close(F1), die "Could not open file $f2"; + + while (defined($l1 = <F1>)) { + if ($lineToBeginWith){ + $lineToBeginWith -- ; + next ; + } + next if ($l1 =~ /^\#/); + $ret = defined($l2 = <F2>); + if ($ret) { + $ret = defined($l2 = <F2>) while ($ret && ($l2 =~ /^\#/)) ; + if ($ret) { + if (!($l1 eq $l2)) { + + # ignore whitespace + $l1_clean = $l1 ; + $l2_clean = $l2 ; + $l1_clean =~ s/\s//g; + $l2_clean =~ s/\s//g; + + if (!($l1_clean eq $l2_clean)) { + $diff_f1 .= "${l1}" unless ($l1_clean eq $NULL); + $diff_f2 .= "${l2}" unless ($l2_clean eq $NULL); + } + } + } + else { + next if ($l1 =~ /^\s*$/) ; + $diff_f1 .= "${l1}"; + } + } + else { + next if ($l1 =~ /^\s*$/) ; + $diff_f1 .= "${l1}"; + } + } + + while (defined($l2 = <F2>)) { + if (($l2 =~ /^\#/) || ($l2 =~ /^\s*$/)) { + next ; + } + else { + $diff_f2 .= "${l2}" ; + } + } + + close(F1); + close(F2); + + $retval .= "- differences present in your config file but not in standard file:\n\n". "$diff_f1\n" if ($diff_f1) ; + $retval .= "- differences present in standard file but not in your config file:\n\n" . "$diff_f2" if ($diff_f2) ; + return $retval ; +} + +sub CompareStdConfigFiles { + # Compare each configuration file against its default version. If it has changed, + # notify the user that the file has changed and will need to be checked by the + # user. This should be safe to do because there should be no path information + # stored in these conf files, which are just schema stuff. + # printTrace("\nCheck if standard configuration files have changed",3); + + my $origFilePath = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}install${PATHSEP}config${PATHSEP}" ; + my $FilesChanged = ""; + my $AllDiffs = "***********************************************************************"; + my $NoChanges = "" ; + my $lineToBegin = 0 ; + printTrace("\nVersion of the old directory server: $oldVersion.$oldMinor",0); + opendir(CONFDIR, $oldConfDir) or + die "Error: could not open migrated config dir $oldConfDir: $!"; + + foreach $file (readdir(CONFDIR)) { + $origFile = $origFilePath . $file ; + $configFile = $oldConfDir . $file ; + if ((! exists($userDefinedConfigFiles{lc($file)})) && (-f $origFile)) { + my $lineToBegin = 1 if (lc($file) eq "slapd-collations.conf"); # we ignore the first line of slapd-collations + $diffs = &diff($configFile, $origFile, $lineToBegin); + $lineToBegin = 0 if $lineToBegin ; + if ($diffs) { + $FilesChanged .= "\n$configFile"; + $AllDiffs .= "\n$configFile is different than the standard configuration file" ; + $AllDiffs .= "\nYou will need to check this file and make sure its changes are compatible "; + $AllDiffs .= "with the new directory server\nHere are the differences:\n"; + $AllDiffs .= "$diffs \n\n"; + $AllDiffs .= "***********************************************************************"; + } + else { + $NoChanges .= "\n$configFile"; + } + } + } + closedir(CONFDIR); + +if ($FilesChanged) { + printTrace("\nNo changes to old configuration files:$NoChanges",3) ; + printTrace("\n***********************************************************************",3) ; + printMsg("\nThe following standard files have been modified: $FilesChanged"); + if ($NO_INPUT_USER) { + # do nothing + } + else { + printMsg("\nDo you want to see the differences Yes/No [No] ?") ; + my $answer = <STDIN> ; + if ($answer =~ /y|yes/i) { + printMsg("$AllDiffs"); + } + printMsg("\nDo you want to continue the migration Yes/No [No] ?"); + $answer = <STDIN> ; + if (! ($answer =~ /y|yes/i)) { + exit(1); + } + } + } +} + + +############################################################################# + +sub db2ldif { + my ($conf, $ldif_dir) = @_; + $ENV{"$LIB_PATH"}=$old_libpath; + if (!$conf) { + $conf = "$oldHome${PATHSEP}config${PATHSEP}slapd.conf"; + } + if (! $ldif_dir) { $ldif_dir = $ldif_rep ;} + if (!(-d $ldif_dir)) { + mkdir($ldif_dir,0777) or die "can't create $ldif_rep to store temporary ldif files"; + } + my $dir = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server"; + chdir($dir) or + die "Error: could not change directory to $dir: $!"; + my @suffixnames = keys(%DBNAMES) ; + foreach $suffixname (@suffixnames) { + my $ldif_file = $ldif_dir.$DBNAMES{$suffixname}.".ldif" ; + # If we are on NT, ${quote} is setup to "\"", else it's setup to "" + # As the suffix can contain some space characters, I write the suffix parameter: "\"$suffixname\"" rather than "${quote}$suffixname${quote}" + my @cmd = + ( "${quote}$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" . + "${PATHSEP}$slapdExecName${quote}", "db2ldif", '-n', '-f', + "${quote}$conf${quote}", '-a', "${quote}$ldif_file${quote}", + '-d', '1','-s',"\"$suffixname\"" ); + open(DB2LDIF, "${quote}@cmd${quote} 2>&1|") or + die "Error: could not execute @cmd: $!"; + sleep(1); # allow pipe to fill with data + $ii = 0; # counter + while (<DB2LDIF>) { + ++$ii; + if (($ii % 250) == 0) { + printMsg(" Processing...\n"); + } + } + close(DB2LDIF); + # set the ownership of the ldif file; should be the same as the new slapd user id + if ((! $isNt) && ($oldlocaluser ne $localuser)) { + if (-f $ldif_file) { + chown( $newuid, $newgid, $ldif_file) or printMsg("\nUnable to change the ownership of $ldif_file to $localuser") ; + } + } + } + print " Done.\n"; + chdir($curdir) or die "Could not change directory to $curdir: $!"; +} + +############################################################################# +# This db2ldif is used to export database of the new instance + +sub newinst_db2ldif { + my $ldif = shift ; + my $include_suffix = shift ; + my $home = shift ; + my $db2ldif_param = "db2ldif -r -D $home -a $ldif -s \"$include_suffix\""; + + open(DB2LDIF, "${quote}${quote}$slapdExecName${quote} $db2ldif_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n"; + sleep(1); # allow some data to accumulate in the pipe + my $ii = 0; + while (<DB2LDIF>) { + ++$ii; + if (($ii % 250) == 0) { + printMsg(" Processing...\n"); + } + printMsg($_); + } + close(DB2LDIF); + # set the ownership of the ldif file; should be the same as the 5.x slapd user id + if ((! $isNt) && ($oldlocaluser ne $localuser)) { + if (-f $ldif) { + chown( $newuid, $newgid, $ldif) or printMsg("\nUnable to change the ownership of $ldif to $localuser") ; + } + } +} + +############################################################################# + +# this is used to run the system() call, capture exit and signal codes, +# and die() upon badness; the first argument is a directory to change +# dir to, if any, and the rest are passed to system() +sub mySystem { + my $rc = &mySystemNoDie(@_); + my ($dir, @args) = @_; + if ($rc == 0) { +# success + } elsif ($rc == 0xff00) { + die "Error executing @args: error code $rc: $!"; + } elsif ($rc > 0x80) { + $rc >>= 8; + die "Error executing @args: error code $rc: $!"; + } else { + if ($rc & 0x80) { + $rc &= ~0x80; + } + die "Error executing @args: received signal $rc: $!"; + } + + # usually won't get return value + return $rc; +} + +# This version does not die but just returns the error code +sub mySystemNoDie { + my ($dir, @args) = @_; + if ($dir && ($dir ne "")) { + chdir($dir) or die "Could not change directory to $dir: $!"; + } + my $cmd = $args[0]; + # the system {$cmd} avoids some NT shell quoting problems if the $cmd + # needs to be quoted e.g. contains spaces; the map puts double quotes + # around the arguments on NT which are stripped by the command + # interpreter cmd.exe; but don't quote things which are already quoted + my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @args; + my $rc = 0; + if ($cmd =~ /[.](bat|cmd)$/) { + # we have to pass batch files directly to the NT command interpreter + $cmd = $com_spec; +# print "system $cmd /c \"@fixargs\"\n"; + $rc = 0xffff & system {$cmd} '/c', "\"@fixargs\""; + } else { +# print "system $cmd @fixargs\n"; + $rc = 0xffff & system {$cmd} @fixargs; + } + chdir(${curdir}) or die "Could not change directory to $curdir: $!"; + return $rc; +} + +############################################################################# +sub manyLdif2db { + my %rev_dbnames = reverse(%DBNAMES); + @backends = keys(%rev_dbnames); + $ENV{"$LIB_PATH"}=$new_libpath; + chdir($slapdExecDir) or die "Could not change directory to $slapdExecDir: $!"; + foreach $backend (@backends) { + my $ldif = "${ldif_rep}$backend.ldif" ; + if (! -f $ldif) { + $ldif = ${ldif_rep}."data.ldif"; + } + &Ldif2db($ldif, $backend); + } + # remove the empty ldif directory + # but not if using the data dir + if (!$olddatadir) { + rmdir($ldif_rep); + } + chdir($curdir) or die "Could not change directory to $curdir: $!"; +} + + +sub Ldif2db { + my $ldif = shift ; + my $backend = shift ; + my $ldif2db_param = "ldif2db -D $serverHome -n $backend -i $ldif"; + open(LDIF2DB, "${quote}${quote}$slapdExecName${quote} $ldif2db_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n"; + sleep(1); # allow some data to accumulate in the pipe + while (<LDIF2DB>) { + printMsg($_); + } + close(LDIF2DB); + # remove the ldif file after the import + # but not if using the data dir + if (!$olddatadir) { + unlink($ldif) ; + } +} + +############################################################################# + +#sub copyBak { +# opendir( OLDBAK, "$oldHome${PATHSEP}bak" ) || +# die "Can't open directory $oldHome${PATHSEP}bak: $!: "; +# local ( @dirs ) = readdir( OLDBAK ); +# closedir ( OLDBAK ); +# for ( @dirs ) { +# if ( $_ eq "." || $_ eq ".." ) { +# next; +# } elsif ( -d "$oldHome${PATHSEP}bak${PATHSEP}$_" ) { +# $srcDir = "$oldHome${PATHSEP}bak${PATHSEP}$_"; +# $destDir = "$serverHome${PATHSEP}bak${PATHSEP}$_"; +# $srcLDIF = "$oldHome${PATHSEP}ldif${PATHSEP}bak.ldif"; +# $destLDIF = "$serverHome${PATHSEP}ldif${PATHSEP}bak.ldif"; +# mkdir( $destDir , 0755 ) if !( -e $destDir); +# # Converting database +# if ( !$isNT && $newuser ) { +# chown($newuid, $newgid, +# "$serverHome${PATHSEP}bak", $destDir); +# } +# &other_db2ldif($srcDir, $srcLDIF); +# if ($needAclUpg) { +# &mySystem("$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server", +# "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" . +# "${PATHSEP}aclupg$exe_suffix", '-d', '-i', +# $srcLDIF, '-o', $destLDIF); +# } else { +# ©BinFile($srcLDIF, $destLDIF); +# } +# &other_ldif2db($destLDIF, $destDir); +# } +# } +#} +############################################################################# + +sub startServer { + my $instanceDir = ${serverHome} ; + my $errLog = $instanceDir . $PATHSEP . 'logs' . $PATHSEP . 'errors'; + # emulate tail -f + # if the last line we see does not contain "slapd started", try again + my $done = 0; + my $started = 0; + my $code = 0; + my $lastLine = ""; + my $timeout = time + 240; # 4 minutes + $ENV{"$LIB_PATH"}=$new_libpath; + + my $startCmd = $instanceDir . $PATHSEP . 'start' . $script_suffix; + if (! -f $startCmd) { + $startCmd = $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix; + } + printTrace("\nInstanceDir: $instanceDir\n",4); + $code = &mySystem($instanceDir,$startCmd); + open(IN, $errLog) or die "Could not open error log $errLog: $!"; + my $pos = tell(IN); + while (($done == 0) && (time < $timeout)) { + for (; ($done == 0) && ($_ = <IN>); $pos = tell(IN)) { + $lastLine = $_; + # print; + # the server has already been started and shutdown once . . . + if (/slapd started\./) { + $started++; + if ($started == 2) { + $done = 1; + } + # sometimes the server will fail to come up; in that case, restart it + } elsif (/Initialization Failed/) { + # print "Server failed to start: $_"; + $code = &mySystem($instanceDir, $startCmd); + # sometimes the server will fail to come up; in that case, restart it + } elsif (/exiting\./) { + # print "Server failed to start: $_"; + #$code = &mySystem($startCmd); + + $code = &mySystem($instanceDir, $startCmd); + } + } + if ($lastLine =~ /PR_Bind/) { + # server port conflicts with another one, just report and punt + print $lastLine; + print "This server cannot be started until the other server on this\n"; + print "port is shutdown.\n"; + $done = 1; + } + if ($done == 0) { + # rest a bit, then . . . + sleep(2); + # . . . reset the EOF status of the file desc + seek(IN, $pos, 0); + } + } + close(IN); + + if ($started < 2) { + $! = $code; + # $now = time; + # if ($now > $timeout) { + # print "Possible timeout: timeout=$timeout now=$now\n"; + # } + die "Error: could not start server: $!"; + } + + return 0; +} + +sub stopServer { + my $root = shift; + my $name = shift; + $maxStopIterations = 5; + print "\nShutting down server $name . . .\n"; + + $ENV{"$LIB_PATH"}=$new_libpath; + $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop' . $script_suffix . $quote; + if (! -f $stopCmd) { + $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop-slapd' . $script_suffix . $quote; + } + + if (! -f $stopCmd) { + # no stop command, probably a 1.X system; for NT, we'll try net stop + # for unix, we'll get the pid and kill it + if ($isNT) { + $stopCmd = 'net stop ' . $name; + } else { + # see if there is a pid file + $pidfile = $root . $PATHSEP . $name . $PATHSEP . 'logs' . + $PATHSEP . 'pid'; + if (open(PIDFILE, $pidfile)) { + chomp($pid = <PIDFILE>); + close(PIDFILE); + while ($maxStopIterations-- && !$exitCode) { + $exitCode = kill(15, $pid); + } + $stopCmd = undef; + } + } + } + + # keep looping until the stop cmd returns an error code, which usually + # means that what ever we want to stop is stopped, or some other error + # occurred e.g. permission, or no such service + $exitCode = &runAndIgnoreOutput($stopCmd); +# print "stopServer: exitCode=$exitCode\n"; + while ($stopCmd && $maxStopIterations-- && $exitCode) { + $exitCode = &runAndIgnoreOutput($stopCmd); +# print "stopServer: exitCode=$exitCode\n"; + } + + if (!$maxStopIterations) { + print "Warning: could not shutdown the server: $!\n"; + } + + sleep(10) ; + + $exitCode = 0; + +} + + +sub runAndIgnoreOutput { + my $cmd = shift; + printMsg("."); + open(RUNCMD, "${quote}$cmd${quote} 2>&1 |") or die "Error: could not run $cmd: $!"; + printMsg("."); + sleep(1); # allow pipe to fill with data + printMsg("."); + while (<RUNCMD>) { +# print; + } + my $code = close(RUNCMD); +# print "runAndIgnore: code=$code status=$?\n"; + return $?; +} +############################################################################# +# migrate some of entries present in the old DSE.ldif like +# cn=snmp,cn=config +# cn=encryption,cn=config +# all the aci's + +sub MigrateDSE { + printTrace("\nMigrate DSE entries...",1); + open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: "; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($old_entry = readOneEntry $in) { + my $DN = $old_entry->getDN() ; + SWITCH: { + # migrate the entrie: cn=snmp,cn=config + if ($DN =~ /^cn=SNMP,cn=config$/i) { + my $entry = $conn->search("$DN","base","objectclass=nsSNMP"); + if ($entry) { + my $res = $conn->update($old_entry); + if ($res) { + printTrace("\n$DN updated !",2); + } + else { + printMsg("\nFailed to update $DN"); + } + } + else { + printMsg("\nUnable to get info under $DN"); + } + last SWITCH; + } + # migrate the entrie: cn=encryption,cn=config + if ($DN =~ /cn=encryption,cn=config$/i) { + if ($conn->search("$DN","base","objectclass=*")) { + if ($old_entry->hasValue("objectClass", "nsEncryptionConfig")) { + my $certfile = "alias/slapd-" . $newname . "-cert8.db"; + my $keyfile = "alias/slapd-" . $newname. "-key3.db"; + $old_entry->setValues("nsCertfile",$certfile) if ! $old_entry->hasValue("nsCertfile",$certfile); + $old_entry->setValues("nsKeyfile",$keyfile) if ! $old_entry->hasValue("nsKeyfile",$keyfile); + } + my $res = $conn->update($old_entry); + if ($res) { + printTrace("\n$DN updated !",2); + } + else { + printMsg("\nFailed to update $DN"); + } + } + else { + my $res = $conn->add($old_entry); + if ($res) { + printTrace("\n$DN added !",2); + } + else { + printMsg("\nFailed to add $DN"); + } + } + last SWITCH; + } + if (@{$old_entry->{aci}} && (! ($DN =~ /^cn=monitor$/i)) && (! ($DN =~ /^cn=schema$/i))) { + # migrate aci's + my $entry = $conn->search("$DN","base","objectclass=*"); + if ($entry) { + my $res = $conn->update($old_entry); + if ($res) { + printTrace("\n$DN updated !",2); + } + else { + printMsg("\nFailed to update $DN"); + } + } + else { + my $res = $conn->add($old_entry); + if ($res) { + printTrace("\n$DN added !",2); + } + else { + printMsg("\nFailed to add $DN"); + } + } + last SWITCH; + } + } + } + close(DSELDIF); +} +############################################################################# +# migrate SSL info + +sub MigrateSSL { + my $secPwd = 'bidon' ; + # copy the SSL directory + ©Dir("$oldHome${PATHSEP}ssl","$serverHome${PATHSEP}ssl"); + # copy the cert db and key files + if ( -d "$oldDir${PATHSEP}alias") { + $aliasDir = "$root${PATHSEP}alias"; + if (! -d $aliasDir) { + mkdir($aliasDir, 0750); + } + &stopServer($root,'slapd-'.$newname); + my $keydb = "$aliasDir${PATHSEP}slapd-$newname-key3.db" ; + my $certdb = "$aliasDir${PATHSEP}slapd-$newname-cert8.db" ; + my $certdb7 = "$aliasDir${PATHSEP}slapd-$newname-cert7.db" ; + my $old_keydb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-key3.db" ; + my $old_certdb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-cert7.db"; + my $keydb_backup = "$aliasDir${PATHSEP}slapd-$newname-key3.db_backup" ; + my $certdb_backup = "$aliasDir${PATHSEP}slapd-$newname-cert7.db_backup" ; + if (-f $old_keydb) { + if (-f $keydb) { + if ($NO_INPUT_USER) { + printMsg("\n$keydb already exists. backup in $keydb_backup ..."); + ©BinFile($keydb,$keydb_backup); + ©BinFile($old_keydb,$keydb); + } + else { + print("\n\n$keydb already exists. Do you want to overwrite it ? [no]: "); + my $answer = <STDIN> ; + if ($answer =~ /^y|yes$/i) { + ©BinFile($old_keydb,$keydb); + } + } + } + else { + ©BinFile($old_keydb,$keydb); + } + } + if (-f $old_certdb) { + $mode = (stat($old_certdb))[2] if $PRESERVE; + if (-f $certdb) { + if ($NO_INPUT_USER) { + printMsg("\n$certdb already exists. backup in $certdb_backup ..."); + ©BinFile($certdb,$certdb_backup); + unlink($certdb) || print "Couldn't delete $certdb : $!\n"; + ©BinFile($old_certdb,$certdb7); + } + else { + print("\n\n$certdb already exists. Do you want to overwrite it ? [no]: "); + my $answer = <STDIN> ; + if ($answer =~ /^y|yes$/i) { + unlink($certdb) || print "Couldn't delete $certdb : $!\n"; + ©BinFile($old_certdb,$certdb7); + } + } + } + else { + ©BinFile($old_certdb,$certdb7); + } + } + # copy the old password file + if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") { + ©BinFile( + "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt", + "$aliasDir${PATHSEP}$type-$newname-pin.txt" + ); + } + &startServer(); + if ($PRESERVE) { + chown($newuid,$newgid,$certdb) || print "Failed to set uid $newuid gid $newgid on $certdb : $!\n"; + chmod($mode,$certdb) || print "Failed to set mode $mode on $certdb : $!\n"; + } + } + +} + +sub DisableSSL { + my $entry = $conn->search("cn=config","base","objectclass=*"); + my $LDAPparam = "nsslapd-security" ; + my $Value = "off" ; + if ($entry->{$LDAPparam}[0] ne $Value) { + printTrace("\nDisable SSL...",1); + $entry->setValues($LDAPparam, $Value); + } + my $res = $conn->update($entry); + if ($res) { + printTrace("\nSSL disabled",2); + } + else { + printMsg("\nCan't disable SSL, the server may have problems starting"); + } +} + +# enable the migration of client authentication informations +sub MigrateCertmap { + # backup the old new certmap.conf and replace it with the old certmap.conf file + my $oldCertmap = "$oldDir${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf"; + my $newCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf" ; + my $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ; + if (&hasChangedoldCertmap($oldCertmap)) { + if ($NO_INPUT_USER) { + printMsg("\n$newCertmap has been backup in $backupCertmap"); + ©BinFile($newCertmap,$backupCertmap); + ©BinFile($oldCertmap,$newCertmap); + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\n\nWhere do you want to back up the file $newCertmap [$backupCertmap] ?") ; + my $Answer = <STDIN> ; + $backupCertmap = $Answer if ($Answer ne "\n"); + chomp($backupCertmap); + printTrace("\nDest: .$backupCertmap.",4); + if (-e $backupCertmap) { + printMsg("\n\n$backupCertmap already exists. Do you want to overwrite it Yes/No [No] ?") ; + if (<STDIN> =~ /yes|y/i) { + $Ask = 0 ; + } + else { + $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ; + } + } + else { + $Ask = 0 ; + } + } + printTrace("\nBackup file: $newCertmap in $backupCertmap",4); + ©BinFile($newCertmap,$backupCertmap); + ©BinFile($oldCertmap,$newCertmap); + } + } + else { + } +} + +sub hasChangedoldCertmap { + my $certmapfile = shift ; + my @reference = ("certmap default default", + "default:DNComps", + "default:FilterComps e") ; + my $cpt = 0 ; + printTrace("\nhasChangedoldCertmap",3); + open(CERTMAP,"< $certmapfile"); + while (<CERTMAP>) { + if ((! /^\s*#/) && (! /^\s*$/)) { + my $ref = $reference[$cpt] ; + printTrace("\nValue: $_, ref: $ref",4); + if (! /^\s*$ref\s*$/) { + return 1 ; + } + else { + $cpt++ ; + } + } + } + close (CERTMAP); + printTrace("\ncpt: $cpt",4); + if ($cpt < $#reference) { + return 1 ; + } + else { + return 0 ; + } +} +############################################################################# +# copy a directory to another + +sub copyDir { + my $src = shift; + my $dest = shift; + my $exclude = shift; + + opendir( SRC, $src ) or die "Can't open directory $src: $!: "; + my $mode; + my $uid; + my $gid; + mkdir ( $dest , 0755 ) or die "\nCan't create directory $dest. \nPlease check you have enough rights to create it and/or check that your parent directory exists.\n" if !( -e $dest ); + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + local ( @files ) = readdir ( SRC ); + closedir( SRC ); + for ( @files ) { + if ( $_ eq "." || $_ eq ".." ) { + next; + } elsif ( $exclude && /$exclude/ ) { + next; + } elsif( -d "$src${PATHSEP}$_") { + ©Dir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" ); + } else { + ©BinFile ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_"); + } + } +} + +sub copyBinFile { + my $src = shift; + my $dest = shift; + my $buf = ""; + my $bufsize = 8192; + + open( SRC, $src ) || die "Can't open $src: $!\n"; + # if we are given a directory destination instead of a file, extract the + # filename portion of the source to use as the destination filename + if (-d $dest) { + $dest = $dest . $PATHSEP . &basename($src); + } + open( DEST, ">$dest" ) || die "Can't create $dest: $!\n"; + binmode SRC; + binmode DEST; + if ($PRESERVE) { + $mode = (stat($src))[2]; + ($uid, $gid) = (stat(_))[4..5]; + # Make sure files owned by the old user are owned by the + # new user + if ($uid == $olduid) { + $uid = $newuid; + $gid = $newgid; + } + chown $uid, $gid, $dest; + chmod $mode, $dest; + } + while (read(SRC, $buf, $bufsize)) { + print DEST $buf; + } + close( SRC ); + close( DEST ); +} +############################################################################# +# backup new configuration files +# backup the directory <new_root_server>/slapd-instance/config in <new_root_server>/slapd-instance/BackupConfig + +sub backupConfigFiles { + # backup the new config files + my $src = "$serverHome${PATHSEP}config" ; + my $dest = "$serverHome${PATHSEP}config_backup" ; + if ($NO_INPUT_USER) { + printMsg("\n$src has been backup in $dest"); + ©Dir($src,$dest); + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\n\nWhere do you want to back up your configuration directory [$dest] ?") ; + my $Answer = <STDIN> ; + $dest = $Answer if ($Answer ne "\n"); + chomp($dest); + printTrace("\nDest: .$dest.",4); + if (-e $dest) { + printMsg("\n\n$dest already exists. Do you want to overwrite it Yes/No [No] ?") ; + if (<STDIN> =~ /yes|y/i) { + $Ask = 0 ; + } + else { + $dest = "$serverHome${PATHSEP}config_backup" ; + } + } + else { + $Ask = 0 ; + } + } + printTrace("\nBackup Directory: $src in $dest",4); + ©Dir($src,$dest); + } +} +############################################################################# + +sub getLDAPservername { + my $oldLDAPservername; + my $LDAPservername; + open(OLDSLAPDCONF, $oldSlapdConf) or + die "\nError: could not open old config file $oldSlapdConf \n"; + while(<OLDSLAPDCONF>) { + chop; + if (/^localhost\s+/i) { + ($oldLDAPservername = $') =~ s/^[\"]//;; + $oldLDAPservername =~ s/[\"]$//; + printTrace("\nName of the old LDAP server: $oldLDAPservername",3); + } + } + close(OLDSLAPDCONF); + + open( DSELDIF, "< $DSEldif" ) || die "\nCan't open $DSEldif \n"; + my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; + while ($entry = readOneEntry $in) { + my $DN = $entry->getDN() ; + if ($DN =~ /^cn=config$/i) { + my $localhost = "nsslapd-localhost"; + my @values = $entry->getValues($localhost); + if ($#values != -1) { + $LDAPservername = $values[0]; + } + break; + } + } + close(DSELDIF); + # check old and new are installed on the same physical machine. + if (lc($oldLDAPservername) ne lc($LDAPservername)) { + # warn the user he tries to migrate a old server installed on a different machine from the new one + printMsg("\n\nYour old server is on $oldLDAPservername, and your new server is on $LDAPservername. We don't support migration on different machines. Do you want to continue ? Yes/No [No]:") ; + if (! (<STDIN> =~ /yes|y/i)) { + return -1; + } + } + return $LDAPservername ; +} + +############################################################################# + +sub getLibPath { + my $myDir = shift; + my $myVersion = shift; + my $myMinor = shift; + + if ($isNT) { + return $ENV{"$LIB_PATH"}; + } + if (($myVersion >= 6) && ($myMinor >= 2)) { + return + "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}". + "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}". + $ENV{"$LIB_PATH"}; + } else { + return "$myDir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"}; + } +} + +############################################################################# + +sub getVersion { + my $dir = shift; + my $versionstr = shift; + my $version = 0; + my $minor = 0; + my $buildNumber = 0; + my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}"; + my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}"; + + # find the slapd executable + if (!$versionstr) { # version not specified on cmd line - find it + $prog = $dir . $progDir . $slapdExecName; + if (! -f $prog) { + $prog = $dir . $progDir2 . $slapdExecName; + if (-f $prog && $isNT) { + # if slapd is in bin/slapd and we're on NT, just assume version 1; + # apparently, slapd.exe doesn't like the -v argument . . . + return ( '1', $minor ); + } + else{ + die "Could not run slapd program $prog: $!"; + } + } + else { + chdir($dir . $progDir); + } + $cur_libpath=$ENV{"$LIB_PATH"}; + $ENV{"$LIB_PATH"}= + "$dir${PATHSEP}lib${SEP}". + "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}". + "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}". + $ENV{"$LIB_PATH"}; + # read the old version from the old slapd program + + open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or + die "Could not run slapd program $prog: $!"; + sleep(1); # allow some data to accumulate in the pipe +# print "Output from $prog -v:\n"; + while (<F>) { + if (/^Netscape-Directory/ || /^iPlanet-Directory/i) { + $versionstr = $_; + last; + } + } + $code = close(F); + # print "$prog returned code=$code status=$?\n"; + $ENV{"$LIB_PATH"}=$cur_libpath; + } + + if ($versionstr =~ /^Netscape-Directory\/(\d+)\.(\d+)(?:b\d)*\s+(\S+)/) { + $version = $1; + $minor = $2; + $buildNumber = $3; + } + elsif ($versionstr =~ /^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ... + $version = $1; + $minor = $2; + $buildNumber = $3; + } + elsif ($versionstr =~ /^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) { + $version = $1; + $minor = $2; + $buildNumber = $3; + } elsif ($versionstr =~ /(\d+)\.(\d+)/) { + $version = $1; + $minor = $2; + } + + if ($version == 0) { + die "\nCould not determine version of the directory server in $dir: \n"; + } + + # distinguish the 4.1 and the 4.11 thanks to the buildNumber + if (($version == 4) && ($minor == 1)){ + if (! ($buildNumber =~ /^B99\.16/)) { + # it's not a 4.1 Netscape Directory Server => it's a 4.11 + $minor = 11 ; + } + } + chdir($curdir) or die "Could not change directory to $curdir: $!" ; + return ( $version, $minor ); +} + +############################################################################# + +sub getDiff { + # we get references to arrays + my $elements = shift ; + my $existing_elements = shift ; + my %count = () ; + my %countEE = () ; + @diff = () ; + foreach $e (@{$elements}, @{$existing_elements}) { $count{$e}++ ;} + foreach $e (@{existing_elements}) { $countEE{$e}++ ;} + foreach $e (@{$elements}) { + # if $e is only present in @$elements, we push it to the diff array + if (($count{$e} == 1) && ($countEE{$e} == 0)) { + push @diff, $e ; + } + } + return @diff ; +} + +############################################################################################### +sub testIndexUpdating { + #my $entry = $conn->newEntry(); + #$entry->setDN("cn=djeattribute,cn=index,cn=MigratedDB_5,cn=ldbm database,cn=plugins,cn=config"); + my $entry = $conn->search("cn=mail,cn=index,cn=MigratedDB_2,cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex"); + my @types = ("pres", "sub", "eq") ; + my @existing_types = $entry->getValues("nsindextype"); + my @typesToAdd = &getDiff(\@types, \@existing_types); + foreach $newtype (@typesToAdd) { + $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2); + } + my $res = $conn->update($entry) ; + if ($res) {print("\nUpdate index mail\n");} + else { print("\ncan't update index mail");} + + $entry = $conn->search("cn=givenName,cn=index,cn=MigratedDB_2,cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex"); + @types = ("pres", "sub", "eq") ; + @existing_types = $entry->getValues("nsindextype"); print("\ngivenName, existing_types: @existing_types"); + @typesToAdd = &getDiff(\@types, \@existing_types); print("\nTypesToAdd: @typesToAdd"); + foreach $newtype (@typesToAdd) { + $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2); + } + my $res = $conn->update($entry) ; + if ($res) {print("\nUpdate index givenName\n");} + else { print("\ncan't update index givenName");} + } + + +############################################################################################### +sub normalizeDir { + my $dir = shift ; + my $dir_prec = "" ; + while ($dir_prec ne $dir) { + $dir_prec = $dir ; + if ($isNT) { + grep { s@\\\\@\\@g } $dir ; + } + else { + grep { s@//@/@g } $dir ; + } + } + return $dir ; +} + + +############################################################################################### +# return 1 if the value parameters is +sub isAllowedPlugin { + my $Value = lc(shift) ; + if ($allowedPlugins{$Value}) { + return 1 ; + } + else { + return 0 ; + } + +} + + +sub getSyntaxOid { + my $Value = lc(shift) ; + return $allowedPlugins{$Value} ; +} + +############################################################################################### +# return 1 if the value given in parameters is an allowed modifier +sub isAllowedModifier { + my $Value = lc(shift) ; + if ($allowedModifiers{$Value}) { + return 1 ; + } + else { + return 0 ; + } +} + +sub getModifierValue { + my $Value = lc(shift) ; + return $allowedModifiers{$Value} ; +} + +############################################################################################### + +sub GetTime { + my $tm = localtime; + (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900); + $sec = "0$sec" unless $sec > 9 ; + $min = "0$min" unless $min > 9 ; + $hour = "0$hour" unless $hour > 9 ; + $dd = "0$dd" unless $dd > 9 ; + $mm = "0$mm" unless $mm > 9 ; + return ($sec, $min, $hour, $dd, $mm, $yy); +} + +############################################################################################### +# get uid and group id of the new slapd server. +# The uid is done through the nsslapd-localuser attribute + +sub getuid_gid { + my $newuid ; + my $newgid ; + my $localuser ; + my $localuser_attr = "nsslapd-localuser" ; + if (! $isNT) { + my $entry = $conn->search("cn=config ", "base","objectclass=*", 0, ($localuser_attr)) ; + # Tests wether we succeed to get the entry cn=config + die "\nCan't get the entry cn=config \n" unless ($entry); + my @values = $entry->getValues($localuser_attr); + if ($#values == -1 || ($values[0] eq "") ) { # tests wether the nsslapd-localuser attribute has a value + printMsg("\nNo localuser has been found in the configuration of the directory. "); + if ($NO_INPUT_USER) { + printMsg("\nWe considered nobody as the localuser"); + $localuser = "nobody" ; + } + else { + my $Ask = 1 ; + while ($Ask) { + printMsg("\nUnder what user does your $Version.$Minor directory server run [nobody] ? ") ; + $localuser = <STDIN> ; + chomp($localuser); + $localuser = "nobody" if ($localuser eq ""); + ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ; + if ($newuid) { + $Ask = 0 ; + } + else { + printMsg("\nError: $localuser is unknown from the system "); + } + } + } + } + else { + $localuser = $values[0]; # returns the first value (we should only have one localuser) + my $size = $#values ; + } + ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ; + return ($localuser, $newuid, $newgid) ; + } + else { + return () ; + } +} + + +############################################################################################### +# get uid and group id of the old slapd server. + +sub getolduid_gid { + my $oldlocaluser ; + if (! $isNT) { + open(CONF, $oldSlapdConf) or die "\nError: cannot open $oldSlapdConf: $!\n"; + while (<CONF>) { + if (/^localuser\s+/i) { + chomp($oldlocaluser = $'); + last; + } + } + close(CONF); + ($olduid, $oldgid) = (getpwnam("$oldlocaluser"))[2..3] ; + return ($oldlocaluser, $olduid, $oldgid) ; + } + else { + return (); + } +} + +############################################################################################### +# get current directory + +sub getCwd { + my $command = $isNT ? "cd" : "/bin/pwd"; + open(PWDCMD, "$command 2>&1 |") or + die "Error: could not execute $command: $!"; + # without the following sleep, reading from the pipe will + # return nothing; I guess it gives the pwd command time + # to get some data to read . . . + sleep(1); + my $currentdir; + while (<PWDCMD>) { + if (!$currentdir) { + chomp($currentdir = $_); + } + } + my $code = close(PWDCMD); +# if ($code || $?) { +# print "$command returned code=$code status=$? dir=$curdir\n"; +# } +# print "getCwd curdir=\[$curdir\]\n"; + return $currentdir; +} diff --git a/ldap/admin/src/scripts/template-ns-accountstatus.pl b/ldap/admin/src/scripts/template-ns-accountstatus.pl new file mode 100644 index 00000000..5913f7ad --- /dev/null +++ b/ldap/admin/src/scripts/template-ns-accountstatus.pl @@ -0,0 +1,813 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +############################### +# SUB-ROUTINES +############################### + +sub usage_and_exit +{ + print (STDERR "$cmd [-D rootdn] { -w password | -w - | -j filename } \n"); + print (STDERR " [-p port] [-h host] -I DN-to-$operation\n\n"); + print (STDERR "May be used to $operation a user or a domain of users\n\n"); + print (STDERR "Arguments:\n"); + print (STDERR " -? - help\n"); + print (STDERR " -D rootdn - Provide a Directory Manager DN. Default= '$defrootdn'\n"); + print (STDERR " -w password - Provide a password for the Directory Manager DN\n"); + print (STDERR " -w - - Prompt for the Directory Manager's password\n"); + print (STDERR " -j filename - Read the Directory Manager's password from file\n"); + print (STDERR " -p port - Provide a port. Default= '$defport'\n"); + print (STDERR " -h host - Provide a host name. Default= '$defhost'\n"); + print (STDERR " -I DN-to-$operation - Single entry DN or role DN to $operation\n"); + exit 100; +} + +sub debug +{ +# print " ==> @_"; +} + +sub out +{ + print "@_"; +} + +# -------------------------- +# Check if the entry is part of a locked role: +# i.e.: for each role member (nsroledn) of nsdisabledrole, check if +# * it is the same as the entry +# * the entry is member of role (==has nsroledn attributes), compare each of +# them with the nsroledn of nsdisabledrole +# * if nsroledn of nsdisabledrole are complex, go through each of them +# argv[0] is the local file handler +# argv[1] is the entry (may be a single entry DN or a role DN) +# argv[2] is the base for the search +# -------------------------- + +$throughRole=""; + +sub indirectLock +{ + # For recursivity, file handler must be local + my $L_filehandle=$_[0]; + $L_filehandle++; + + my $L_entry=$_[1]; + # Remove useless space + my @L_intern=split /([,])/,$L_entry; + my $L_result=""; + foreach $L_part (@L_intern) + { + $L_part=~s/^ +//; + $L_part=~ tr/A-Z/a-z/; + $L_result="$L_result$L_part"; + } + $L_entry=$L_result; + + my $L_base=$_[2]; + + my $L_search; + my $L_currentrole; + my $L_retCode; + + my $L_local; + +`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsroledn >> {{DEV-NULL}} 2>&1 `; +$retCode=$?; +if ( $retCode != 0 ) +{ + $retCode=$?>>8; + return 1; +} + + # Check if the role is a nested role + @L_Nested="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=nsNestedRoleDefinition)(objectclass=ldapsubentry))\" "; + # L_isNested == 1 means that we are going through a nested role, so for each member of that + # nested role, check that the member is below the scope of the nested + $L_isNested=@L_Nested; + + # Not Direct Lock, Go through roles if any + $L_search="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsroledn "; + + debug("\t-->indirectLock: check if $L_entry is part of a locked role from base $L_base\n\n"); + + unless (open ($L_filehandle, "$L_search |")) + { + out("Can't open file $L_filehandle\n"); + exit; + } + while (<$L_filehandle>) { + + s/\n //g; + if (/^nsroledn: (.*)\n/) { + $L_currentrole = $1; + + # Remove useless space + my @L_intern=split /([,])/,$L_currentrole; + my $L_result=""; + foreach $L_part (@L_intern) + { + $L_part=~s/^ +//; + $L_part=~ tr/A-Z/a-z/; + $L_result="$L_result$L_part"; + } + $L_currentrole=$L_result; + + debug("\t-- indirectLock loop: current nsroledn $L_currentrole of base $L_base\n"); + if ( $L_isNested == 1 ) + { + if ( checkScope($L_currentrole, $L_base) == 0 ) + { + # Scope problem probably a bad conf, skip the currentrole + next; + } + } + + if ( $L_currentrole eq $L_entry ) + { + # the entry is a role that is directly locked + # i.e, nsroledn of nsdisabledrole contains the entry + $throughRole=$L_base; + $throughRole=~ tr/A-Z/a-z/; + + # skipDisabled means that we've just found that the entry (which is a role) + # is locked directly (==its DN is part of nsroledn attributes) + # we just want to know now, if it is locked through another role + # at least, one + if ( $skipDisabled == 1 ) + { + # direct inactivation + $directLocked=1; + # just go through that test once + $skipDisabled=0; + next; + } + debug("\t-- 1 indirectLock: $L_currentrole locked throughRole == $throughRole\n"); + return 0; + } + + $L_retCode=memberOf($L_currentrole, $L_entry); + if ( $L_retCode == 0 && $single == 1 ) + { + $throughRole=$L_currentrole; + $throughRole=~ tr/A-Z/a-z/; + if ( $skipManaged == 1 ) + { + if ( $L_currentrole eq $nsManagedDisabledRole) + { + # Try next nsroledn + $directLocked=1; + $skipManaged=0; + next; + } + } + debug("\t-- 2 indirectLock: $L_currentrole locked throughRole == $throughRole\n"); + return 0; + } + + # Only for the first iteration + # the first iteration is with nsdisabledrole as base, other + # loops are deeper + $L_local=$skipDisabled; + $skipDisabled=0; + + # the current nsroledn may be a complex role, just go through + # its won nsroledn + $L_retCode=indirectLock($L_filehandle,$L_entry, $L_currentrole); + + # Because of recursivity, to keep the initial value for the first level + $skipDisabled=$L_local; + + if ( $L_retCode == 0 ) + { + $throughRole=$L_currentrole; + $throughRole=~ tr/A-Z/a-z/; + debug("\t-- 3 indirectLock: $L_entry locked throughRole == $throughRole\n"); + return 0; + } + } + } + + close($L_filehandle); + + debug("\t<--indirectLock: no more nsroledn to process\n"); + return 1; +} + +# -------------------------- +# Check if nsroledn is part of the entry attributes +# argv[0] is a role DN (nsroledn attribute) +# argv[1] is the entry +# -------------------------- +sub memberOf +{ + my $L_nsroledn=$_[0]; + $L_nsroledn=~ tr/A-Z/a-z/; + + my $L_entry=$_[1]; + + my $L_search; + my $L_currentrole; + + $L_search="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_entry\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsrole"; + + debug("\t\t-->memberOf: $L_search: check if $L_entry has $L_nsroledn as nsroledn attribute\n"); + + open (LDAP2, "$L_search |"); + while (<LDAP2>) { + s/\n //g; + if (/^nsrole: (.*)\n/) { + $L_currentrole = $1; + $L_currentrole=~ tr/A-Z/a-z/; + if ( $L_currentrole eq $L_nsroledn ) + { + # the parm is part of the $L_entry nsroledn + debug("\t\t<--memberOf: $L_entry locked through $L_nsroledn\n"); + return 0; + } + } + } + close(LDAP2); + + # the parm is not part of the $L_entry nsroledn + debug("\t\t<--memberOf: $L_entry not locked through $L_nsroledn\n"); + return 1; +} + + +# -------------------------- +# Remove the rdn of a DN +# argv[0] is a DN +# -------------------------- +sub removeRdn +{ + $L_entry=$_[0]; + + @L_entryToTest=split /([,])/,$L_entry; + debug("removeRdn: entry to split: $L_entry**@L_entryToTest\n"); + + $newDN=""; + $removeRDN=1; + foreach $part (@L_entryToTest) + { + $part=~ s/^ +//; + $part=~ tr/A-Z/a-z/; + if ( $removeRDN <= 2 ) + { + $removeRDN=$removeRDN+1; + } + else + { + $newDN="$newDN$part"; + } + } + + debug("removeRdn: new DN **$newDN**\n"); +} + +# -------------------------- +# Check if L_current is below the scope of +# L_nestedRole +# argv[0] is a role +# argv[1] is the nested role +# -------------------------- +sub checkScope +{ + $L_current=$_[0]; + $L_nestedRole=$_[1]; + + debug("checkScope: check if $L_current is below $L_nestedRole\n"); + + removeRdn($L_nestedRole); + $L_nestedRoleSuffix=$newDN; + debug("checkScope: nested role based: $L_nestedRoleSuffix\n"); + + $cont=1; + while ( ($cont == 1) && ($L_current ne "") ) + { + removeRdn($L_current); + $currentDn=$newDN; + debug("checkScope: current DN to check: $currentDn\n"); + + if ( $currentDn eq $L_nestedRoleSuffix ) + { + debug("checkScope: DN match!!!\n"); + $cont = 0; + } + else + { + $L_current=$currentDn; + } + } + + if ( $cont == 1 ) + { + debug("checkScope: $_[0] and $_[1] are not compatible\n"); + return 0; + } + else + { + debug("checkScope: $_[0] and $_[1] are compatible\n"); + return 1; + } +} + + +############################### +# MAIN ROUTINE +############################### + +# Generated variable +$dsroot="{{DS-ROOT}}"; + +# Determine which command we are running +if ( $0 =~ /ns-inactivate(.pl)?$/ ) +{ + $cmd="ns-inactivate.pl"; + $operation="inactivate"; + $state="inactivated"; + $modrole="add"; + $already="already"; +} +elsif ( $0 =~ /ns-activate(.pl)?$/ ) +{ + $cmd="ns-activate.pl"; + $operation="activate"; + $state="activated"; + $modrole="delete"; + $already="already"; +} +elsif ( $0 =~ /ns-accountstatus(.pl)?$/ ) +{ + $cmd="ns-accountstatus.pl"; + $operation="get status of"; + $state="activated"; + # no need for $modrole as no operation is performed + $already=""; + +} +else +{ + out("$0: unknown command\n"); + exit 100; +} + +debug("Running ** $cmd ** $operation\n"); + +$dsbinroot="$dsroot{{SEP}}shared{{SEP}}bin"; +$ldapsearch="$dsbinroot{{SEP}}ldapsearch -1"; +$ldapmodify="$dsbinroot{{SEP}}ldapmodify"; + +# Default values +$defrootdn= "{{ROOT-DN}}"; +$defhost= "{{SERVER-NAME}}"; +$defport= "{{SERVER-PORT}}"; + +# User values +$rootdn= "{{ROOT-DN}}"; +$rootpw= ""; +$pwfile= ""; +$host= "{{SERVER-NAME}}"; +$port= "{{SERVER-PORT}}"; +$entry= ""; + +$single=0; +$role=0; + +chdir("$dsbinroot"); + +# Process the command line arguments +while( $arg = shift) +{ + if($arg eq "-?") + { + usage_and_exit(); + } + elsif($arg eq "-D") + { + $rootdn= shift @ARGV; + } + elsif($arg eq "-w") + { + $rootpw= shift @ARGV; + } + elsif($arg eq "-j") + { + $pwfile= shift @ARGV; + } + elsif($arg eq "-p") + { + $port= shift @ARGV; + } + elsif($arg eq "-h") + { + $host= shift @ARGV; + } + elsif($arg eq "-I") + { + $entry= shift @ARGV; + } + else + { + print "$arg: Unknown command line argument.\n"; + usage_and_exit(); + } +} + +if ($pwfile ne ""){ +# Open file and get the password + unless (open (RPASS, $pwfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $rootpw = <RPASS>; + chomp($rootpw); + close(RPASS); +} elsif ($rootpw eq "-"){ +# Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; +# Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $rootpw = ReadLine(0); +# chomp($rootpw); +# ReadMode('normal'); +} + +if( $rootpw eq "" ) +{ + usage_and_exit(); +} + +if( $entry eq "" ) +{ + usage_and_exit(); +} + +# +# Check the actual existence of the entry to inactivate/activate +# and at the same time, validate the various parm: port, host, rootdn, rootpw +# +@exist=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(objectclass=*)\" dn`; +$retCode1=$?; +if ( $retCode1 != 0 ) +{ + $retCode1=$?>>8; + exit $retCode1; +} + +@isRole=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(&(objectclass=LDAPsubentry)(objectclass=nsRoleDefinition))\" dn`; +$nbLineRole=@isRole; +$retCode2=$?; +if ( $retCode2 != 0 ) +{ + $retCode2=$?>>8; + exit $retCode2; +} + +if ( $nbLineRole == 1 ) +{ + debug("Groups of users\n"); + $role=1; +} +else +{ + debug("Single user\n"); + $single=1; +} + +# +# First of all, check the existence of the nsaccountlock attribute in the entry +# +$isLocked=0; +if ( $single == 1 ) +{ + $searchAccountLock="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(objectclass=*)\" nsaccountlock"; + open (LDAP1, "$searchAccountLock |"); + while (<LDAP1>) { + s/\n //g; + if (/^nsaccountlock: (.*)\n/) { + $L_currentvalue = $1; + $L_currentvalue=~ tr/A-Z/a-z/; + if ( $L_currentvalue eq "true") + { + $isLocked=1; + } + elsif ( $L_currentvalue eq "false" ) + { + $isLocked=0; + } + } + } + close(LDAP1); +} +debug("Is the entry already locked? ==> $isLocked\n"); + +# +# Get the suffix name of that entry +# + +# Remove the space at the beginning (just in case...) +# -I "uid=jvedder , ou=People , o=sun.com" +@suffix=split /([,])/,$entry; +$result=""; +foreach $part (@suffix) +{ + $part=~s/^ +//; + $part=~ tr/A-Z/a-z/; + $result="$result$part"; +} +@suffixN=$result; + +debug("Entry to $operation: #@suffix#\n"); +debug("Entry to $operation: #@suffixN#\n"); + +# Get the suffix +$cont=0; +while ($cont == 0) +{ + # Look if suffix is the suffix of the entry + # ldapsearch -s one -b "cn=mapping tree,cn=config" "cn=\"uid=jvedder,ou=People,o=sun.com\"" + # + debug("\tSuffix from the entry: #@suffixN#\n"); + @mapping=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s one -b \"cn=mapping tree, cn=config\" \"cn=\\"@suffixN\\"\" cn `; + + $retCode=$?; + if ( $retCode != 0 ) + { + $retCode=$?>>8; + exit $retCode; + } + + # If we get a result, remove the dn: + # dn: cn="o=sun.com",cn=mapping tree,cn=config + # cn: "o=sun.com" + # + shift @mapping; + + foreach $res (@mapping) + { + # Break the string cn: "o=sun.com" into pieces + @cn= split(/ /,$res); + + # And remove the cn: part + shift @cn; + + # Now compare the suffix we extract from the mapping tree + # with the suffix derived from the entry + debug("\tSuffix from mapping tree: #@cn#\n"); + if ( @cn eq @suffixN ) { + debug("Found matching suffix\n"); + $cont=1; + } + } + + if ( $cont == 0 ) + { + # Remove the current rdn to try another suffix + shift @suffix; + + $result=""; + foreach $part (@suffix) + { + $part=~ s/^ +//; + $part=~ tr/A-Z/a-z/; + $result="$result$part"; + } + @suffixN=$result; + + debug("\t\tNothing found => go up one level in rdn #@suffix#\n"); + $len=@suffix; + if ( $len == 0 ) + { + debug("Can not find suffix. Problem\n"); + $cont=2; + } + } +} +if ( $cont == 2) +{ + out("Can not find suffix for entry $entry\n"); + exit 100; +} + +if ( $operation eq "inactivate" ) +{ + # + # Now that we have the suffix and we know if we deal with a single entry or + # a role, just try to create the COS and roles associated. + # + @base=( + "cn=nsManagedDisabledRole,@suffixN", + "cn=nsDisabledRole,@suffixN", + "cn=nsAccountInactivationTmp,@suffixN", + "\'cn=\"cn=nsDisabledRole,@suffixN\",cn=nsAccountInactivationTmp,@suffixN\'", + "cn=nsAccountInactivation_cos,@suffixN" ); + + $addrolescos="$ldapmodify -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -c -a >> {{DEV-NULL}} 2>&1 "; + @role1=( + "dn: cn=nsManagedDisabledRole,@suffixN\n", + "objectclass: LDAPsubentry\n", + "objectclass: nsRoleDefinition\n", + "objectclass: nsSimpleRoleDefinition\n", + "objectclass: nsManagedRoleDefinition\n", + "cn: nsManagedDisabledRole\n\n" ); + @role2=( + "dn: cn=nsDisabledRole,@suffixN\n", + "objectclass: top\n", + "objectclass: LDAPsubentry\n", + "objectclass: nsRoleDefinition\n", + "objectclass: nsComplexRoleDefinition\n", + "objectclass: nsNestedRoleDefinition\n", + "nsRoleDN: cn=nsManagedDisabledRole,@suffixN\n", + "cn: nsDisabledRole\n\n" ); + @cos1=( + "dn: cn=nsAccountInactivationTmp,@suffixN\n", + "objectclass: top\n", + "objectclass: nsContainer\n\n" ); + @cos2=( + "dn: cn=\"cn=nsDisabledRole,@suffixN\",cn=nsAccountInactivationTmp,@suffixN\n", + "objectclass: top\n", + "objectclass: extensibleObject\n", + "objectclass: costemplate\n", + "objectclass: ldapsubentry\n", + "cosPriority: 1\n", + "nsAccountLock: true\n\n" ); + @cos3=( + "dn: cn=nsAccountInactivation_cos,@suffixN\n", + "objectclass: top\n", + "objectclass: LDAPsubentry\n", + "objectclass: cosSuperDefinition\n", + "objectclass: cosClassicDefinition\n", + "cosTemplateDn: cn=nsAccountInactivationTmp,@suffixN\n", + "cosSpecifier: nsRole\n", + "cosAttribute: nsAccountLock operational\n\n" ); + + @all=(\@role1, \@role2, \@cos1, \@cos2, \@cos3); + + $i=0; + + foreach $current (@base) + { + debug("Creating $current ??\n"); + open(FD,"| $addrolescos "); + print FD @{$all[$i]}; + close(FD); + if ( $? != 0 ) + { + $retCode=$?>>8; + if ( $retCode == 68 ) + { + debug("Entry $current already exists, ignore error\n"); + } + else + { + # Probably a more serious problem. + # Exit with LDAP error + exit $retCode; + } + } + else + { + debug("Entry $current created\n"); + } + $i=$i+1; + } +} + +$skipManaged=0; +$skipDisabled=0; +$directLocked=0; + +$nsDisabledRole="cn=nsDisabledRole,@suffixN"; +$nsDisabledRole=~ tr/A-Z/a-z/; + +$nsManagedDisabledRole="cn=nsManagedDisabledRole,@suffixN"; +$nsManagedDisabledRole=~ tr/A-Z/a-z/; + +if ( $operation eq "inactivate" ) +{ + # Go through all the roles part of nsdisabledrole to check if the entry + # is a member of one of those roles + $ret=indirectLock("LDAP00", $entry, $nsDisabledRole); + if ( $ret == 0 ) + { + if ( $throughRole ne $nsDisabledRole && $throughRole ne $nsManagedDisabledRole ) + { + # indirect lock + out("$entry already $state through $throughRole.\n"); + } + else + { + # direct lock + out("$entry already $state.\n"); + } + exit 100; + } + elsif ( $isLocked == 1 ) + { + # the entry is not locked through a role, may be nsaccountlock is "hardcoded" ? + out("$entry already $state (probably directly).\n"); + exit 103; + } +} +elsif ( $operation eq "activate" || $operation eq "get status of" ) +{ + $skipManaged=$single; + $skipDisabled=$role; + + $ret=indirectLock("LDAP00",$entry, $nsDisabledRole); + + if ( $ret == 0 ) + { + # undirectly locked + if ( $throughRole ne $nsDisabledRole && $throughRole ne $nsManagedDisabledRole ) + { + if ( $operation eq "activate" ) + { + out("$entry inactivated through $throughRole. Can not activate it individually.\n"); + exit 100; + } + else + { + out("$entry inactivated through $throughRole.\n"); + exit 104; + } + } + debug("$entry locked individually\n"); + + if ( $operation ne "activate" ) + { + out("$entry inactivated.\n"); + exit 103; + } + } + elsif ( $directLocked == 0 ) + { + if ( $operation eq "activate" && $isLocked != 1 ) + { + out("$entry $already $state.\n"); + exit 100; + } + elsif ( $isLocked != 1 ) + { + out("$entry $already $state.\n"); + exit 102; + } + else + { + # not locked using our schema, but nsaccountlock is probably present + out("$entry inactivated (probably directly).\n"); + exit 103; + } + } + elsif ( $operation ne "activate" ) + { + out("$entry inactivated.\n"); + exit 103; + } + # else Locked directly, juste unlock it! + debug("$entry locked individually\n"); +} + +# +# Inactivate/activate the entry +# +$action="$ldapmodify -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -c >> {{DEV-NULL}} 2>&1"; +if ( $single == 1 ) +{ + @record=( + "dn: $entry\n", + "changetype: modify\n", + "$modrole: nsRoleDN\n", + "nsRoleDN: cn=nsManagedDisabledRole,@suffixN\n\n" ); +} +else +{ + @record=( + "dn: cn=nsDisabledRole,@suffixN\n", + "changetype: modify\n", + "$modrole: nsRoleDN\n", + "nsRoleDN: $entry\n\n" ); +} +open(FD,"| $action "); +print FD @record; +close(FD); +if ( $? != 0 ) +{ +debug("$modrole, $entry\n"); + $retCode=$?>>8; + exit $retCode; +} + +out("$entry $state.\n"); +exit 0; diff --git a/ldap/admin/src/scripts/template-ns-activate.pl b/ldap/admin/src/scripts/template-ns-activate.pl new file mode 100644 index 00000000..5913f7ad --- /dev/null +++ b/ldap/admin/src/scripts/template-ns-activate.pl @@ -0,0 +1,813 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +############################### +# SUB-ROUTINES +############################### + +sub usage_and_exit +{ + print (STDERR "$cmd [-D rootdn] { -w password | -w - | -j filename } \n"); + print (STDERR " [-p port] [-h host] -I DN-to-$operation\n\n"); + print (STDERR "May be used to $operation a user or a domain of users\n\n"); + print (STDERR "Arguments:\n"); + print (STDERR " -? - help\n"); + print (STDERR " -D rootdn - Provide a Directory Manager DN. Default= '$defrootdn'\n"); + print (STDERR " -w password - Provide a password for the Directory Manager DN\n"); + print (STDERR " -w - - Prompt for the Directory Manager's password\n"); + print (STDERR " -j filename - Read the Directory Manager's password from file\n"); + print (STDERR " -p port - Provide a port. Default= '$defport'\n"); + print (STDERR " -h host - Provide a host name. Default= '$defhost'\n"); + print (STDERR " -I DN-to-$operation - Single entry DN or role DN to $operation\n"); + exit 100; +} + +sub debug +{ +# print " ==> @_"; +} + +sub out +{ + print "@_"; +} + +# -------------------------- +# Check if the entry is part of a locked role: +# i.e.: for each role member (nsroledn) of nsdisabledrole, check if +# * it is the same as the entry +# * the entry is member of role (==has nsroledn attributes), compare each of +# them with the nsroledn of nsdisabledrole +# * if nsroledn of nsdisabledrole are complex, go through each of them +# argv[0] is the local file handler +# argv[1] is the entry (may be a single entry DN or a role DN) +# argv[2] is the base for the search +# -------------------------- + +$throughRole=""; + +sub indirectLock +{ + # For recursivity, file handler must be local + my $L_filehandle=$_[0]; + $L_filehandle++; + + my $L_entry=$_[1]; + # Remove useless space + my @L_intern=split /([,])/,$L_entry; + my $L_result=""; + foreach $L_part (@L_intern) + { + $L_part=~s/^ +//; + $L_part=~ tr/A-Z/a-z/; + $L_result="$L_result$L_part"; + } + $L_entry=$L_result; + + my $L_base=$_[2]; + + my $L_search; + my $L_currentrole; + my $L_retCode; + + my $L_local; + +`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsroledn >> {{DEV-NULL}} 2>&1 `; +$retCode=$?; +if ( $retCode != 0 ) +{ + $retCode=$?>>8; + return 1; +} + + # Check if the role is a nested role + @L_Nested="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=nsNestedRoleDefinition)(objectclass=ldapsubentry))\" "; + # L_isNested == 1 means that we are going through a nested role, so for each member of that + # nested role, check that the member is below the scope of the nested + $L_isNested=@L_Nested; + + # Not Direct Lock, Go through roles if any + $L_search="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsroledn "; + + debug("\t-->indirectLock: check if $L_entry is part of a locked role from base $L_base\n\n"); + + unless (open ($L_filehandle, "$L_search |")) + { + out("Can't open file $L_filehandle\n"); + exit; + } + while (<$L_filehandle>) { + + s/\n //g; + if (/^nsroledn: (.*)\n/) { + $L_currentrole = $1; + + # Remove useless space + my @L_intern=split /([,])/,$L_currentrole; + my $L_result=""; + foreach $L_part (@L_intern) + { + $L_part=~s/^ +//; + $L_part=~ tr/A-Z/a-z/; + $L_result="$L_result$L_part"; + } + $L_currentrole=$L_result; + + debug("\t-- indirectLock loop: current nsroledn $L_currentrole of base $L_base\n"); + if ( $L_isNested == 1 ) + { + if ( checkScope($L_currentrole, $L_base) == 0 ) + { + # Scope problem probably a bad conf, skip the currentrole + next; + } + } + + if ( $L_currentrole eq $L_entry ) + { + # the entry is a role that is directly locked + # i.e, nsroledn of nsdisabledrole contains the entry + $throughRole=$L_base; + $throughRole=~ tr/A-Z/a-z/; + + # skipDisabled means that we've just found that the entry (which is a role) + # is locked directly (==its DN is part of nsroledn attributes) + # we just want to know now, if it is locked through another role + # at least, one + if ( $skipDisabled == 1 ) + { + # direct inactivation + $directLocked=1; + # just go through that test once + $skipDisabled=0; + next; + } + debug("\t-- 1 indirectLock: $L_currentrole locked throughRole == $throughRole\n"); + return 0; + } + + $L_retCode=memberOf($L_currentrole, $L_entry); + if ( $L_retCode == 0 && $single == 1 ) + { + $throughRole=$L_currentrole; + $throughRole=~ tr/A-Z/a-z/; + if ( $skipManaged == 1 ) + { + if ( $L_currentrole eq $nsManagedDisabledRole) + { + # Try next nsroledn + $directLocked=1; + $skipManaged=0; + next; + } + } + debug("\t-- 2 indirectLock: $L_currentrole locked throughRole == $throughRole\n"); + return 0; + } + + # Only for the first iteration + # the first iteration is with nsdisabledrole as base, other + # loops are deeper + $L_local=$skipDisabled; + $skipDisabled=0; + + # the current nsroledn may be a complex role, just go through + # its won nsroledn + $L_retCode=indirectLock($L_filehandle,$L_entry, $L_currentrole); + + # Because of recursivity, to keep the initial value for the first level + $skipDisabled=$L_local; + + if ( $L_retCode == 0 ) + { + $throughRole=$L_currentrole; + $throughRole=~ tr/A-Z/a-z/; + debug("\t-- 3 indirectLock: $L_entry locked throughRole == $throughRole\n"); + return 0; + } + } + } + + close($L_filehandle); + + debug("\t<--indirectLock: no more nsroledn to process\n"); + return 1; +} + +# -------------------------- +# Check if nsroledn is part of the entry attributes +# argv[0] is a role DN (nsroledn attribute) +# argv[1] is the entry +# -------------------------- +sub memberOf +{ + my $L_nsroledn=$_[0]; + $L_nsroledn=~ tr/A-Z/a-z/; + + my $L_entry=$_[1]; + + my $L_search; + my $L_currentrole; + + $L_search="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_entry\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsrole"; + + debug("\t\t-->memberOf: $L_search: check if $L_entry has $L_nsroledn as nsroledn attribute\n"); + + open (LDAP2, "$L_search |"); + while (<LDAP2>) { + s/\n //g; + if (/^nsrole: (.*)\n/) { + $L_currentrole = $1; + $L_currentrole=~ tr/A-Z/a-z/; + if ( $L_currentrole eq $L_nsroledn ) + { + # the parm is part of the $L_entry nsroledn + debug("\t\t<--memberOf: $L_entry locked through $L_nsroledn\n"); + return 0; + } + } + } + close(LDAP2); + + # the parm is not part of the $L_entry nsroledn + debug("\t\t<--memberOf: $L_entry not locked through $L_nsroledn\n"); + return 1; +} + + +# -------------------------- +# Remove the rdn of a DN +# argv[0] is a DN +# -------------------------- +sub removeRdn +{ + $L_entry=$_[0]; + + @L_entryToTest=split /([,])/,$L_entry; + debug("removeRdn: entry to split: $L_entry**@L_entryToTest\n"); + + $newDN=""; + $removeRDN=1; + foreach $part (@L_entryToTest) + { + $part=~ s/^ +//; + $part=~ tr/A-Z/a-z/; + if ( $removeRDN <= 2 ) + { + $removeRDN=$removeRDN+1; + } + else + { + $newDN="$newDN$part"; + } + } + + debug("removeRdn: new DN **$newDN**\n"); +} + +# -------------------------- +# Check if L_current is below the scope of +# L_nestedRole +# argv[0] is a role +# argv[1] is the nested role +# -------------------------- +sub checkScope +{ + $L_current=$_[0]; + $L_nestedRole=$_[1]; + + debug("checkScope: check if $L_current is below $L_nestedRole\n"); + + removeRdn($L_nestedRole); + $L_nestedRoleSuffix=$newDN; + debug("checkScope: nested role based: $L_nestedRoleSuffix\n"); + + $cont=1; + while ( ($cont == 1) && ($L_current ne "") ) + { + removeRdn($L_current); + $currentDn=$newDN; + debug("checkScope: current DN to check: $currentDn\n"); + + if ( $currentDn eq $L_nestedRoleSuffix ) + { + debug("checkScope: DN match!!!\n"); + $cont = 0; + } + else + { + $L_current=$currentDn; + } + } + + if ( $cont == 1 ) + { + debug("checkScope: $_[0] and $_[1] are not compatible\n"); + return 0; + } + else + { + debug("checkScope: $_[0] and $_[1] are compatible\n"); + return 1; + } +} + + +############################### +# MAIN ROUTINE +############################### + +# Generated variable +$dsroot="{{DS-ROOT}}"; + +# Determine which command we are running +if ( $0 =~ /ns-inactivate(.pl)?$/ ) +{ + $cmd="ns-inactivate.pl"; + $operation="inactivate"; + $state="inactivated"; + $modrole="add"; + $already="already"; +} +elsif ( $0 =~ /ns-activate(.pl)?$/ ) +{ + $cmd="ns-activate.pl"; + $operation="activate"; + $state="activated"; + $modrole="delete"; + $already="already"; +} +elsif ( $0 =~ /ns-accountstatus(.pl)?$/ ) +{ + $cmd="ns-accountstatus.pl"; + $operation="get status of"; + $state="activated"; + # no need for $modrole as no operation is performed + $already=""; + +} +else +{ + out("$0: unknown command\n"); + exit 100; +} + +debug("Running ** $cmd ** $operation\n"); + +$dsbinroot="$dsroot{{SEP}}shared{{SEP}}bin"; +$ldapsearch="$dsbinroot{{SEP}}ldapsearch -1"; +$ldapmodify="$dsbinroot{{SEP}}ldapmodify"; + +# Default values +$defrootdn= "{{ROOT-DN}}"; +$defhost= "{{SERVER-NAME}}"; +$defport= "{{SERVER-PORT}}"; + +# User values +$rootdn= "{{ROOT-DN}}"; +$rootpw= ""; +$pwfile= ""; +$host= "{{SERVER-NAME}}"; +$port= "{{SERVER-PORT}}"; +$entry= ""; + +$single=0; +$role=0; + +chdir("$dsbinroot"); + +# Process the command line arguments +while( $arg = shift) +{ + if($arg eq "-?") + { + usage_and_exit(); + } + elsif($arg eq "-D") + { + $rootdn= shift @ARGV; + } + elsif($arg eq "-w") + { + $rootpw= shift @ARGV; + } + elsif($arg eq "-j") + { + $pwfile= shift @ARGV; + } + elsif($arg eq "-p") + { + $port= shift @ARGV; + } + elsif($arg eq "-h") + { + $host= shift @ARGV; + } + elsif($arg eq "-I") + { + $entry= shift @ARGV; + } + else + { + print "$arg: Unknown command line argument.\n"; + usage_and_exit(); + } +} + +if ($pwfile ne ""){ +# Open file and get the password + unless (open (RPASS, $pwfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $rootpw = <RPASS>; + chomp($rootpw); + close(RPASS); +} elsif ($rootpw eq "-"){ +# Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; +# Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $rootpw = ReadLine(0); +# chomp($rootpw); +# ReadMode('normal'); +} + +if( $rootpw eq "" ) +{ + usage_and_exit(); +} + +if( $entry eq "" ) +{ + usage_and_exit(); +} + +# +# Check the actual existence of the entry to inactivate/activate +# and at the same time, validate the various parm: port, host, rootdn, rootpw +# +@exist=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(objectclass=*)\" dn`; +$retCode1=$?; +if ( $retCode1 != 0 ) +{ + $retCode1=$?>>8; + exit $retCode1; +} + +@isRole=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(&(objectclass=LDAPsubentry)(objectclass=nsRoleDefinition))\" dn`; +$nbLineRole=@isRole; +$retCode2=$?; +if ( $retCode2 != 0 ) +{ + $retCode2=$?>>8; + exit $retCode2; +} + +if ( $nbLineRole == 1 ) +{ + debug("Groups of users\n"); + $role=1; +} +else +{ + debug("Single user\n"); + $single=1; +} + +# +# First of all, check the existence of the nsaccountlock attribute in the entry +# +$isLocked=0; +if ( $single == 1 ) +{ + $searchAccountLock="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(objectclass=*)\" nsaccountlock"; + open (LDAP1, "$searchAccountLock |"); + while (<LDAP1>) { + s/\n //g; + if (/^nsaccountlock: (.*)\n/) { + $L_currentvalue = $1; + $L_currentvalue=~ tr/A-Z/a-z/; + if ( $L_currentvalue eq "true") + { + $isLocked=1; + } + elsif ( $L_currentvalue eq "false" ) + { + $isLocked=0; + } + } + } + close(LDAP1); +} +debug("Is the entry already locked? ==> $isLocked\n"); + +# +# Get the suffix name of that entry +# + +# Remove the space at the beginning (just in case...) +# -I "uid=jvedder , ou=People , o=sun.com" +@suffix=split /([,])/,$entry; +$result=""; +foreach $part (@suffix) +{ + $part=~s/^ +//; + $part=~ tr/A-Z/a-z/; + $result="$result$part"; +} +@suffixN=$result; + +debug("Entry to $operation: #@suffix#\n"); +debug("Entry to $operation: #@suffixN#\n"); + +# Get the suffix +$cont=0; +while ($cont == 0) +{ + # Look if suffix is the suffix of the entry + # ldapsearch -s one -b "cn=mapping tree,cn=config" "cn=\"uid=jvedder,ou=People,o=sun.com\"" + # + debug("\tSuffix from the entry: #@suffixN#\n"); + @mapping=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s one -b \"cn=mapping tree, cn=config\" \"cn=\\"@suffixN\\"\" cn `; + + $retCode=$?; + if ( $retCode != 0 ) + { + $retCode=$?>>8; + exit $retCode; + } + + # If we get a result, remove the dn: + # dn: cn="o=sun.com",cn=mapping tree,cn=config + # cn: "o=sun.com" + # + shift @mapping; + + foreach $res (@mapping) + { + # Break the string cn: "o=sun.com" into pieces + @cn= split(/ /,$res); + + # And remove the cn: part + shift @cn; + + # Now compare the suffix we extract from the mapping tree + # with the suffix derived from the entry + debug("\tSuffix from mapping tree: #@cn#\n"); + if ( @cn eq @suffixN ) { + debug("Found matching suffix\n"); + $cont=1; + } + } + + if ( $cont == 0 ) + { + # Remove the current rdn to try another suffix + shift @suffix; + + $result=""; + foreach $part (@suffix) + { + $part=~ s/^ +//; + $part=~ tr/A-Z/a-z/; + $result="$result$part"; + } + @suffixN=$result; + + debug("\t\tNothing found => go up one level in rdn #@suffix#\n"); + $len=@suffix; + if ( $len == 0 ) + { + debug("Can not find suffix. Problem\n"); + $cont=2; + } + } +} +if ( $cont == 2) +{ + out("Can not find suffix for entry $entry\n"); + exit 100; +} + +if ( $operation eq "inactivate" ) +{ + # + # Now that we have the suffix and we know if we deal with a single entry or + # a role, just try to create the COS and roles associated. + # + @base=( + "cn=nsManagedDisabledRole,@suffixN", + "cn=nsDisabledRole,@suffixN", + "cn=nsAccountInactivationTmp,@suffixN", + "\'cn=\"cn=nsDisabledRole,@suffixN\",cn=nsAccountInactivationTmp,@suffixN\'", + "cn=nsAccountInactivation_cos,@suffixN" ); + + $addrolescos="$ldapmodify -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -c -a >> {{DEV-NULL}} 2>&1 "; + @role1=( + "dn: cn=nsManagedDisabledRole,@suffixN\n", + "objectclass: LDAPsubentry\n", + "objectclass: nsRoleDefinition\n", + "objectclass: nsSimpleRoleDefinition\n", + "objectclass: nsManagedRoleDefinition\n", + "cn: nsManagedDisabledRole\n\n" ); + @role2=( + "dn: cn=nsDisabledRole,@suffixN\n", + "objectclass: top\n", + "objectclass: LDAPsubentry\n", + "objectclass: nsRoleDefinition\n", + "objectclass: nsComplexRoleDefinition\n", + "objectclass: nsNestedRoleDefinition\n", + "nsRoleDN: cn=nsManagedDisabledRole,@suffixN\n", + "cn: nsDisabledRole\n\n" ); + @cos1=( + "dn: cn=nsAccountInactivationTmp,@suffixN\n", + "objectclass: top\n", + "objectclass: nsContainer\n\n" ); + @cos2=( + "dn: cn=\"cn=nsDisabledRole,@suffixN\",cn=nsAccountInactivationTmp,@suffixN\n", + "objectclass: top\n", + "objectclass: extensibleObject\n", + "objectclass: costemplate\n", + "objectclass: ldapsubentry\n", + "cosPriority: 1\n", + "nsAccountLock: true\n\n" ); + @cos3=( + "dn: cn=nsAccountInactivation_cos,@suffixN\n", + "objectclass: top\n", + "objectclass: LDAPsubentry\n", + "objectclass: cosSuperDefinition\n", + "objectclass: cosClassicDefinition\n", + "cosTemplateDn: cn=nsAccountInactivationTmp,@suffixN\n", + "cosSpecifier: nsRole\n", + "cosAttribute: nsAccountLock operational\n\n" ); + + @all=(\@role1, \@role2, \@cos1, \@cos2, \@cos3); + + $i=0; + + foreach $current (@base) + { + debug("Creating $current ??\n"); + open(FD,"| $addrolescos "); + print FD @{$all[$i]}; + close(FD); + if ( $? != 0 ) + { + $retCode=$?>>8; + if ( $retCode == 68 ) + { + debug("Entry $current already exists, ignore error\n"); + } + else + { + # Probably a more serious problem. + # Exit with LDAP error + exit $retCode; + } + } + else + { + debug("Entry $current created\n"); + } + $i=$i+1; + } +} + +$skipManaged=0; +$skipDisabled=0; +$directLocked=0; + +$nsDisabledRole="cn=nsDisabledRole,@suffixN"; +$nsDisabledRole=~ tr/A-Z/a-z/; + +$nsManagedDisabledRole="cn=nsManagedDisabledRole,@suffixN"; +$nsManagedDisabledRole=~ tr/A-Z/a-z/; + +if ( $operation eq "inactivate" ) +{ + # Go through all the roles part of nsdisabledrole to check if the entry + # is a member of one of those roles + $ret=indirectLock("LDAP00", $entry, $nsDisabledRole); + if ( $ret == 0 ) + { + if ( $throughRole ne $nsDisabledRole && $throughRole ne $nsManagedDisabledRole ) + { + # indirect lock + out("$entry already $state through $throughRole.\n"); + } + else + { + # direct lock + out("$entry already $state.\n"); + } + exit 100; + } + elsif ( $isLocked == 1 ) + { + # the entry is not locked through a role, may be nsaccountlock is "hardcoded" ? + out("$entry already $state (probably directly).\n"); + exit 103; + } +} +elsif ( $operation eq "activate" || $operation eq "get status of" ) +{ + $skipManaged=$single; + $skipDisabled=$role; + + $ret=indirectLock("LDAP00",$entry, $nsDisabledRole); + + if ( $ret == 0 ) + { + # undirectly locked + if ( $throughRole ne $nsDisabledRole && $throughRole ne $nsManagedDisabledRole ) + { + if ( $operation eq "activate" ) + { + out("$entry inactivated through $throughRole. Can not activate it individually.\n"); + exit 100; + } + else + { + out("$entry inactivated through $throughRole.\n"); + exit 104; + } + } + debug("$entry locked individually\n"); + + if ( $operation ne "activate" ) + { + out("$entry inactivated.\n"); + exit 103; + } + } + elsif ( $directLocked == 0 ) + { + if ( $operation eq "activate" && $isLocked != 1 ) + { + out("$entry $already $state.\n"); + exit 100; + } + elsif ( $isLocked != 1 ) + { + out("$entry $already $state.\n"); + exit 102; + } + else + { + # not locked using our schema, but nsaccountlock is probably present + out("$entry inactivated (probably directly).\n"); + exit 103; + } + } + elsif ( $operation ne "activate" ) + { + out("$entry inactivated.\n"); + exit 103; + } + # else Locked directly, juste unlock it! + debug("$entry locked individually\n"); +} + +# +# Inactivate/activate the entry +# +$action="$ldapmodify -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -c >> {{DEV-NULL}} 2>&1"; +if ( $single == 1 ) +{ + @record=( + "dn: $entry\n", + "changetype: modify\n", + "$modrole: nsRoleDN\n", + "nsRoleDN: cn=nsManagedDisabledRole,@suffixN\n\n" ); +} +else +{ + @record=( + "dn: cn=nsDisabledRole,@suffixN\n", + "changetype: modify\n", + "$modrole: nsRoleDN\n", + "nsRoleDN: $entry\n\n" ); +} +open(FD,"| $action "); +print FD @record; +close(FD); +if ( $? != 0 ) +{ +debug("$modrole, $entry\n"); + $retCode=$?>>8; + exit $retCode; +} + +out("$entry $state.\n"); +exit 0; diff --git a/ldap/admin/src/scripts/template-ns-inactivate.pl b/ldap/admin/src/scripts/template-ns-inactivate.pl new file mode 100644 index 00000000..5913f7ad --- /dev/null +++ b/ldap/admin/src/scripts/template-ns-inactivate.pl @@ -0,0 +1,813 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +############################### +# SUB-ROUTINES +############################### + +sub usage_and_exit +{ + print (STDERR "$cmd [-D rootdn] { -w password | -w - | -j filename } \n"); + print (STDERR " [-p port] [-h host] -I DN-to-$operation\n\n"); + print (STDERR "May be used to $operation a user or a domain of users\n\n"); + print (STDERR "Arguments:\n"); + print (STDERR " -? - help\n"); + print (STDERR " -D rootdn - Provide a Directory Manager DN. Default= '$defrootdn'\n"); + print (STDERR " -w password - Provide a password for the Directory Manager DN\n"); + print (STDERR " -w - - Prompt for the Directory Manager's password\n"); + print (STDERR " -j filename - Read the Directory Manager's password from file\n"); + print (STDERR " -p port - Provide a port. Default= '$defport'\n"); + print (STDERR " -h host - Provide a host name. Default= '$defhost'\n"); + print (STDERR " -I DN-to-$operation - Single entry DN or role DN to $operation\n"); + exit 100; +} + +sub debug +{ +# print " ==> @_"; +} + +sub out +{ + print "@_"; +} + +# -------------------------- +# Check if the entry is part of a locked role: +# i.e.: for each role member (nsroledn) of nsdisabledrole, check if +# * it is the same as the entry +# * the entry is member of role (==has nsroledn attributes), compare each of +# them with the nsroledn of nsdisabledrole +# * if nsroledn of nsdisabledrole are complex, go through each of them +# argv[0] is the local file handler +# argv[1] is the entry (may be a single entry DN or a role DN) +# argv[2] is the base for the search +# -------------------------- + +$throughRole=""; + +sub indirectLock +{ + # For recursivity, file handler must be local + my $L_filehandle=$_[0]; + $L_filehandle++; + + my $L_entry=$_[1]; + # Remove useless space + my @L_intern=split /([,])/,$L_entry; + my $L_result=""; + foreach $L_part (@L_intern) + { + $L_part=~s/^ +//; + $L_part=~ tr/A-Z/a-z/; + $L_result="$L_result$L_part"; + } + $L_entry=$L_result; + + my $L_base=$_[2]; + + my $L_search; + my $L_currentrole; + my $L_retCode; + + my $L_local; + +`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsroledn >> {{DEV-NULL}} 2>&1 `; +$retCode=$?; +if ( $retCode != 0 ) +{ + $retCode=$?>>8; + return 1; +} + + # Check if the role is a nested role + @L_Nested="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=nsNestedRoleDefinition)(objectclass=ldapsubentry))\" "; + # L_isNested == 1 means that we are going through a nested role, so for each member of that + # nested role, check that the member is below the scope of the nested + $L_isNested=@L_Nested; + + # Not Direct Lock, Go through roles if any + $L_search="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsroledn "; + + debug("\t-->indirectLock: check if $L_entry is part of a locked role from base $L_base\n\n"); + + unless (open ($L_filehandle, "$L_search |")) + { + out("Can't open file $L_filehandle\n"); + exit; + } + while (<$L_filehandle>) { + + s/\n //g; + if (/^nsroledn: (.*)\n/) { + $L_currentrole = $1; + + # Remove useless space + my @L_intern=split /([,])/,$L_currentrole; + my $L_result=""; + foreach $L_part (@L_intern) + { + $L_part=~s/^ +//; + $L_part=~ tr/A-Z/a-z/; + $L_result="$L_result$L_part"; + } + $L_currentrole=$L_result; + + debug("\t-- indirectLock loop: current nsroledn $L_currentrole of base $L_base\n"); + if ( $L_isNested == 1 ) + { + if ( checkScope($L_currentrole, $L_base) == 0 ) + { + # Scope problem probably a bad conf, skip the currentrole + next; + } + } + + if ( $L_currentrole eq $L_entry ) + { + # the entry is a role that is directly locked + # i.e, nsroledn of nsdisabledrole contains the entry + $throughRole=$L_base; + $throughRole=~ tr/A-Z/a-z/; + + # skipDisabled means that we've just found that the entry (which is a role) + # is locked directly (==its DN is part of nsroledn attributes) + # we just want to know now, if it is locked through another role + # at least, one + if ( $skipDisabled == 1 ) + { + # direct inactivation + $directLocked=1; + # just go through that test once + $skipDisabled=0; + next; + } + debug("\t-- 1 indirectLock: $L_currentrole locked throughRole == $throughRole\n"); + return 0; + } + + $L_retCode=memberOf($L_currentrole, $L_entry); + if ( $L_retCode == 0 && $single == 1 ) + { + $throughRole=$L_currentrole; + $throughRole=~ tr/A-Z/a-z/; + if ( $skipManaged == 1 ) + { + if ( $L_currentrole eq $nsManagedDisabledRole) + { + # Try next nsroledn + $directLocked=1; + $skipManaged=0; + next; + } + } + debug("\t-- 2 indirectLock: $L_currentrole locked throughRole == $throughRole\n"); + return 0; + } + + # Only for the first iteration + # the first iteration is with nsdisabledrole as base, other + # loops are deeper + $L_local=$skipDisabled; + $skipDisabled=0; + + # the current nsroledn may be a complex role, just go through + # its won nsroledn + $L_retCode=indirectLock($L_filehandle,$L_entry, $L_currentrole); + + # Because of recursivity, to keep the initial value for the first level + $skipDisabled=$L_local; + + if ( $L_retCode == 0 ) + { + $throughRole=$L_currentrole; + $throughRole=~ tr/A-Z/a-z/; + debug("\t-- 3 indirectLock: $L_entry locked throughRole == $throughRole\n"); + return 0; + } + } + } + + close($L_filehandle); + + debug("\t<--indirectLock: no more nsroledn to process\n"); + return 1; +} + +# -------------------------- +# Check if nsroledn is part of the entry attributes +# argv[0] is a role DN (nsroledn attribute) +# argv[1] is the entry +# -------------------------- +sub memberOf +{ + my $L_nsroledn=$_[0]; + $L_nsroledn=~ tr/A-Z/a-z/; + + my $L_entry=$_[1]; + + my $L_search; + my $L_currentrole; + + $L_search="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_entry\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsrole"; + + debug("\t\t-->memberOf: $L_search: check if $L_entry has $L_nsroledn as nsroledn attribute\n"); + + open (LDAP2, "$L_search |"); + while (<LDAP2>) { + s/\n //g; + if (/^nsrole: (.*)\n/) { + $L_currentrole = $1; + $L_currentrole=~ tr/A-Z/a-z/; + if ( $L_currentrole eq $L_nsroledn ) + { + # the parm is part of the $L_entry nsroledn + debug("\t\t<--memberOf: $L_entry locked through $L_nsroledn\n"); + return 0; + } + } + } + close(LDAP2); + + # the parm is not part of the $L_entry nsroledn + debug("\t\t<--memberOf: $L_entry not locked through $L_nsroledn\n"); + return 1; +} + + +# -------------------------- +# Remove the rdn of a DN +# argv[0] is a DN +# -------------------------- +sub removeRdn +{ + $L_entry=$_[0]; + + @L_entryToTest=split /([,])/,$L_entry; + debug("removeRdn: entry to split: $L_entry**@L_entryToTest\n"); + + $newDN=""; + $removeRDN=1; + foreach $part (@L_entryToTest) + { + $part=~ s/^ +//; + $part=~ tr/A-Z/a-z/; + if ( $removeRDN <= 2 ) + { + $removeRDN=$removeRDN+1; + } + else + { + $newDN="$newDN$part"; + } + } + + debug("removeRdn: new DN **$newDN**\n"); +} + +# -------------------------- +# Check if L_current is below the scope of +# L_nestedRole +# argv[0] is a role +# argv[1] is the nested role +# -------------------------- +sub checkScope +{ + $L_current=$_[0]; + $L_nestedRole=$_[1]; + + debug("checkScope: check if $L_current is below $L_nestedRole\n"); + + removeRdn($L_nestedRole); + $L_nestedRoleSuffix=$newDN; + debug("checkScope: nested role based: $L_nestedRoleSuffix\n"); + + $cont=1; + while ( ($cont == 1) && ($L_current ne "") ) + { + removeRdn($L_current); + $currentDn=$newDN; + debug("checkScope: current DN to check: $currentDn\n"); + + if ( $currentDn eq $L_nestedRoleSuffix ) + { + debug("checkScope: DN match!!!\n"); + $cont = 0; + } + else + { + $L_current=$currentDn; + } + } + + if ( $cont == 1 ) + { + debug("checkScope: $_[0] and $_[1] are not compatible\n"); + return 0; + } + else + { + debug("checkScope: $_[0] and $_[1] are compatible\n"); + return 1; + } +} + + +############################### +# MAIN ROUTINE +############################### + +# Generated variable +$dsroot="{{DS-ROOT}}"; + +# Determine which command we are running +if ( $0 =~ /ns-inactivate(.pl)?$/ ) +{ + $cmd="ns-inactivate.pl"; + $operation="inactivate"; + $state="inactivated"; + $modrole="add"; + $already="already"; +} +elsif ( $0 =~ /ns-activate(.pl)?$/ ) +{ + $cmd="ns-activate.pl"; + $operation="activate"; + $state="activated"; + $modrole="delete"; + $already="already"; +} +elsif ( $0 =~ /ns-accountstatus(.pl)?$/ ) +{ + $cmd="ns-accountstatus.pl"; + $operation="get status of"; + $state="activated"; + # no need for $modrole as no operation is performed + $already=""; + +} +else +{ + out("$0: unknown command\n"); + exit 100; +} + +debug("Running ** $cmd ** $operation\n"); + +$dsbinroot="$dsroot{{SEP}}shared{{SEP}}bin"; +$ldapsearch="$dsbinroot{{SEP}}ldapsearch -1"; +$ldapmodify="$dsbinroot{{SEP}}ldapmodify"; + +# Default values +$defrootdn= "{{ROOT-DN}}"; +$defhost= "{{SERVER-NAME}}"; +$defport= "{{SERVER-PORT}}"; + +# User values +$rootdn= "{{ROOT-DN}}"; +$rootpw= ""; +$pwfile= ""; +$host= "{{SERVER-NAME}}"; +$port= "{{SERVER-PORT}}"; +$entry= ""; + +$single=0; +$role=0; + +chdir("$dsbinroot"); + +# Process the command line arguments +while( $arg = shift) +{ + if($arg eq "-?") + { + usage_and_exit(); + } + elsif($arg eq "-D") + { + $rootdn= shift @ARGV; + } + elsif($arg eq "-w") + { + $rootpw= shift @ARGV; + } + elsif($arg eq "-j") + { + $pwfile= shift @ARGV; + } + elsif($arg eq "-p") + { + $port= shift @ARGV; + } + elsif($arg eq "-h") + { + $host= shift @ARGV; + } + elsif($arg eq "-I") + { + $entry= shift @ARGV; + } + else + { + print "$arg: Unknown command line argument.\n"; + usage_and_exit(); + } +} + +if ($pwfile ne ""){ +# Open file and get the password + unless (open (RPASS, $pwfile)) { + die "Error, cannot open password file $passwdfile\n"; + } + $rootpw = <RPASS>; + chomp($rootpw); + close(RPASS); +} elsif ($rootpw eq "-"){ +# Read the password from terminal + die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n", + "part of the standard perl distribution. If you want to use it, you must\n", + "download and install the module. You can find it at\n", + "http://www.perl.com/CPAN/CPAN.html\n"; +# Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module. +# use Term::ReadKey; +# print "Bind Password: "; +# ReadMode('noecho'); +# $rootpw = ReadLine(0); +# chomp($rootpw); +# ReadMode('normal'); +} + +if( $rootpw eq "" ) +{ + usage_and_exit(); +} + +if( $entry eq "" ) +{ + usage_and_exit(); +} + +# +# Check the actual existence of the entry to inactivate/activate +# and at the same time, validate the various parm: port, host, rootdn, rootpw +# +@exist=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(objectclass=*)\" dn`; +$retCode1=$?; +if ( $retCode1 != 0 ) +{ + $retCode1=$?>>8; + exit $retCode1; +} + +@isRole=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(&(objectclass=LDAPsubentry)(objectclass=nsRoleDefinition))\" dn`; +$nbLineRole=@isRole; +$retCode2=$?; +if ( $retCode2 != 0 ) +{ + $retCode2=$?>>8; + exit $retCode2; +} + +if ( $nbLineRole == 1 ) +{ + debug("Groups of users\n"); + $role=1; +} +else +{ + debug("Single user\n"); + $single=1; +} + +# +# First of all, check the existence of the nsaccountlock attribute in the entry +# +$isLocked=0; +if ( $single == 1 ) +{ + $searchAccountLock="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(objectclass=*)\" nsaccountlock"; + open (LDAP1, "$searchAccountLock |"); + while (<LDAP1>) { + s/\n //g; + if (/^nsaccountlock: (.*)\n/) { + $L_currentvalue = $1; + $L_currentvalue=~ tr/A-Z/a-z/; + if ( $L_currentvalue eq "true") + { + $isLocked=1; + } + elsif ( $L_currentvalue eq "false" ) + { + $isLocked=0; + } + } + } + close(LDAP1); +} +debug("Is the entry already locked? ==> $isLocked\n"); + +# +# Get the suffix name of that entry +# + +# Remove the space at the beginning (just in case...) +# -I "uid=jvedder , ou=People , o=sun.com" +@suffix=split /([,])/,$entry; +$result=""; +foreach $part (@suffix) +{ + $part=~s/^ +//; + $part=~ tr/A-Z/a-z/; + $result="$result$part"; +} +@suffixN=$result; + +debug("Entry to $operation: #@suffix#\n"); +debug("Entry to $operation: #@suffixN#\n"); + +# Get the suffix +$cont=0; +while ($cont == 0) +{ + # Look if suffix is the suffix of the entry + # ldapsearch -s one -b "cn=mapping tree,cn=config" "cn=\"uid=jvedder,ou=People,o=sun.com\"" + # + debug("\tSuffix from the entry: #@suffixN#\n"); + @mapping=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s one -b \"cn=mapping tree, cn=config\" \"cn=\\"@suffixN\\"\" cn `; + + $retCode=$?; + if ( $retCode != 0 ) + { + $retCode=$?>>8; + exit $retCode; + } + + # If we get a result, remove the dn: + # dn: cn="o=sun.com",cn=mapping tree,cn=config + # cn: "o=sun.com" + # + shift @mapping; + + foreach $res (@mapping) + { + # Break the string cn: "o=sun.com" into pieces + @cn= split(/ /,$res); + + # And remove the cn: part + shift @cn; + + # Now compare the suffix we extract from the mapping tree + # with the suffix derived from the entry + debug("\tSuffix from mapping tree: #@cn#\n"); + if ( @cn eq @suffixN ) { + debug("Found matching suffix\n"); + $cont=1; + } + } + + if ( $cont == 0 ) + { + # Remove the current rdn to try another suffix + shift @suffix; + + $result=""; + foreach $part (@suffix) + { + $part=~ s/^ +//; + $part=~ tr/A-Z/a-z/; + $result="$result$part"; + } + @suffixN=$result; + + debug("\t\tNothing found => go up one level in rdn #@suffix#\n"); + $len=@suffix; + if ( $len == 0 ) + { + debug("Can not find suffix. Problem\n"); + $cont=2; + } + } +} +if ( $cont == 2) +{ + out("Can not find suffix for entry $entry\n"); + exit 100; +} + +if ( $operation eq "inactivate" ) +{ + # + # Now that we have the suffix and we know if we deal with a single entry or + # a role, just try to create the COS and roles associated. + # + @base=( + "cn=nsManagedDisabledRole,@suffixN", + "cn=nsDisabledRole,@suffixN", + "cn=nsAccountInactivationTmp,@suffixN", + "\'cn=\"cn=nsDisabledRole,@suffixN\",cn=nsAccountInactivationTmp,@suffixN\'", + "cn=nsAccountInactivation_cos,@suffixN" ); + + $addrolescos="$ldapmodify -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -c -a >> {{DEV-NULL}} 2>&1 "; + @role1=( + "dn: cn=nsManagedDisabledRole,@suffixN\n", + "objectclass: LDAPsubentry\n", + "objectclass: nsRoleDefinition\n", + "objectclass: nsSimpleRoleDefinition\n", + "objectclass: nsManagedRoleDefinition\n", + "cn: nsManagedDisabledRole\n\n" ); + @role2=( + "dn: cn=nsDisabledRole,@suffixN\n", + "objectclass: top\n", + "objectclass: LDAPsubentry\n", + "objectclass: nsRoleDefinition\n", + "objectclass: nsComplexRoleDefinition\n", + "objectclass: nsNestedRoleDefinition\n", + "nsRoleDN: cn=nsManagedDisabledRole,@suffixN\n", + "cn: nsDisabledRole\n\n" ); + @cos1=( + "dn: cn=nsAccountInactivationTmp,@suffixN\n", + "objectclass: top\n", + "objectclass: nsContainer\n\n" ); + @cos2=( + "dn: cn=\"cn=nsDisabledRole,@suffixN\",cn=nsAccountInactivationTmp,@suffixN\n", + "objectclass: top\n", + "objectclass: extensibleObject\n", + "objectclass: costemplate\n", + "objectclass: ldapsubentry\n", + "cosPriority: 1\n", + "nsAccountLock: true\n\n" ); + @cos3=( + "dn: cn=nsAccountInactivation_cos,@suffixN\n", + "objectclass: top\n", + "objectclass: LDAPsubentry\n", + "objectclass: cosSuperDefinition\n", + "objectclass: cosClassicDefinition\n", + "cosTemplateDn: cn=nsAccountInactivationTmp,@suffixN\n", + "cosSpecifier: nsRole\n", + "cosAttribute: nsAccountLock operational\n\n" ); + + @all=(\@role1, \@role2, \@cos1, \@cos2, \@cos3); + + $i=0; + + foreach $current (@base) + { + debug("Creating $current ??\n"); + open(FD,"| $addrolescos "); + print FD @{$all[$i]}; + close(FD); + if ( $? != 0 ) + { + $retCode=$?>>8; + if ( $retCode == 68 ) + { + debug("Entry $current already exists, ignore error\n"); + } + else + { + # Probably a more serious problem. + # Exit with LDAP error + exit $retCode; + } + } + else + { + debug("Entry $current created\n"); + } + $i=$i+1; + } +} + +$skipManaged=0; +$skipDisabled=0; +$directLocked=0; + +$nsDisabledRole="cn=nsDisabledRole,@suffixN"; +$nsDisabledRole=~ tr/A-Z/a-z/; + +$nsManagedDisabledRole="cn=nsManagedDisabledRole,@suffixN"; +$nsManagedDisabledRole=~ tr/A-Z/a-z/; + +if ( $operation eq "inactivate" ) +{ + # Go through all the roles part of nsdisabledrole to check if the entry + # is a member of one of those roles + $ret=indirectLock("LDAP00", $entry, $nsDisabledRole); + if ( $ret == 0 ) + { + if ( $throughRole ne $nsDisabledRole && $throughRole ne $nsManagedDisabledRole ) + { + # indirect lock + out("$entry already $state through $throughRole.\n"); + } + else + { + # direct lock + out("$entry already $state.\n"); + } + exit 100; + } + elsif ( $isLocked == 1 ) + { + # the entry is not locked through a role, may be nsaccountlock is "hardcoded" ? + out("$entry already $state (probably directly).\n"); + exit 103; + } +} +elsif ( $operation eq "activate" || $operation eq "get status of" ) +{ + $skipManaged=$single; + $skipDisabled=$role; + + $ret=indirectLock("LDAP00",$entry, $nsDisabledRole); + + if ( $ret == 0 ) + { + # undirectly locked + if ( $throughRole ne $nsDisabledRole && $throughRole ne $nsManagedDisabledRole ) + { + if ( $operation eq "activate" ) + { + out("$entry inactivated through $throughRole. Can not activate it individually.\n"); + exit 100; + } + else + { + out("$entry inactivated through $throughRole.\n"); + exit 104; + } + } + debug("$entry locked individually\n"); + + if ( $operation ne "activate" ) + { + out("$entry inactivated.\n"); + exit 103; + } + } + elsif ( $directLocked == 0 ) + { + if ( $operation eq "activate" && $isLocked != 1 ) + { + out("$entry $already $state.\n"); + exit 100; + } + elsif ( $isLocked != 1 ) + { + out("$entry $already $state.\n"); + exit 102; + } + else + { + # not locked using our schema, but nsaccountlock is probably present + out("$entry inactivated (probably directly).\n"); + exit 103; + } + } + elsif ( $operation ne "activate" ) + { + out("$entry inactivated.\n"); + exit 103; + } + # else Locked directly, juste unlock it! + debug("$entry locked individually\n"); +} + +# +# Inactivate/activate the entry +# +$action="$ldapmodify -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -c >> {{DEV-NULL}} 2>&1"; +if ( $single == 1 ) +{ + @record=( + "dn: $entry\n", + "changetype: modify\n", + "$modrole: nsRoleDN\n", + "nsRoleDN: cn=nsManagedDisabledRole,@suffixN\n\n" ); +} +else +{ + @record=( + "dn: cn=nsDisabledRole,@suffixN\n", + "changetype: modify\n", + "$modrole: nsRoleDN\n", + "nsRoleDN: $entry\n\n" ); +} +open(FD,"| $action "); +print FD @record; +close(FD); +if ( $? != 0 ) +{ +debug("$modrole, $entry\n"); + $retCode=$?>>8; + exit $retCode; +} + +out("$entry $state.\n"); +exit 0; diff --git a/ldap/admin/src/scripts/template-ns-newpwpolicy.pl b/ldap/admin/src/scripts/template-ns-newpwpolicy.pl new file mode 100755 index 00000000..dd57c944 --- /dev/null +++ b/ldap/admin/src/scripts/template-ns-newpwpolicy.pl @@ -0,0 +1,241 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# Add new password policy specific entries + +############################################################################# +# enable the use of Perldap functions +require DynaLoader; + +use Getopt::Std; +use Mozilla::LDAP::Conn; +use Mozilla::LDAP::Utils qw(:all); +use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API + +############################################################################# +# Default values of the variables + +$opt_D = "{{ROOT-DN}}"; +$opt_p = "{{SERVER-PORT}}"; +$opt_h = "{{SERVER-NAME}}"; +$opt_v = 0; + +# Variables +$ldapsearch="{{DS-ROOT}}{{SEP}}shared{{SEP}}bin{{SEP}}ldapsearch"; +$ldapmodify="{{DS-ROOT}}{{SEP}}shared{{SEP}}bin{{SEP}}ldapmodify"; + +chdir("{{DS-ROOT}}{{SEP}}shared{{SEP}}bin"); + +############################################################################# + +sub usage { + print (STDERR "ns-newpwpolicy.pl [-v] [-D rootdn] { -w password | -j filename } \n"); + print (STDERR " [-p port] [-h host] -U UserDN -S SuffixDN\n\n"); + + print (STDERR "Arguments:\n"); + print (STDERR " -? - help\n"); + print (STDERR " -v - verbose output\n"); + print (STDERR " -D rootdn - Directory Manager DN. Default= '$opt_D'\n"); + print (STDERR " -w rootpw - password for the Directory Manager DN\n"); + print (STDERR " -j filename - Read the Directory Manager's password from file\n"); + print (STDERR " -p port - port. Default= $opt_p\n"); + print (STDERR " -h host - host name. Default= '$opt_h'\n"); + print (STDERR " -U userDN - User entry DN\n"); + print (STDERR " -S suffixDN - Suffix entry DN\n"); + exit 100; +} + +# Process the command line arguments +{ + usage() if (!getopts('vD:w:j:p:h:U:S:')); + + if ($opt_j ne ""){ + die "Error, cannot open password file $opt_j\n" unless (open (RPASS, $opt_j)); + $opt_w = <RPASS>; + chomp($opt_w); + close(RPASS); + } + + usage() if( $opt_w eq "" ); + if ($opt_U eq "" && $opt_S eq "") { + print (STDERR "Please provide at least -S or -U option.\n\n"); + } + + # Now, check if the user/group exists + + if ($opt_S) { + print (STDERR "host = $opt_h, port = $opt_p, suffixDN = \"$opt_S\"\n\n") if $opt_v; + @base=( + "cn=nsPwPolicyContainer,$opt_S", + "cn=\"cn=nsPwPolicyEntry,$opt_S\",cn=nsPwPolicyContainer,$opt_S", + "cn=\"cn=nsPwTemplateEntry,$opt_S\",cn=nsPwPolicyContainer,$opt_S", + "cn=nsPwPolicy_cos,$opt_S" + ); + + $ldapadd="$ldapmodify -p $opt_p -h $opt_h -D \"$opt_D\" -w \"$opt_w\" -c -a 2>&1"; + $modifyCfg="$ldapmodify -p $opt_p -h $opt_h -D \"$opt_D\" -w \"$opt_w\" -c 2>&1"; + + @container=( + "dn: cn=nsPwPolicyContainer,$opt_S\n", + "objectclass: top\n", + "objectclass: nsContainer\n\n" ); + @pwpolicy=( + "dn: cn=\"cn=nsPwPolicyEntry,$opt_S\",cn=nsPwPolicyContainer,$opt_S\n", + "objectclass: top\n", + "objectclass: ldapsubentry\n", + "objectclass: passwordpolicy\n\n" ); + @template=( + "dn: cn=\"cn=nsPwTemplateEntry,$opt_S\",cn=nsPwPolicyContainer,$opt_S\n", + "objectclass: top\n", + "objectclass: extensibleObject\n", + "objectclass: costemplate\n", + "objectclass: ldapsubentry\n", + "cosPriority: 1\n", + "pwdpolicysubentry: cn=\"cn=nsPwPolicyEntry,$opt_S\",cn=nsPwPolicyContainer,$opt_S\n\n" ); + @cos=( + "dn: cn=nsPwPolicy_cos,$opt_S\n", + "objectclass: top\n", + "objectclass: LDAPsubentry\n", + "objectclass: cosSuperDefinition\n", + "objectclass: cosPointerDefinition\n", + "cosTemplateDn: cn=\"cn=nsPwTemplateEntry,$opt_S\",cn=nsPwPolicyContainer,$opt_S\n", + "cosAttribute: pwdpolicysubentry default operational-default\n\n" ); + + @all=(\@container, \@pwpolicy, \@template, \@cos); + + $i=0; + + foreach $current (@base) + { + open(FD,"| $ldapadd"); + print FD @{$all[$i]}; + close(FD); + if ( $? != 0 ) { + $retCode=$?>>8; + if ( $retCode == 68 ) { + print( STDERR "Entry \"$current\" already exists. Please ignore the error\n\n"); + } + else { + # Probably a more serious problem. + # Exit with LDAP error + print(STDERR "Error $retcode while adding \"$current\". Exiting.\n"); + exit $retCode; + } + } + else { + print( STDERR "Entry \"$current\" created\n\n") if $opt_v; + } + $i=$i+1; + } + + $modConfig = "dn:cn=config\nchangetype: modify\nreplace:nsslapd-pwpolicy-local\nnsslapd-pwpolicy-local: on\n\n"; + open(FD,"| $modifyCfg "); + print(FD $modConfig); + close(FD); + $retcode = $?; + if ( $retcode != 0 ) { + print( STDERR "Error $retcode while modifing \"cn=config\". Exiting.\n" ); + exit ($retcode); + } + else { + print( STDERR "Entry \"cn=config\" modified\n\n") if $opt_v; + } + } # end of $opt_S + + if ($opt_U) { + my $norm_opt_U = normalizeDN($opt_U); + print (STDERR "host = $opt_h, port = $opt_p, userDN = \"$norm_opt_U\"\n\n") if $opt_v; + $retcode = `$ldapsearch -h $opt_h -p $opt_p -b \"$norm_opt_U\" -s base \"\"`; + if ($retcode != 0 ) { + print( STDERR "the user entry $norm_opt_U does not exist. Exiting.\n"); + exit ($retcode); + } + + print( STDERR "the user entry $norm_opt_U found..\n\n") if $opt_v; + + # Now, get the parentDN + @rdns = ldap_explode_dn($norm_opt_U, 0); + shift @rdns; + $parentDN = join(',', @rdns); + + print (STDERR "parentDN is $parentDN\n\n") if $opt_v; + + @base=( + "cn=nsPwPolicyContainer,$parentDN", + "cn=\"cn=nsPwPolicyEntry,$norm_opt_U\",cn=nsPwPolicyContainer,$parentDN" + ); + + $ldapadd="$ldapmodify -p $opt_p -h $opt_h -D \"$opt_D\" -w \"$opt_w\" -c -a 2>&1"; + $modifyCfg="$ldapmodify -p $opt_p -h $opt_h -D \"$opt_D\" -w \"$opt_w\" -c 2>&1"; + + @container=( + "dn: cn=nsPwPolicyContainer,$parentDN\n", + "objectclass: top\n", + "objectclass: nsContainer\n\n" ); + @pwpolicy=( + "dn: cn=\"cn=nsPwPolicyEntry,$norm_opt_U\",cn=nsPwPolicyContainer,$parentDN\n", + "objectclass: top\n", + "objectclass: ldapsubentry\n", + "objectclass: passwordpolicy\n\n" ); + + @all=(\@container, \@pwpolicy); + + $i=0; + + foreach $current (@base) + { + open(FD,"| $ldapadd "); + print FD @{$all[$i]}; + close(FD); + if ( $? != 0 ) { + $retCode=$?>>8; + if ( $retCode == 68 ) { + print( STDERR "Entry $current already exists. Please ignore the error\n\n"); + } + else { + # Probably a more serious problem. + # Exit with LDAP error + print(STDERR "Error $retcode while adding \"$current\". Exiting.\n"); + exit $retCode; + } + } + else { + print( STDERR "Entry $current created\n\n") if $opt_v; + } + $i=$i+1; + } + + $target = "cn=\"cn=nsPwPolicyEntry,$norm_opt_U\",cn=nsPwPolicyContainer,$parentDN"; + $modConfig = "dn: $norm_opt_U\nchangetype: modify\nreplace:pwdpolicysubentry\npwdpolicysubentry: $target\n\n"; + open(FD,"| $modifyCfg "); + print(FD $modConfig); + close(FD); + $retcode = $?; + if ( $retcode != 0 ) { + print( STDERR "Error $retcode while modifing $norm_opt_U. Exiting.\n" ); + exit ($retcode); + } + else { + print( STDERR "Entry \"$norm_opt_U\" modified\n\n") if $opt_v; + } + + $modConfig = "dn:cn=config\nchangetype: modify\nreplace:nsslapd-pwpolicy-local\nnsslapd-pwpolicy-local: on\n\n"; + open(FD,"| $modifyCfg "); + print(FD $modConfig); + close(FD); + $retcode = $?; + if ( $retcode != 0 ) { + print( STDERR "Error $retcode while modifing \"cn=config\". Exiting.\n" ); + exit ($retcode); + } + else { + print( STDERR "Entry \"cn=config\" modified\n\n") if $opt_v; + } + } # end of $opt_U +} diff --git a/ldap/admin/src/scripts/template-repl-monitor-cgi.pl b/ldap/admin/src/scripts/template-repl-monitor-cgi.pl new file mode 100755 index 00000000..b9494d0d --- /dev/null +++ b/ldap/admin/src/scripts/template-repl-monitor-cgi.pl @@ -0,0 +1,40 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright (C) 2002-2004 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +use Cgi; + +$params = ""; +$params .= " -h $cgiVars{'servhost'}" if $cgiVars{'servhost'}; +$params .= " -p $cgiVars{'servport'}" if $cgiVars{'servport'}; +$params .= " -f $cgiVars{'configfile'}" if $cgiVars{'configfile'}; +$params .= " -t $cgiVars{'refreshinterval'}" if $cgiVars{'refreshinterval'}; +if ($cgiVars{'admurl'}) { + $admurl = "$cgiVars{'admurl'}"; + if ( $ENV{'QUERY_STRING'} ) { + $admurl .= "?$ENV{'QUERY_STRING'}"; + } + elsif ( $ENV{'CONTENT_LENGTH'} ) { + $admurl .= "?$Cgi::CONTENT"; + } + $params .= " -u \"$admurl\""; +} +$siteroot = $cgiVars{'siteroot'}; +$perl = "$siteroot/bin/slapd/admin/bin/perl"; +$ENV{'LD_LIBRARY_PATH'} = "$siteroot/lib:$siteroot/lib/nsPerl5.005_03/lib"; + +# Save user-specified parameters as cookies in monreplication.properties. +# Sync up with the property file so that monreplication2 is interval, and +# monreplication3 the config file pathname. +$propertyfile = "$siteroot/bin/admin/admin/bin/property/monreplication.properties"; +$edit1 = "s#monreplication2=.*#monreplication2=$cgiVars{'refreshinterval'}#;"; +$edit2 = "s#^monreplication3=.*#monreplication3=$cgiVars{'configfile'}#;"; +system("$perl -p -i.bak -e \"$edit1\" -e \"$edit2\" $propertyfile"); + +# Now the real work +$replmon = "$siteroot/bin/slapd/admin/scripts/template-repl-monitor.pl"; +system("$perl $replmon $params"); diff --git a/ldap/admin/src/scripts/template-repl-monitor.pl b/ldap/admin/src/scripts/template-repl-monitor.pl new file mode 100755 index 00000000..78e3aa85 --- /dev/null +++ b/ldap/admin/src/scripts/template-repl-monitor.pl @@ -0,0 +1,956 @@ +#{{PERL-EXEC}} + +############################################################################## +# +# Copyright (C) 2002-2004 Netscape Communications Corporation. +# All Rights Reserved. +# +# FILE: repl-monitor.pl +# +# SYNOPSIS: +# repl-monitor.pl -f configuration-file [-h host] [-p port] [-r] \ +# [-u refresh-url] [-t refresh-interval] +# +# repl-monitor.pl -v +# +# DESCRIPTION: +# Given an LDAP replication "supplier" server, crawl over all the ldap +# servers via direct or indirect replication agreements. +# For each master replica discovered, display the maxcsn of the master +# and the replication status of all its lower level replicas. +# All output is in HTML. +# +# OPTIONS: +# +# -f configuration-file +# The configuration file contains the sections for the connection +# parameters, the server alias, and the thresholds for different colors +# when display the time lags between consumers and master. +# If the Admin Server is running on Windows, the configuration-file +# name may have format "D:/Netscape/replmon.conf". +# +# The connection parameter section consists of the section name +# followed by one of more connection parameter entries: +# +# [connection] +# host:port:binddn:bindpwd:bindcert +# host:port=shadowport:binddn:bindpwd:bindcert +# ... +# +# where host:port default (*:*) to that in a replication agreement, +# binddn default (*) to "cn=Directory Manager", and bindcert is the +# pathname of cert db if you want the script to connect to the server +# via SSL. If bindcert is omitted, the connection will be simple +# bind. +# "port=shadowport" means to use shadowport instead of port if port +# is specified in the replication agreement. This is useful when +# for example, ssl port is specified in a replication agreement, +# but you can't access the cert db from the machine where this +# script is running. So you could let the script to map the ssl +# port to a non-ssl port and use the simple bind. +# +# A server may have a dedicated or a share entry in the connection +# section. The script will find out the most matched entry for a given +# server. For example, if all the ldap servers except host1 share the +# same binddn and bindpassword, the connection section then just need +# two entries: +# +# [connection] +# *:*:binddn:bindpassword: +# host1:*:binddn:bindpassword: +# +# If a host:port is assigned an alias, then the alias instead of +# host:port will be displayed in The output file. Each host:port +# can have only one alias. But each alias may be used by more than +# one host:port. +# +# [alias] +# alias = host:port +# ... +# +# CSN time lags between masters and consumers might be displayed in +# different colors based on their range. The thresholds for different +# colors may be specified in color section: +# +# [color] +# lowmark (in minutes) = color +# ... +# If the color section or color entry is missing, the default color +# set is: green for [0-5) minutes lag, yellow [5-60), and red 60 and more. +# +# -h host +# Initial replication supplier's host. Default to the current host. +# +# -p port +# Initial replication supplier's port. Default to 389. +# +# -r If specified, -r causes the routine to be entered without printing +# HTML header information. This is suitable when making multiple calls +# to this routine (e.g. when specifying multiple, different, "unrelated" +# supplier servers) and expecting a single HTML output. +# +# -t refresh-interval +# Specify the refresh interval in seconds. This option has to be +# jointly used with option -u. +# +# -u refresh-url +# The output HTML file may invoke a CGI program periodically. If +# this CGI program in turn calls this script, the effect is that +# the output HTML file would automatically refresh itself. This +# is useful for continuing monitoring. See also option -t. +# +# -v Print out the version of this script +# +# DIAGNOSTICS: +# There are several ways to invoke this script if you got error +# "Can't locate Mozilla/LDAP/Conn.pm in @INC", or +# "usage: Undefined variable": +# +# 1. Set the first line of the script to #!<DSHOME>/bin/slapd/admin/bin/perl +# and run this script directly. +# +# 2. Run +# <DSHOME>/bin/slapd/admin/bin/perl repl-monitor.pl +# +# 3. Set environment variable PERL5LIB to your Perl lib dirs where +# Mozilla::LDAP module can be located. +# +# 4. Invoke the script as follows if <MYPERLDIR>/lib/site contains +# Mozilla/LDAP: +# <MYPERLDIR>/bin/perl -I <MYPERLDIR>/lib/site repl-monitor.pl +# +# If you get error "Can't load ...", try to set environment variable +# for library path to <DSHOME>/lib:<DSHOME>/lib/nsPerl5.005_03/lib +# +############################################################################# +$usage = "\nusage: $0 -f configuration-file [-h host] [-p port] [-r] [-u refresh-url] [-t refresh-interval]\n\nor : $0 -v\n"; + +use Getopt::Std; # parse command line arguments +use Mozilla::LDAP::Conn; # LDAP module for Perl +use Mozilla::LDAP::Utils qw(normalizeDN); # LULU, utilities. +use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API +use Time::Local; # to convert GMT Z strings to localtime + +# +# Global variables +# +$product = "Netscape Directory Server Replication Monitor"; +$version = "Version 1.0"; +# +# ldap servers given or discovered from the replication agreements: +# @servers = (host:port=shadowport:binddn:password:cert_db) +# +# entries read from the connection section of the configuration file: +# @allconnections = (host:port=shadowport:binddn:password:cert_db) +# +# aliases of ldap servers read from the configuration file: +# %allaliases{$host:$port}= (alias) +# +# replicas discovered on all ldap servers +# @allreplicas = (server#:replicaroot:replicatype:serverid:replicadn) +# +# ruvs retrieved from all replicas +# @allruvs{replica#:masterid} = (rawcsn:decimalcsn;mon/day/year hh:mi:ss) +# +# agreements discovered on all ldap supplier servers: +# @allagreements = (supplier_replica#:consumer#:conntype:schedule:status) +# the array may take another format after the consumer replicas are located: +# @allagreements = (supplier_replica#:consumer_replica#:conntype:schedule:status) +# + +#main +{ + # turn off buffered I/O + $| = 1; + + # Check for legal options + if (!getopts('h:p:f:ru:t:v')) { + print $usage; + exit -1; + } + + if ($opt_v) { + print "$product - $version\n"; + exit; + } + + $interval = $opt_t; + $interval = 300 if ( !$interval || $interval <= 0 ); + + # Get current date/time + $nowraw = localtime(); + ($wday, $mm, $dd, $tt, $yy) = split(/ /, $nowraw); + $now = "$wday $mm $dd $yy $tt"; + + # if no -r (Reenter and skip html header), print html header + if (!$opt_r) { + # print the HTML header + &print_html_header; + } else { + # print separator for new replication set + print "<hr width=90% size=3><br>\n"; + } + + exit -1 if &validateArgs < 0; + exit if &read_cfg_file ($opt_f) < 0; + + # Start with the given host and port + # The index names in %ld are defined in Mozilla::LDAP::Utils::ldapArgs() + &add_server ("$ld{host}:$ld{port}:$ld{bind}:$ld{pswd}:$ld{cert}"); + + $serveridx = 0; + while ($serveridx <= $#servers) { + if (&get_replicas ($serveridx) != 0 && $serveridx == 0) { + my ($host, $port, $binddn) = split (/:/, $servers[0]); + print("Login to $host:$port as \"$binddn\" failed\n"); + exit; + } + $serveridx++; + } + + &find_consumer_replicas; + &process_suppliers; + + # All done! - well, for the current invokation only + # print "</body></html>\n"; + exit; +} + +sub validateArgs +{ + my ($rc) = 0; + + %ld = Mozilla::LDAP::Utils::ldapArgs(); + + if (!$opt_v && !$opt_f) { + print "<p>Error: Missing configuration file.\n"; + print "<p>If you need help on the configuration file, Please go back and click the Help button.\n"; + #print $usage; # Don't show usage in CGI + $rc = -1; + } + elsif (!$opt_h) { + chop ($ld{"host"} = `hostname`); + } + + return $rc; +} + +sub read_cfg_file +{ + my ($fn) = @_; + unless (open(CFGFILEHANDLE, $fn)) { + print "<p>Error: Can't open \"$fn\": $!.\n"; + print "<p>If you need help on the configuration file, Please go back and click the Help button.\n"; + return -1; + } + $section = 0; + while (<CFGFILEHANDLE>) { + next if (/^\s*\#/ || /^\s*$/); + chop ($_); + if (m/^\[(.*)\]/) { + $section = $1; + } + else { + if ( $section =~ /conn/i ) { + push (@allconnections, $_); + } + elsif ( $section =~ /alias/i ) { + m/^\s*(\S.*)\s*=\s*(\S+)/; + $allaliases {$2} = $1; + } + elsif ( $section =~ /color/i ) { + m/^\s*(-?\d+)\s*=\s*(\S+)/; + $allcolors {$1} = $2; + } + } + } + if ( ! keys (%allcolors) ) { + $allcolors {0} = "#ccffcc"; #apple green + $allcolors {5} = "#ffffcc"; #cream yellow + $allcolors {60} = "#ffcccc"; #pale pink + } + @colorkeys = sort (keys (%allcolors)); + close (CFGFILEHANDLE); + return 0; +} + +sub get_replicas +{ + my ($serveridx) = @_; + my ($conn, $host, $port, $shadowport, $binddn, $bindpwd, $bindcert); + my ($others); + my ($replica, $replicadn); + my ($ruv, $replicaroot, $replicatype, $serverid, $masterid, $maxcsn); + my ($type, $flag, $i); + my ($myridx, $ridx, $cidx); + + # + # Bind to the server + # + ($host, $port, $binddn, $bindpwd, $bindcert) = split (/:/, "$servers[$serveridx]", 5); + + ($port, $shadowport) = split (/=/, $port); + $shadowport = $port if !$shadowport; + + $conn = new Mozilla::LDAP::Conn ($host, $shadowport, "$binddn", $bindpwd, $bindcert); + + return -1 if (!$conn); + + # + # Get all the replica on the server + # + $myridx = $#allreplicas + 1; + $replica = $conn->search ("cn=mapping tree,cn=config", + "sub", + "(objectClass=nsDS5Replica)", 0, + qw(nsDS5ReplicaRoot nsDS5ReplicaType nsDS5Flags nsDS5ReplicaId)); + while ($replica) { + $replicadn = $replica->getDN; + $replicaroot = normalizeDN ($replica->{nsDS5ReplicaRoot}[0]); + $type = $replica->{nsDS5ReplicaType}[0]; + $flag = $replica->{nsDS5Flags}[0]; + $serverid = $replica->{nsDS5ReplicaId}[0]; + + # flag = 0: change log is not created + # type = 2: read only replica + # type = 3: updatable replica + $replicatype = $flag == 0 ? "consumer" : ($type == 2 ? "hub" : "master"); + + push (@allreplicas, "$serveridx:$replicaroot:$replicatype:$serverid:$replicadn"); + + $replica = $conn->nextEntry (); + } + + # + # Get ruv for each replica + # + for ($ridx = $myridx; $ridx <= $#allreplicas; $ridx++) { + + $replicaroot = $1 if ($allreplicas[$ridx] =~ /^\d+:([^:]*)/); + # do a one level search with nsuniqueid in the filter - this will force the use of the + # nsuniqueid index instead of the entry dn index, which seems to be unreliable in + # heavily loaded servers + $ruv = $conn->search($replicaroot, "one", + "(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectClass=nsTombstone))", + 0, qw(nsds50ruv nsruvReplicaLastModified)); + next if !$ruv; # this should be an error case . . . + + for ($ruv->getValues('nsds50ruv')) { + if (m/\{replica\s+(\d+).+?\}\s*\S+\s*(\S+)/i) { + $masterid = $1; + $maxcsn = &to_decimal_csn ($2); + $allruvs {"$ridx:$masterid"} = "$2:$maxcsn"; + } + } + + for ($ruv->getValues('nsruvReplicaLastModified')) { + if (m/\{replica\s+(\d+).+?\}\s*(\S+)/i) { + $masterid = $1; + $lastmodifiedat = hex($2); + my ($sec, $min, $hour, $mday, $mon, $year) = localtime ($lastmodifiedat); + $mon++; + $year += 1900; + $hour = "0".$hour if ($hour < 10); + $min = "0".$min if ($min < 10); + $sec = "0".$sec if ($sec < 10); + $allruvs {"$ridx:$masterid"} .= ";$mon/$mday/$year $hour:$min:$sec"; + } + } + } + + # + # Get all agreements for each supplier replica + # + for ($ridx = $myridx; $ridx <= $#allreplicas; $ridx++) { + $_ = $allreplicas[$ridx]; + + # Skip consumers + next if m/:consumer:/i; + + m/:([^:]*)$/; + $replicadn = $1; + my @attrlist = qw(cn nsds5BeginReplicaRefresh nsds5replicaUpdateInProgress + nsds5ReplicaLastInitStatus nsds5ReplicaLastInitStart + nsds5ReplicaLastInitEnd nsds5replicaReapActive + nsds5replicaLastUpdateStart nsds5replicaLastUpdateEnd + nsds5replicaChangesSentSinceStartup nsds5replicaLastUpdateStatus + nsds5ReplicaHost + nsds5ReplicaPort nsDS5ReplicaBindMethod nsds5ReplicaUpdateSchedule); + $agreement = $conn->search("$replicadn", "sub", "(objectClass=nsDS5ReplicationAgreement)", + 0, @attrlist); + while ($agreement) { + + my %agmt = (); + # Push consumer to server stack if we have not already + $host = ($agreement->getValues('nsDS5ReplicaHost'))[0]; + $port = ($agreement->getValues('nsDS5ReplicaPort'))[0]; + $cidx = &add_server ("$host:$port"); + + for (@attrlist) { + $agmt{$_} = ($agreement->getValues($_))[0]; + } + if ($agmt{nsDS5ReplicaBindMethod} =~ /simple/i) { + $agmt{nsDS5ReplicaBindMethod} = 'n'; + } + if (!$agmt{nsds5ReplicaUpdateSchedule} || + ($agmt{nsds5ReplicaUpdateSchedule} eq '0000-2359 0123456') || + ($agmt{nsds5ReplicaUpdateSchedule} eq '*') || + ($agmt{nsds5ReplicaUpdateSchedule} eq '* *')) { + $agmt{nsds5ReplicaUpdateSchedule} = 'always in sync'; + } + + $agmt{ridx} = $ridx; + $agmt{cidx} = $cidx; + push @allagreements, \%agmt; + + $agreement = $conn->nextEntry (); + } + } + + $conn->close; +} + +# +# Initially, the agreements have consumer host:port info instead of +# replica info. This routine will find the consumer replica info +# +sub find_consumer_replicas +{ + my ($m_ridx); # index of master's replica + my ($s_ridx); # index of supplier's replica + my ($c_ridx); # index of consumer's replica + my ($c_sidx); # index of consumer server + my ($remainder); # + my ($s_replicaroot); # supplier replica root + my ($c_replicaroot); # consumer replica root + my ($j, $val); + + # + # Loop through every agreement defined on the current supplier replica + # + foreach (@allagreements) { + $s_ridx = $_->{ridx}; + $c_sidx = $_->{cidx}; + $s_replicaroot = $1 if ($allreplicas[$s_ridx] =~ /^\d+:([^:]*)/); + $c_replicaroot = ""; + + # $c_ridx will be assigned to -$c_sidx + # if the condumer is not accessible + # $c_sidx will not be zero since it's + # not the first server. + $c_ridx = -$c_sidx; # $c_sidx will not be zero + + # Loop through consumer's replicas and find + # the counter part for the current supplier + # replica + for ($j = 0; $j <= $#allreplicas; $j++) { + + # Get a replica on consumer + # I'm not sure what's going on here, but possibly could be made + # much simpler with normalizeDN and/or ldap_explode_dn + if ($allreplicas[$j] =~ /^$c_sidx:([^:]*)/) { + $val = $1; + + # We need to find out the consumer + # replica that matches the supplier + # replicaroot most. + if ($s_replicaroot =~ /^.*$val$/i && + length ($val) >= length ($c_replicaroot)) { + $c_ridx = $j; + + # Avoid case-sensitive comparison + last if (length($s_replicaroot) == length($val)); + $c_replicaroot = $val; + } + } + } + $_->{ridx} = $s_ridx; + $_->{cidx} = $c_ridx; + } +} + +sub process_suppliers +{ + my ($ridx, $mid, $maxcsn); + + $mid = ""; + + $last_sidx = -1; # global variable for print html page + + for ($ridx = 0; $ridx <= $#allreplicas; $ridx++) { + + # Skip consumers and hubs + next if $allreplicas[$ridx] !~ /:master:(\d+):/i; + $mid = $1; + + # Skip replicas without agreements defined yet + next if (! grep {$_->{ridx} == $ridx} @allagreements); + + $maxcsn = &print_master_header ($ridx, $mid); + if ( "$maxcsn" != "none" ) { + &print_consumer_header (); + &print_consumers ($ridx, $mid); + } + &print_supplier_end; + } + + if ($mid eq "") { + print "<p>The server is not a master or it has no replication agreement\n"; + } +} + +sub print_master_header +{ + my ($ridx, $mid) = @_; + my ($myruv) = $allruvs {"$ridx:$mid"}; + my ($maxcsnval) = split ( /;/, "$myruv" ); + my ($maxcsn) = &to_string_csn ($maxcsnval); + my ($sidx, $replicaroot, $replicatype, $serverid) = split (/:/, $allreplicas[$ridx]); + + # Print the master name + if ( $last_sidx != $sidx ) { + my ($ldapurl) = &get_ldap_url ($sidx, $sidx); + &print_legend if ( $last_sidx < 0); + print "<p><p><hr><p>\n"; + print "\n<p><center class=page-subtitle><font color=#0099cc>\n"; + print "Master:  $ldapurl</center>\n"; + $last_sidx = $sidx; + } + + # Print the current replica info onthe master + print "\n<p><table border=0 cellspacing=1 cellpadding=6 cols=10 width=100% class=bgColor9>\n"; + + print "\n<tr><td colspan=10><center>\n"; + print "<font class=areatitle>Replica ID: </font>"; + print "<font class=text28>$serverid</font>\n"; + + print "<font class=areatitle>Replica Root: </font>"; + print "<font class=text28>$replicaroot</font>\n"; + + print "<font class=areatitle>Max CSN: </font>"; + print "<font class=text28>$maxcsn</font>\n"; + + return $maxcsn; +} + +sub print_consumer_header +{ + #Print the header of consumer + print "\n<tr class=bgColor16>\n"; + print "<th nowrap>Receiver</th>\n"; + print "<th nowrap>Time Lag</th>\n"; + print "<th nowrap>Max CSN</th>\n"; + print "<th nowrap>Last Modify Time</th>\n"; + print "<th nowrap>Supplier</th>\n"; + print "<th nowrap>Sent/Skipped</th>\n"; + print "<th nowrap>Update Status</th>\n"; + print "<th nowrap>Update Started</th>\n"; + print "<th nowrap>Update Ended</th>\n"; + print "<th nowrap colspan=2>Schedule</th>\n"; + print "<th nowrap>SSL?</th>\n"; + print "</tr>\n"; +} + +sub print_consumers +{ + my ($m_ridx, $mid) = @_; + my ($ignore, $m_replicaroot) = split (/:/, $allreplicas[$m_ridx]); + my (@consumers, @ouragreements, @myagreements); + my ($s_ridx, $c_ridx, $conntype, $schedule, $status); + my ($c_maxcsn_str, $lag, $markcolor); + my ($c_replicaroot, $c_replicatype); + my ($first_entry); + my ($nrows); + my ($found); + + undef @ouragreements; + + # Collect all the consumer replicas for the current master replica + push (@consumers, $m_ridx); + foreach (@consumers) { + $s_ridx = $_; + for (@allagreements) { + next if ($_->{ridx} != $s_ridx); + $c_ridx = $_->{cidx}; + next if $c_ridx == $m_ridx; + push @ouragreements, $_; + $found = 0; + foreach (@consumers) { + if ($_ == $c_ridx) { + $found = 1; + last; + } + } + push (@consumers, $c_ridx) if !$found; + } + } + + # Print each consumer replica + my ($myruv) = $allruvs {"$m_ridx:$mid"}; + my ($m_maxcsn) = split ( /;/, "$myruv" ); + foreach (@consumers) { + $c_ridx = $_; + next if $c_ridx == $m_ridx; + + if ($c_ridx >= 0) { + $myruv = $allruvs {"$c_ridx:$mid"}; + ($c_maxcsn, $c_lastmodified) = split ( /;/, "$myruv" ); + ($c_maxcsn_str, $lag, $markcolor) = &cacl_time_lag ($m_maxcsn, $c_maxcsn); + $c_maxcsn_str =~ s/ /\<br\>/; + ($c_sidx, $c_replicaroot, $c_replicatype) = split (/:/, $allreplicas[$c_ridx]); + $c_replicaroot = "same as master" if $m_replicaroot eq $c_replicaroot; + } + else { + # $c_ridx is actually -$c_sidx when c is not available + $c_sidx = -$c_ridx; + $c_maxcsn_str = "_"; + $lag = "n/a"; + $markcolor = red; + $c_replicaroot = "_"; + $c_replicatype = "_"; + } + + $nrows = 0; + foreach (@ouragreements) { + next if ($_->{cidx} != $c_ridx); + $nrows++; + } + + $first_entry = 1; + foreach (@ouragreements) { + next if ($_->{cidx} != $c_ridx); + $s_ridx = $_->{ridx}; + $conntype = $_->{nsDS5ReplicaBindMethod}; + $status = $_->{nsds5replicaLastUpdateStatus}; + $schedule = $_->{nsds5ReplicaUpdateSchedule}; + $s_sidx = $1 if $allreplicas [$s_ridx] =~ /^(\d+):/; + $s_ldapurl = &get_ldap_url ($s_sidx, "n/a"); + + # Print out the consumer's replica and ruvs + print "\n<tr class=bgColor13>\n"; + if ($first_entry) { + $first_entry = 0; + $c_ldapurl = &get_ldap_url ($c_sidx, $conntype); + print "<td rowspan=$nrows width=5% class=bgColor5>$c_ldapurl<BR>Type: $c_replicatype</td>\n"; + print "<td rowspan=$nrows width=5% nowrap bgcolor=$markcolor><center>$lag</center></td>\n"; + print "<td rowspan=$nrows width=15% nowrap>$c_maxcsn_str</td>\n"; + print "<td rowspan=$nrows width=15% nowrap>$c_lastmodified</td>\n"; + } + print "<td width=5% nowrap><center>$s_ldapurl</center></td>\n"; + my $changecount = $_->{nsds5replicaChangesSentSinceStartup}; + if ( $changecount =~ /^$mid:(\d+)\/(\d+) / || $changecount =~ / $mid:(\d+)\/(\d+) / ) { + $changecount = "$1 / $2"; + } + elsif ( $changecount =~ /^(\d+)$/ ) { + $changecount = $changecount . " / " . "$_->{nsds5replicaChangesSkippedSinceStartup}"; + } + else { + $changecount = "0 / 0"; + } + print "<td width=3% nowrap>$changecount</td>\n"; + my $redfontstart = ""; + my $redfontend = ""; + if ($status =~ /error/i) { + $redfontstart = "<font color='red'>"; + $redfontend = "</font>"; + } + elsif ($status =~ /^(\d+) /) { + if ( $1 != 0 ) { + # warning + $redfontstart = "<font color='#FF7777'>"; + $redfontend = "</font>"; + } + } + print "<td width=20% nowrap>$redfontstart$status$redfontend</td>\n"; + print "<td nowrap>", &format_z_time($_->{nsds5replicaLastUpdateStart}), "</td>\n"; + print "<td nowrap>", &format_z_time($_->{nsds5replicaLastUpdateEnd}), "</td>\n"; + if ( $schedule =~ /always/i ) { + print "<td colspan=2 width=10% nowrap>$schedule</td>\n"; + } + else { + my ($ndays, @days); + $schedule =~ /(\d\d)(\d\d)-(\d\d)(\d\d) (\d+)/; + print "<td width=10% nowrap>$1:$2-$3:$4</td>\n"; + $ndays = $5; + $ndays =~ s/(\d)/$1,/g; + @days = (Sun,Mon,Tue,Wed,Thu,Fri,Sat)[eval $ndays]; + print "<td width=10% nowrap>@days</td>\n"; + } + print "<td width=3% nowrap class=bgColor5>$conntype</td>\n"; + } + } +} + +sub cacl_time_lag +{ + my ($s_maxcsn, $c_maxcsn) = @_; + my ($markcolor); + my ($csn_str); + my ($s_tm, $c_tm, $lag_tm, $lag_str, $hours, $minute); + + $csn_str = &to_string_csn ($c_maxcsn); + + if ($s_maxcsn && !$c_maxcsn) { + $lag_str = "- ?:??:??"; + $markcolor = &get_color (36000); # assume consumer has big latency + } + elsif (!$s_maxcsn && $c_maxcsn) { + $lag_str = "+ ?:??:??"; + $markcolor = &get_color (1); # consumer is ahead of supplier + } + elsif ($s_maxcsn le $c_maxcsn) { + $lag_str = "0:00:00"; + $markcolor = &get_color (0); + } + else { + my ($rawcsn, $decimalcsn) = split (/:/, $s_maxcsn); + ($s_tm) = split(/ /, $decimalcsn); + + ($rawcsn, $decimalcsn) = split (/:/, $c_maxcsn); + ($c_tm) = split(/ /, $decimalcsn); + if ($s_tm > $c_tm) { + $lag_tm = $s_tm - $c_tm; + $lag_str = "- "; + $markcolor = &get_color ($lag_tm); + } + else { + $lag_tm = $c_tm - $s_tm; + $lag_str = "+ "; + $markcolor = $allcolors{ $colorkeys[0] }; # no delay + } + $hours = int ($lag_tm / 3600); + $lag_str .= "$hours:"; + + $lag_tm = $lag_tm % 3600; + $minutes = int ($lag_tm / 60); + $minutes = "0".$minutes if ($minutes < 10); + $lag_str .= "$minutes:"; + + $lag_tm = $lag_tm % 60; + $lag_tm = "0".$lag_tm if ($lag_tm < 10); + $lag_str .= "$lag_tm"; + } + return ($csn_str, $lag_str, $markcolor); +} + +# +# The subroutine would append a new entry to the end of +# @servers if the host and port are new to @servers. +# +sub add_server +{ + my ($host, $port, $binddn, $bindpwd, $bindcert) = split (/:/, "@_"); + my ($shadowport) = $port; + my ($domainpattern) = '\.[^:]+'; + my ($i); + + # Remove the domain name from the host name + my ($hostnode) = $host; + $hostnode = $1 if $host =~ /^(\w+)\./; + + # new host:port + if ($binddn eq "" || $bindpwd eq "" && $bindcert eq "") { + # + # Look up connection parameter in the order of + # host:port + # host:* + # *:port + # *:* + # + my (@myconfig, $h, $p, $d, $w, $c); + (@myconfig = grep (/^$hostnode($domainpattern)*:$port\D/i, @allconnections)) || + (@myconfig = grep (/^$hostnode($domainpattern)*:\*:/i, @allconnections)) || + (@myconfig = grep (/^\*:$port\D/, @allconnections)) || + (@myconfig = grep (/^\*:\*\D/, @allconnections)); + if ($#myconfig >= 0) { + ($h, $p, $d, $w, $c) = split (/:/, $myconfig[0]); + ($p, $shadowport) = split (/=/, $p); + $p = "" if $p eq "*"; + $c = "" if $c eq "*"; + } + if ($binddn eq "" || $binddn eq "*") { + if ($d eq "" || $d eq "*") { + $binddn = "cn=Directory Manager"; + } + else { + $binddn = $d; + } + } + $bindpwd = $w if ($bindpwd eq "" || $bindpwd eq "*"); + $bindcert = $c if ($bindcert eq "" || $bindcert eq "*"); + } + + for ($i = 0; $i <= $#servers; $i++) { + return $i if ($servers[$i] =~ /$hostnode($domainpattern)*:\d*=$shadowport\D/i); + } + + push (@servers, "$host:$port=$shadowport:$binddn:$bindpwd:$bindcert"); + return $i; +} + +sub get_ldap_url +{ + my ($sidx, $conntype) = @_; + my ($host, $port) = split(/:/, $servers[$sidx]); + my ($shadowport); + ($port, $shadowport) = split (/=/, $port); + my ($protocol, $ldapurl); + + if ($port eq 636 && $conntype eq "0" || $conntype =~ /SSL/i) { + $protocol = ldaps; + } + else { + $protocol = ldap; + } + my ($instance) = $allaliases { "$host:$port" }; + $instance = "$host:$port" if !$instance; + if ($conntype eq "n/a") { + $ldapurl = $instance; + } + else { + $ldapurl = "<a href=\"$protocol://$host:$port/\">$instance</a>"; + } + return $ldapurl; +} + +sub to_decimal_csn +{ + my ($maxcsn) = @_; + if (!$maxcsn || $maxcsn eq "") { + return "none"; + } + + my ($tm, $seq, $masterid, $subseq) = unpack("a8 a4 a4 a4", $maxcsn); + + $tm = hex($tm); + $seq = hex($seq); + $masterid = hex($masterid); + $subseq = hex($subseq); + + return "$tm $seq $masterid $subseq"; +} + +sub to_string_csn +{ + my ($rawcsn, $decimalcsn) = split(/:/, "@_"); + if (!$rawcsn || $rawcsn eq "") { + return "none"; + } + my ($tm, $seq, $masterid, $subseq) = split(/ /, $decimalcsn); + my ($sec, $min, $hour, $mday, $mon, $year) = localtime($tm); + $mon++; + $year += 1900; + foreach ($sec, $min, $hour, $mday, $mon) { + $_ = "0".$_ if ($_ < 10); + } + my ($csnstr) = "$mon/$mday/$year $hour:$min:$sec"; + $csnstr .= " $seq $subseq" if ( $seq != 0 || $subseq != 0 ); + return "$rawcsn ($csnstr)"; +} + +sub get_color +{ + my ($lag_minute) = @_; + $lag_minute /= 60; + my ($color) = $allcolors { $colorkeys[0] }; + foreach (@colorkeys) { + last if ($lag_minute < $_); + $color = $allcolors {$_}; + } + return $color; +} + +# subroutine to remove escaped encoding + +sub unescape +{ + #my ($_) = @_; + tr/+/ /; + s/%(..)/pack("c",hex($1))/ge; + $_; +} + +sub print_html_header +{ + # print the HTML header + + print "Content-type: text/html\n\n"; + print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\"><html>\n"; + print "<head><title>Replication Status</title>\n"; + # print "<link type=text/css rel=stylesheet href=\"master-style.css\">\n"; + print "<style text/css>\n"; + print "Body, p, table, td, ul, li {color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 12px;}\n"; + print "A {color:blue; text-decoration: none;}\n"; + print "BODY {font-family: arial, helvetica, sans-serif}\n"; + print "P {font-family: arial, helvetica, sans-serif}\n"; + print "TH {font-weight: bold; font-family: arial, helvetica, sans-serif}\n"; + print "TD {font-family: arial, helvetica, sans-serif}\n"; + print ".bgColor1 {background-color: #003366;}\n"; + print ".bgColor4 {background-color: #cccccc;}\n"; + print ".bgColor5 {background-color: #999999;}\n"; + print ".bgColor9 {background-color: #336699;}\n"; + print ".bgColor13 {background-color: #ffffff;}\n"; + print ".bgColor16 {background-color: #6699cc;}\n"; + print ".text8 {color: #0099cc; font-size: 11px; font-weight: bold;}\n"; + print ".text28 {color: #ffcc33; font-size: 12px; font-weight: bold;}\n"; + print ".areatitle {font-weight: bold; color: #ffffff; font-family: arial, helvetica, sans-serif}\n"; + print ".page-title {font-weight: bold; font-size: larger; font-family: arial, helvetica, sans-serif}\n"; + print ".page-subtitle {font-weight: bold; font-family: arial, helvetica, sans-serif}\n"; + + print "</style></head>\n<body class=bgColor4>\n"; + + if ($opt_u) { + print "<meta http-equiv=refresh content=$interval; URL=$opt_u>\n"; + } + + print "<table border=0 cellspacing=0 cellpadding=10 width=100% class=bgColor1>\n"; + print "<tr><td><font class=text8>$now</font></td>\n"; + print "<td align=center class=page-title><font color=#0099CC>"; + print "Netscape Directory Server Replication Status</font>\n"; + + if ($opt_u) { + print "<br><font class=text8>(This page updates every $interval seconds)</font>\n"; + } + + print "</td><td align=right valign=center width=25%><font class=text8>$version"; + print "</font></td></table>\n"; +} + +sub print_legend +{ + my ($nlegends) = $#colorkeys + 1; + print "\n<center><p><font class=page-subtitle color=#0099cc>Time Lag Legend:</font><p>\n"; + print "<table cellpadding=6 cols=$nlegends width=40%>\n<tr>\n"; + my ($i, $j); + for ($i = 0; $i < $nlegends - 1; $i++) { + $j = $colorkeys[$i]; + print "\n<td bgcolor=$allcolors{$j}><center>within $colorkeys[$i+1] min</center></td>\n"; + } + $j = $colorkeys[$i]; + print "\n<td bgcolor=$allcolors{$j}><center>over $colorkeys[$i] min</center></td>\n"; + print "\n<td bgcolor=red><center>server n/a</center></td>\n"; + print "</table></center>\n"; +} + +sub print_supplier_end +{ + print "</table>\n"; +} + +# given a string in generalized time format, convert to ascii time +sub format_z_time +{ + my $zstr = shift; + return "n/a" if (! $zstr); + my ($year, $mon, $day, $hour, $min, $sec) = + ($zstr =~ /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/); + my $time = timegm($sec, $min, $hour, $day, ($mon-1), $year); + ($sec, $min, $hour, $day, $mon, $year) = localtime($time); + $mon++; + $year += 1900; + foreach ($sec, $min, $hour, $day, $mon) { + $_ = "0".$_ if ($_ < 10); + } + + return "$mon/$day/$year $hour:$min:$sec"; +} diff --git a/ldap/admin/src/scripts/template-verify-db.pl b/ldap/admin/src/scripts/template-verify-db.pl new file mode 100644 index 00000000..a6cd98ca --- /dev/null +++ b/ldap/admin/src/scripts/template-verify-db.pl @@ -0,0 +1,196 @@ +#{{PERL-EXEC}} +# +# BEGIN COPYRIGHT BLOCK +# Copyright (C) 2003-2004 AOL, Inc. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +sub getDbDir +{ + (my $here) = @_; + my @dbdirs = (); + + opendir(DIR, $here) or die "can't opendir $here : $!"; + while (defined($dir = readdir(DIR))) + { + my $thisdir; + if ("$here" eq ".") + { + $thisdir = $dir; + } + else + { + $thisdir = $here . "{{SEP}}" . $dir; + } + if (-d $thisdir) + { + if (!($thisdir =~ /\./)) + { + opendir(SUBDIR, "$thisdir") or die "can't opendir $thisdir : $!"; + while (defined($file = readdir(SUBDIR))) + { + if ($file eq "DBVERSION") + { + $#dbdirs++; + $dbdirs[$#dbdirs] = $thisdir; + } + } + closedir(SUBDIR); + } + } + } + closedir(DIR); + + return \@dbdirs; +} + +sub getLastLogfile +{ + (my $here) = @_; + my $logfile = ""; + + opendir(DIR, $here) or die "can't opendir $here : $!"; + while (defined($file = readdir(DIR))) + { + if ($file =~ /log./) + { + $logfile = $file; + } + } + closedir(DIR); + + return \$logfile; +} + +print("*****************************************************************\n"); +print("verify-db: This tool should only be run if recovery start fails\n" . + "and the server is down. If you run this tool while the server is\n" . + "running, you may get false reports of corrupted files or other\n" . + "false errors.\n"); +print("*****************************************************************\n"); + +# get dirs having DBVERSION +my $dbdirs = getDbDir("."); + +for (my $i = 0; $i < @$dbdirs; $i++) +{ + # run ../bin/slapd/server/db_printlog -h <dbdir> for each <dbdir> + print "Verify log files in $$dbdirs[$i] ... "; + open(PRINTLOG, "..{{SEP}}bin{{SEP}}slapd{{SEP}}server{{SEP}}db_printlog -h $$dbdirs[$i] 2>&1 1> nul |"); + sleep 1; + my $haserr = 0; + while ($l = <PRINTLOG>) + { + if ("$l" ne "") + { + if ($haserr == 0) + { + print "\n"; + } + print "LOG ERROR: $l"; + $haserr++; + } + } + close(PRINTLOG); + if ($haserr == 0 && $? == 0) + { + print "Good\n"; + } + else + { + my $logfile = getLastLogfile($$dbdirs[$i]); + print "Log file(s) in $$dbdirs[$i] could be corrupted.\n"; + print "Please delete a log file $$logfile, and try restarting the server.\n"; + } +} + +for (my $i = 0; $i < @$dbdirs; $i++) +{ + # changelog + opendir(DB, $$dbdirs[$i]) or die "can't opendir $$dbdirs[$i] : $!"; + while (defined($db = readdir(DB))) + { + if ($db =~ /\.db/) + { + my $thisdb = $$dbdirs[$i] . "{{SEP}}" . $db; + print "Verify $thisdb ... "; + open(DBVERIFY, "..{{SEP}}bin{{SEP}}slapd{{SEP}}server{{SEP}}db_verify $thisdb 2>&1 1> nul |"); + sleep 1; + my $haserr = 0; + while ($l = <DBVERIFY>) + { + if ($haserr == 0) + { + print "\n"; + } + if ("$l" ne "") + { + $haserr++; + print "DB ERROR: $l"; + } + } + close(DBVERIFY); + if ($haserr == 0 && $? == 0) + { + print "Good\n"; + } + else + { + print "changelog file $db in $$dbdirs[$i] is corrupted.\n"; + print "Please restore your backup and recover the database.\n"; + } + } + } + closedir(DB); + + # backend: get instance dirs under <dbdir> + my $instdirs = getDbDir($$dbdirs[$i]); + + for (my $j = 0; $j < @$instdirs; $j++) + { + opendir(DIR, $$instdirs[$j]) or die "can't opendir $here : $!"; + while (defined($db = readdir(DIR))) + { + if ($db =~ /\.db/) + { + my $thisdb = $$instdirs[$j] . "{{SEP}}" . $db; + print "Verify $thisdb ... "; + open(DBVERIFY, "..{{SEP}}bin{{SEP}}slapd{{SEP}}server{{SEP}}db_verify $thisdb 2>&1 1> null |"); + sleep 1; + my $haserr = 0; + while ($l = <DBVERIFY>) + { + if ($haserr == 0) + { + print "\n"; + } + if ("$l" ne "") + { + $haserr++; + print "DB ERROR: $l"; + } + } + close(DBVERIFY); + if ($haserr == 0 && $? == 0) + { + print "Good\n"; + } + else + { + if ("$db" =~ /id2entry.db/) + { + print "Primary db file $db in $$instdirs[$j] is corrupted.\n"; + print "Please restore your backup and recover the database.\n"; + } + else + { + print "Secondary index file $db in $$instdirs[$j] is corrupted.\n"; + print "Please run db2index(.pl) for reindexing.\n"; + } + } + } + } + closedir(DIR); + } +} diff --git a/ldap/admin/src/shutdown.c b/ldap/admin/src/shutdown.c new file mode 100644 index 00000000..0ed55c1c --- /dev/null +++ b/ldap/admin/src/shutdown.c @@ -0,0 +1,39 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * shutdown.c: Kills the server. + * + * DS changes: Anil Bhavnani + * Removed all HTML output for DS 4.0: Rob Weltman + * Mike McCool + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "libadminutil/admutil.h" +#include "dsalib.h" +#include "init_ds_env.h" + +int main(int argc, char *argv[]) +{ + int status = -1; + + fprintf(stdout, "Content-type: text/html\n\n"); + + if ( init_ds_env() ) + return 1; + + status = ds_bring_down_server(); + if(status == DS_SERVER_DOWN) { + rpt_success("Success! The server has been shut down."); + return 0; + } else { + rpt_err( status, "", NULL, NULL ); + return 1; + } +} + diff --git a/ldap/admin/src/start.c b/ldap/admin/src/start.c new file mode 100644 index 00000000..8a0e4289 --- /dev/null +++ b/ldap/admin/src/start.c @@ -0,0 +1,42 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * start.c: Starts up the server. + * + * DS changes: Anil Bhavnani + * Removed all HTML output for DS 4.0: Rob Weltman + * Mike McCool + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "libadminutil/admutil.h" +#include "dsalib.h" +#include "init_ds_env.h" + + +static char buf[1024]; + +int main(int argc, char *argv[]) +{ + int status = -1; + char *instanceName = 0; + + fprintf(stdout, "Content-type: text/html\n\n"); + + if ( init_ds_env() ) + return 0; + + status = ds_bring_up_server(1); + if(status == DS_SERVER_UP) { + rpt_success("Success! The server has been started."); + return 0; + } else { + rpt_err( status, "", NULL, NULL ); + return 1; + } +} diff --git a/ldap/admin/src/uname.lib b/ldap/admin/src/uname.lib new file mode 100644 index 00000000..f3269e65 --- /dev/null +++ b/ldap/admin/src/uname.lib @@ -0,0 +1,169 @@ +#!perl +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +sub uname +{ + local (@CommandLine) = @_; + + local($getall) = 0; + local($getproc) = 0; + local($getosrel) = 0; + local($getosname) = 0; + local($getosver) = 0; + + while ($_ = @CommandLine[0]) { + PARSE_SWITCH: { + if (/^-a\b/i) {# show all information + $getall=1; + shift(@CommandLine); + last PARSE_SWITCH + } + if (/^-n\b/i) {# show node name + $getnodename=1; + shift(@CommandLine); + last PARSE_SWITCH + } + if (/^-p\b/i) {# show processor + $getproc=1; + shift(@CommandLine); + last PARSE_SWITCH + } + if (/^-r\b/i) {# show os release + $getosrel=1; + shift(@CommandLine); + last PARSE_SWITCH + } + if (/^-s\b/i) {# show os name + $getosname=1; + shift(@CommandLine); + last PARSE_SWITCH + } + if (/^-v\b/i) {# show os version + $getosver=1; + shift(@CommandLine); + last PARSE_SWITCH + } + print " ERROR: Unknown parameter: $_\n"; + shift(@CommandLine); + } + } + +chomp(local($os) = `uname -s`); +local($nodename) = ""; +local($proc) = ""; +local($osrel) = ""; +local($osname) = ""; +local($osver) = ""; +local($osrel1) = ""; +local($osrel2) = ""; +local($nodename1) = ""; +local($retval) = ""; +local($ret) = ""; + +if ($os eq "Windows_NT") +{ + chomp($nodename = `uname -n`); + chomp($proc = `uname -m`); lc($proc); + if ($proc =~ /^[0-9]86.*/) + { + $proc = "i386"; + } + else + { + $proc = "?"; + } + chomp($osrel1 = `uname -r`); + chomp($osrel2 = `uname -v`); + $osrel = $osrel1.".".$osrel2; + $osname = "WINNT"; + $osver = "???"; +} +if ($os eq "WINNT") +{ + chomp($nodename = `uname -n`); + chomp($proc = `uname -p`); lc($proc); + chomp($osrel = `uname -r`); + $osname = "WINNT"; + chomp($osver = `uname -v`); +} + +if ($os eq "SunOS") +{ + chomp($nodename = `uname -n`); + chomp($proc = `uname -p`); + chomp($osrel = `uname -r`); + $osname = $os; + chomp($osver = `uname -v`); +} +if ($os eq "IRIX" || $os eq "IRIX64") +{ + chomp($nodename = `uname -n`); + chomp($proc = `uname -p`); + chomp($osrel = `uname -r`); + $osname = "IRIX"; + chomp($osver = `uname -v`); +} + +if ($os eq "HP-UX") +{ + chomp($nodename = `uname -n`); +# $proc = "hppa1.1"; + chomp($proc = `uname -m`); + chomp($osrel = `uname -r`); + $osname = $os; + chomp($osver = `uname -v`); +} + +if ($os eq "OSF1") +{ + chomp($nodename1 = `uname -n`); + ($nodename) = ($nodename1 =~ /(\w+)\..*/); + chomp($proc = `uname -m`); + chomp($osrel = `uname -r`); + $osname = $os; + chomp($osver = `uname -v`); +} + +if ($os eq "AIX") +{ + chomp($nodename = `uname -n`); + $proc = "rs6000"; + chomp($osrel1 = `uname -v`); + chomp($osrel2 = `uname -r`); + $osrel = $osrel1.".".$osrel2; + $osname = $os; + $osver = "???"; +} + +if ($getall) +{ + $getosname = 1; + $getnodename = 1; + $getosrel = 1; + $getosver = 1; + $getproc = 1; +} + +$retval = ""; +$retval = $retval.($getosname ? $osname : ""); +$retval = $retval.($getnodename ? " ".$nodename : ""); +$retval = $retval.($getosrel ? " ".$osrel : ""); +$retval = $retval.($getosver ? " ".$osver : ""); +$retval = $retval.($getproc ? " ".$proc : ""); + +if ($retval eq "") +{ + $retval = $nodename; +} + +($ret) = ($retval =~ /\s*(.*)/); + +return "$ret"; +} +1 diff --git a/ldap/admin/src/updatedsgw b/ldap/admin/src/updatedsgw new file mode 100755 index 00000000..e09c59ac --- /dev/null +++ b/ldap/admin/src/updatedsgw @@ -0,0 +1,331 @@ +#!perl +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +$nshome = $ENV{'NETSITE_ROOT'}; + +# If there is no nshome, then assume that we're running +# as a commandline script. +if (!$nshome ) { + $script_mode = 1; + +# get the commandline options + if (!getopts('h:i:d:e:s:t:n:') || !$opt_n || !$opt_h ) { + print "usage: " . $0 . " -n nshome -h current_slapd_host:current_slapd_port [options]\n"; + print "\nrequired:\n"; + print " -n directory\tthe directory where 7.0 is installed (NS-HOME)\n"; + print " -h host[:port]\tthe current host and port of the directory server\n"; + print " \tto which the gateway connects.\n"; + print "\noptions:\n"; + print " -i host[:port]\tthe new host and port of the directory server\n"; + print " -s suffix\t\tthe old suffix of the directory server\n"; + print " -t suffix\t\tthe new ESCAPED suffix of the directory server\n"; + print " -d dirmgrdn\t\tthe old manager dn of the directory server\n"; + print " -e dirmgrdn\t\tthe new manager dn of the directory server\n"; + print "\nexample:\n " . $0 . " -n /home/servers/ds70/ -h gargoyle:1974 -i brooklyn -s \"dc=example,dc=com\" -t \"o%3Dmcom.com\" -d \"cn=directory manager\" -e \"cn=directory guru\"\n"; + + exit; + } + + # Parse the commandline options + handle_script_input(); + +} else { +# output cgi header + print "Content-type: text/plain\n\n"; + +# print "Done\n"; +# parse the input + while ( <> ) { + &parse_input( $_ ); + } + + if ( !$vars{'old_host'}) { + rpt_err( -13, "host"); +# -13 = null parameter. +# print "Invalid input for DSGW changer CGI\n\n"; + exit; + } + +# print "$nshome $vars{'old_host'} $vars{'old_port'}\n"; +} + +# setup the path separator +$isNT = -d '\\'; +$PS = $isNT ? "\\" : "/"; + +$contextdir = "$nshome"."$PS"."dsgw"."$PS"."context"; + +#make sure that the target directory exists +if (! -e "$contextdir") { + rpt_err( -16 ,"$contextdir"); +# -16 = not a directory +# print "$contextdir does not exist\n"; + exit; +} + + +# cd into NS-HOME/dsgw/context directory +chdir "$contextdir" or die "Unable to cd to $contextdir: $!\n"; + +# read the files + opendir DSGW_CONTEXT, "." or die "$!"; + @dsgwconfs = grep !/^\.\.?$/, readdir DSGW_CONTEXT; + closedir DSGW_CONTEXT; + + +# unescape the new and old suffixes +if ($vars{'old_suffix'} && $vars{'new_suffix'}) { + $escaped_suffix = $vars{'new_suffix'}; + $vars{'new_suffix'} =~ s/%(\w\w)/chr(hex($1))/eg; + $unescaped_suffix = $vars{'new_suffix'}; +# print "Normal new suffix: $unescaped_suffix\n"; +# print "Escaped new suffix: $escaped_suffix\n"; + $unescaped_oldsuffix = $vars{'old_suffix'}; + $unescaped_oldsuffix =~ s/%(\w\w)/chr(hex($1))/eg; +} + +#unescape the digmrs +if ($vars{'new_dirmgr'}){ + $vars{'new_dirmgr'} =~ s/%(\w\w)/chr(hex($1))/eg; +} + +if ($vars{'old_dirmgr'}){ + $vars{'old_dirmgr'} =~ s/%(\w\w)/chr(hex($1))/eg; +} + + + # + $changed = ""; + foreach $file (@dsgwconfs){ + +# print "working on $file\n"; + + # If it's not a .conf file, skip it. + if ( $file !~ m/.*?\.conf$/ ) { +# print "skipping $file\n\n\n\n"; + next; + } + + $relevant_conf = 0; + $relevant_suffix = 0; + + # open the old file + open(OLDFILE, "$file") or die "Cannot read $file. $!\n"; # + + # Need to test to see if this conf file has a baseurl that + # matches the old host and port + for ($line=<OLDFILE>; $line ; $line=<OLDFILE>) { # + + # If we find the matching baseurl, then set a flag and break out of the loop. + if ($line =~ m:^baseurl\s*("){0,1}\s*ldap(s){0,1}\://$vars{'old_host'}(\:$vars{'old_port'}){0,1}/:) { #") + # Also check for a matching suffix. + if ($vars{'old_suffix'} && $vars{'new_suffix'}) { + @baseurl = split("/", $line); + $curr_suff = $baseurl[3]; + + # Get rid of any double quotes. + @baseurl = split("\"", $curr_suff); + $curr_suff = $baseurl[0]; + + $unescaped_currsuffix = $curr_suff; + $unescaped_currsuffix =~ s/%(\w\w)/chr(hex($1))/eg; + +# print "curr Suffix: $curr_suff\n"; +# print "old Suffix: $vars{'old_suffix'}\n"; +# print "unescaped curr Suffix: $unescaped_currsuffix\n"; +# print "unescaped old Suffix: $unescaped_oldsuffix\n"; + + if ($unescaped_currsuffix eq $unescaped_oldsuffix) { + $relevant_suffix = 1; +# print "suffix match for $file\n"; + } + + } + # set a flag + $relevant_conf = 1; +# print "host:port match for $file\n"; + last; + } + + + } + + # If there was no match, then go on to the next file. + if (! $relevant_conf) { + close(OLDFILE); +# print "no match for $file\n"; + next; + } + + # Else, there is a match start over at the beginning of the file + seek OLDFILE, 0, 0; + if ($changed eq "") { + $changed = $file; + } + + # open the new file + open(NEWFILE, ">"."tmpcp_"."$file"."1") or die "Cannot write $contextdir$PStmpcp_$file1. $!\n"; + + # Go through each line, replacing the relevant information + for ($line=<OLDFILE>; $line ; $line=<OLDFILE>) { # + + # If there is a new host + if ($vars{'new_host'}) { + $line =~ s:^baseurl\s*("){0,1}\s*ldap(s){0,1}\://.*?(\:\d*){0,1}/:baseurl\t$1ldap$2\://$vars{'new_host'}$3/:og; #") +# print "new host for $file\n"; + + } + + # a new port + if ($vars{'new_port'}) { + $line =~ s:^baseurl\s*("){0,1}\s*ldap(s){0,1}\://(.*?)(\:\d*){0,1}/:baseurl\t$1ldap$2\://$3\:$vars{'new_port'}/:og; #") +# print "new port for $file\n"; + } + + # new dirmgr + if ($vars{'new_dirmgr'} && $vars{'old_dirmgr'}) { + $line =~ s:(?i)^dirmgr\s*("){0,1}$vars{'old_dirmgr'}("){0,1}:dirmgr\t"$vars{'new_dirmgr'}":g; +# print "new dirmgr for $file\n"; + } + + # new suffix + if ($relevant_suffix) { + $line =~ s:(^baseurl\s*("){0,1}\s*ldap(s){0,1}\://.*?(\:\d*){0,1}/)((.*?("))|(.*?)):$1$escaped_suffix$7:og; # + $line =~ s:^location-suffix.*:location-suffix\t"$unescaped_suffix":og; +# print "new suffix for $file\n"; + } + + + print NEWFILE $line; + + } + # + close(OLDFILE); + close(NEWFILE); + + rename "tmpcp_" . "$file"."1", "$file"; + + } +rpt_err(0, $changed); + + +sub parse_input +{ + local( $line ) = @_; + local($var, $value, $assign ); + + + foreach $assign ( split( /&/, $line ) ) { + ( $var, $value ) = split( /=/, $assign ); + $value =~ s/\+/ /g; + $value =~ s/ /%20/g; +# $value =~ s/%(\w\w)/chr(hex($1))/eg; + $var =~ s/\+/ /g; +# $var =~ s/%(\w\w)/chr(hex($1))/eg; + + + $vars{$var} = $value; + } +} + + +sub handle_script_input +{ + + if ($opt_h) { + @temp_array = split(":", $opt_h); + + $vars{'old_host'} = $temp_array[0]; + $vars{'old_port'} = $temp_array[1]; + +# print "host: $vars{'old_port'}\n"; +# print "port: $vars{'old_host'}\n"; + } + + if ($opt_i) { + @temp_array = split(":", $opt_i); + + $vars{'new_host'} = $temp_array[0]; + $vars{'new_port'} = $temp_array[1]; + +# print " $vars{'new_port'}\n"; +# print " $vars{'new_host'}\n"; + } + if ($opt_d) { + $vars{'old_dirmgr'} = $opt_d; + } + if ($opt_e) { + $vars{'new_dirmgr'} = $opt_e; + } + if ($opt_s) { + $vars{'old_suffix'} = $opt_s; + } + if ($opt_t) { + $vars{'new_suffix'} = $opt_t; + } + if ($opt_n) { + $nshome = $opt_n; + } + +} + + +sub rpt_err +{ + my $code = shift; + my $err_string = shift; + + print "NMC_ErrInfo: " . "$err_string" . "\n"; + print "NMC_STATUS: " . "$code"."\n"; + +} + +sub getopts { + local($argumentative) = @_; + local(@args,$_,$first,$rest); + local($errs) = 0; + local($[) = 0; + + @args = split( / */, $argumentative ); + while(@ARGV && ($_ = $ARGV[0]) =~ /^-(.)(.*)/) { + ($first,$rest) = ($1,$2); + $pos = index($argumentative,$first); + if($pos >= $[) { + if($args[$pos+1] eq ':') { + shift(@ARGV); + if($rest eq '') { + ++$errs unless @ARGV; + $rest = shift(@ARGV); + } + eval "\$opt_$first = \$rest;"; + } + else { + eval "\$opt_$first = 1"; + if($rest eq '') { + shift(@ARGV); + } + else { + $ARGV[0] = "-$rest"; + } + } + } + else { + print STDERR "Unknown option: $first\n"; + ++$errs; + if($rest ne '') { + $ARGV[0] = "-$rest"; + } + else { + shift(@ARGV); + } + } + } + $errs == 0; +} + diff --git a/ldap/admin/src/upgradeServer b/ldap/admin/src/upgradeServer new file mode 100755 index 00000000..d6bec4a7 --- /dev/null +++ b/ldap/admin/src/upgradeServer @@ -0,0 +1,442 @@ +#!perl +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +# This script is used to copy over files from 'install' directory +# to the server instance. + +BEGIN { + $isNT = -d "\\"; + $PS = $isNT ? "\\" : "/"; + $SEP = $isNT ? ";" : ":" ; + $slapdExecName = $isNT ? "slapd.exe" : "ns-slapd"; + # NT needs quotes around some things unix doesn't + $quote = $isNT ? "\"" : ""; +} + +$sroot = $ARGV[0]; +$prefix = $ARGV[1]; +$installDir = sprintf("%s%s%s%s%s%s%s", $sroot, ${PS}, "bin", ${PS}, "slapd", ${PS}, "install"); + +push @INC, "$sroot/bin/slapd/admin/bin"; +require 'uname.lib'; + +my $os = &uname("-s"); +my $shlibsuf; +SWITCH: { + if ($os eq "AIX") { + $LIB_PATH = "LIBPATH" ; + $shlibsuf = ".so"; + last SWITCH ; + } + if ($os eq "HP-UX") { + $LIB_PATH = "SHLIB_PATH" ; + $shlibsuf = ".sl"; + last SWITCH ; + } + if ($isNT) { + $LIB_PATH = "PATH" ; + $shlibsuf = ".dll"; + last SWITCH ; + } + else { + $LIB_PATH = "LD_LIBRARY_PATH" ; + $shlibsuf = ".so"; + last SWITCH ; + } +} + +# This subroutine takes source directory and destination directory +# as the arguments. + +sub copy_files +{ + my $destDir = pop(@_); + my $srcDir = pop(@_); + my $buf = ""; + my $bufsize = 8192; + + opendir(SRCDIR, $srcDir) || die "Can not open source directory $src_dir\n"; + my @srcfiles = readdir(SRCDIR); + closedir(SRCDIR); + + my $count = 0; + while ($count <= $#srcfiles) { + if ($srcfiles[$count] eq "." || $srcfiles[$count] eq ".." + || $srcfiles[$count] eq "99user.ldif" ) { + $count++; + next; + } + my $fullpath_srcfile = sprintf("%s%s%s", $srcDir, ${PS}, $srcfiles[$count]); + my $fullpath_destfile = sprintf("%s%s%s", $destDir, ${PS}, $srcfiles[$count]); + + open( SRC, $fullpath_srcfile ) || die "Can't open $fullpath_srcfile: $!\n"; + open( DEST, ">$fullpath_destfile" ) || die "Can't create $fullpath_destfile: $!\n"; + while (read(SRC, $buf, $bufsize)) { + print DEST $buf; + } + close( SRC ); + close( DEST ); + + $count++; + } +} + +# Copy schema ldiffiles from <server-root>/bin/slapd/install/schema to +# <server-root>/<server-instance>/config/schema + +sub copy_schema_files +{ + my $schema_bakdir = sprintf("%s%s%s%s%s%s%s", $sroot, ${PS}, ${prefix}, ${PS}, "config", ${PS}, "schema-bak"); + my $schema_srcdir = sprintf("%s%s%s", $installDir, ${PS}, "schema"); + my $schema_destdir = sprintf("%s%s%s%s%s%s%s", $sroot, ${PS}, ${prefix}, ${PS}, "config", ${PS}, "schema"); + + # First, back up the original schema ldiffiles under schema-bak directory + unless (-d $schema_bakdir) { + mkdir ($schema_bakdir, 0755) || + die "Cannot create directory $schema_bakdir: $!\n"; + } + copy_files( $schema_destdir, $schema_bakdir ); + + # Now, copy the latest schema ldiffiles + copy_files( $schema_srcdir, $schema_destdir ); +} + +sub modify_dse_ldif +{ + my $dse_ldiffile = sprintf("%s%s%s%s%s%s%s", $sroot, ${PS}, ${prefix}, ${PS}, "config", ${PS}, "dse.ldif"); + my $isOID = 0; + my $isJPEG = 0; + my $isSpInSt = 0; + my $reqNameChange = 0; + + open( DSE, "$dse_ldiffile" ) || die "Can't open $dse_ldiffile: $!\n"; + my $new_filename = "$dse_ldiffile"."_new"; + open( OUTFILE, "> $new_filename" ); + while($line = <DSE>) { + $isOID = 1 if ( $line =~ /^dn:\s*cn=OID Syntax,\s*cn=plugins,\s*cn=config/i); + $isJPEG = 1 if ( $line =~ /^dn:\s*cn=JPEG Syntax,\s*cn=plugins,\s*cn=config/i); + $isSpInSt = 1 if ( $line =~ /^dn:\s*cn=Space Insensitive String Syntax,\s*cn=plugins,\s*cn=config/i); + if( ($line =~ s/uid uniqueness/attribute uniqueness/) || + ($line =~ s/uid-plugin/attr-unique-plugin/) ){ + # the plugin name has changed + $reqNameChange = 1; + print OUTFILE $line; + } else { + print OUTFILE $line; + } + + } + close( DSE ); + close(OUTFILE); + + if ($isOID && $isJPEG && $isSpInSt && !$reqNameChange) { + # nothing to be done - just return + unlink($new_filename); + return; + } + + if($reqNameChange){ + # if the name change is required copy the contents of the edited dse.ldif_new to the dse.ldif + open( DSE, ">$dse_ldiffile" ) || die "Can't open $dse_ldiffile: $!\n"; + open( OUTFILE, "$new_filename" ) || die "Can't open $new_filename: $!\n"; + while($line = <OUTFILE>) { + print DSE $line; + } + close( DSE ); + close(OUTFILE); + } + unlink($new_filename) or die "Cannot unlink $new_filename \n"; + + + open( DSE, ">>$dse_ldiffile" ) || die "Can't open $dse_ldiffile: $!\n"; + + unless ($isOID) { + # Add OID Syntax entry + print DSE "dn: cn=OID Syntax,cn=plugins,cn=config\n"; + print DSE "objectClass: top\n"; + print DSE "objectClass: nsSlapdPlugin\n"; + print DSE "objectClass: extensibleObject\n"; + print DSE "cn: OID Syntax\n"; + print DSE "nsslapd-pluginPath: $sroot/lib/syntax-plugin$shlibsuf\n"; + print DSE "nsslapd-pluginInitfunc: oid_init\n"; + print DSE "nsslapd-pluginType: syntax\n"; + print DSE "nsslapd-pluginEnabled: on\n"; + print DSE "nsslapd-pluginId: oid-syntax\n"; + print DSE "nsslapd-pluginVersion: 6.2.1\n"; + print DSE "nsslapd-pluginVendor: Netscape Communications Corp.\n"; + print DSE "nsslapd-pluginDescription: OID attribute syntax plugin\n"; + print DSE "\n"; + } + + unless ($isJPEG) { + # Add JPEG Syntax entry + print DSE "dn: cn=JPEG Syntax,cn=plugins,cn=config\n"; + print DSE "objectClass: top\n"; + print DSE "objectClass: nsSlapdPlugin\n"; + print DSE "objectClass: extensibleObject\n"; + print DSE "cn: JPEG Syntax\n"; + print DSE "nsslapd-pluginPath: $sroot/lib/syntax-plugin$shlibsuf\n"; + print DSE "nsslapd-pluginInitfunc: jpeg_init\n"; + print DSE "nsslapd-pluginType: syntax\n"; + print DSE "nsslapd-pluginEnabled: on\n"; + print DSE "nsslapd-pluginId: jpeg-syntax\n"; + print DSE "nsslapd-pluginVersion: 6.2.1\n"; + print DSE "nsslapd-pluginVendor: Netscape Communications Corp.\n"; + print DSE "nsslapd-pluginDescription: JPEG attribute syntax plugin\n"; + print DSE "\n"; + } + + unless ($isSpInSt) { + # Add Space Insensitive String Syntax entry + print DSE "dn: cn=Space Insensitive String Syntax,cn=plugins,cn=config\n"; + print DSE "objectClass: top\n"; + print DSE "objectClass: nsSlapdPlugin\n"; + print DSE "objectClass: extensibleObject\n"; + print DSE "cn: Space Insensitive String Syntax\n"; + print DSE "nsslapd-pluginPath: $sroot/lib/syntax-plugin$shlibsuf\n"; + print DSE "nsslapd-pluginInitfunc: sicis_init\n"; + print DSE "nsslapd-pluginType: syntax\n"; + print DSE "nsslapd-pluginEnabled: on\n"; + print DSE "nsslapd-pluginId: spaceinsensitivestring-syntax\n"; + print DSE "nsslapd-pluginVersion: 6.2.1\n"; + print DSE "nsslapd-pluginVendor: Netscape Communications Corp.\n"; + print DSE "nsslapd-pluginDescription: space insensitive string attribute syntax plugin\n"; + print DSE "\n"; + } + + close( DSE ); +} + +sub get_changelog_dir { + my $dse_ldiffile = sprintf("%s%s%s%s%s%s%s", $sroot, ${PS}, ${prefix}, ${PS}, "config", ${PS}, "dse.ldif"); + my $inClEntry = 0; + my $clDir; + + # first find the changelog dir, if any + open( DSE, "$dse_ldiffile" ) || die "Can't open $dse_ldiffile: $!\n"; + while(<DSE>) { + if (/^dn:\s*cn=changelog5,\s*cn=config/i) { + $inClEntry = 1; + next; + } + if (/^\s*$/ && $inClEntry) { + $inClEntry = 0; + last; # not found, just abort + } + if ($inClEntry && /^nsslapd-changelogdir:\s*/i) { + $clDir = $'; + chomp($clDir); + last; + } + } + close( DSE ); + return $clDir; +} + +sub fix_changelog { + my $clDir = shift; + my $newver = shift; + + # look for the region files and remove them - they are the files + # that start with "__" - like __db.001 + opendir CLDIR, $clDir || die "Error: can't open changelog db dir $clDir: $!"; + while (my $ff = readdir CLDIR) { + unlink $clDir."/".$ff if ($ff =~ /^__/); + } + closedir CLDIR; + + # change the dbversion + my $dbverfile = $clDir . "/DBVERSION"; + my $tmpverfile = $clDir . "/DBVERSION.tmp"; + open DBVER, $dbverfile or die "Error: could not read file $dbverfile: $!"; + open TMPVER, ">$tmpverfile" or die "Error: could not write file $tmpverfile: $!"; + while (<DBVER>) { + s/\d+\.\d+$/$newver/; + print TMPVER; + } + close TMPVER; + close DBVER; + unlink $dbverfile; + rename $tmpverfile, $dbverfile; +} + +# get the new (current) version from slapd itself +# not currently used +sub getSlapdVersion { + my $dir = shift; + my $version = 0; # major version of e.g. 6.1 == 6 + my $minor = 0; # minor version of e.g. 6.1 == 1 + my $subminor = 0; # subminor version of e.g. 6.1.2 == 2 + my $buildNumber = 0; + my $progDir = "${PS}bin${PS}slapd${PS}server${PS}"; + + # find the slapd executable + $prog = $dir . $progDir . $slapdExecName; + if (! -f $prog) { + die "Could not run slapd program $prog: $!"; + } + else { + chdir($dir . $progDir); + } + + open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or + die "Could not run slapd program $prog: $!"; + sleep(1); # allow some data to accumulate in the pipe +# print "Output from $prog -v:\n"; + while (<F>) { + if (/^Netscape-Directory\/(\d+)\.(\d+)(?:\.(\d+))?(?:b\d)*\s+(\S+)/) { + $version = $1; + $minor = $2; + if ($4) { + $subminor = $3; + $buildNumber = $4; + } else { + $buildNumber = $3; + } + last; + } + elsif (/^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)(?:\.(\d+))?\s+(\S+)/) { # we can have restricted-mode or restriced-mode ... + # version could be X.Y or X.Y.Z + $version = $1; + $minor = $2; + if ($4) { + $subminor = $3; + $buildNumber = $4; + } else { + $buildNumber = $3; + } + last; + } + elsif (/^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) { + $version = $1; + $minor = $2; + $buildNumber = $3; + last; + } + } + my $code = close(F); + + if ($version == 0) { + die "\nCould not determine version of the directory server in $dir: \n"; + } + + # distinguish the 4.1 and the 4.11 thanks to the buildNumber + if (($version == 4) && ($minor == 1)){ + if (! ($buildNumber =~ /^B99\.16/)) { + # it's not a 4.1 Netscape Directory Server => it's a 4.11 + $minor = 11 ; + } + } + return ( $version, $minor, $subminor ); +} + +# get the old version from the $sroot/setup/slapd/slapd.inf file +# not currently used +sub getInfVersion { + my $inffile = "$sroot/setup/slapd/slapd.inf"; + open INF, $inffile || die "Error: could not read file $inffile: $!"; + my $inslapdsection = 0; + while (<INF>) { + if (/^\[slapd\]/) { + $inslapdsection = 1; + } elsif ($inslapdsection && /^\[/) { + $inslapdsection = 0; + last; + } elsif ($inslapdsection && /^\s*Version\s*=\s*(\d+)\.(\d+)(?:\.(\d+))?/) { + close INF; + return ($1, $2, $3); + } + } + close INF; + return ('0', '0'); +} + +sub getChangelogVersion { + my $cldir = shift; + my $versionfile = $cldir . "/DBVERSION"; + my $version = "0.0"; + open DBVER, $versionfile or return '0.0'; + while (<DBVER>) { + if (/(\d+\.\d+)$/) { + $version = $1; + } + } + close DBVER; + return $version; +} + +# +# Some scripts generated by create_instance may not +# get generated during in-place upgrade. This function +# is to fix it during postinstall. +# A new template can be directly added to array @newtemplates +# if it follows the naming convertion of "template-<target_name>", +# and its target is $prefix/<target_name>. Otherwise +# modify the script to include any new need. +# +sub instantiate_new_scripts { + + @newtemplates = ( + "$sroot/bin/slapd/admin/scripts/template-ns-newpwpolicy.pl" + ); + + $host = localhost; + $port = 389; + $rootdn = "cn=Directory Manager"; + if ( open ( dse, "$sroot/$prefix/config/dse.ldif" )) { + while ( <dse> ) { + $host = $1 if /^nsslapd-localhost:\s*(\S+)\s*$/; + $port = $1 if /^nsslapd-port:\s*(\d+)\D*$/; + $rootdn = $1 if /^nsslapd-rootdn:\s*(\S.+)\s*$/; + } + } + + foreach $src ( @newtemplates ) { + $dest = "$sroot/$prefix/$1" if $src =~ /.*template-(.*)$/; + next if -f $dest; + unless ( open ( template, $src )) { + print "Can't open $src: $!\n"; + next; + } + unless ( open ( target, ">$dest" )) { + print "Can't open $dest: $!\n"; + next; + } + while ( <template> ) { + s#{{PERL-EXEC}}#!$sroot/bin/slapd/admin/bin/perl#g; + s#{{DS-ROOT}}#$sroot#g; + s#{{SEP}}#${PS}#g; + s#{{ROOT-DN}}#$rootdn#g; + s#{{SERVER-PORT}}#$port#g; + s#{{SERVER-NAME}}#$host#g; + printf target; + } + close template; + close target; + } + return 0; +} + +# copy schema is safe even if same version +copy_schema_files; + +# modify only if necessary +modify_dse_ldif; + +# fix changelog is safe even if same version - no op +my $clDir = get_changelog_dir; +if ($clDir && -d $clDir) { + my $oldclversion = getChangelogVersion($clDir); + my $clversion = "2.0"; # with DS 6.1 + + if ($oldclversion < $clversion) { + fix_changelog($clDir, $clversion); + } +} + +instantiate_new_scripts (); diff --git a/ldap/admin/src/vlvindex.c b/ldap/admin/src/vlvindex.c new file mode 100644 index 00000000..e1be972c --- /dev/null +++ b/ldap/admin/src/vlvindex.c @@ -0,0 +1,92 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * vlvindex.c: Creates a VLV index for a given search + * + * Rob Weltman + */ + +#include <stdio.h> +#include <stdlib.h> +#include "libadminutil/admutil.h" +#include "dsalib.h" +#include "init_ds_env.h" +#include <string.h> + +int main(int argc, char *argv[]) +{ + int status; + char *backendNames = NULL; + char *attributes = NULL; + char *tmparg = NULL; + char **attrList = NULL; + char **backendList = NULL; + int nItem = 0; + char *nextItem = NULL; + int i=0; + + fprintf(stdout, "Content-type: text/html\n\n"); + + if ( init_ds_env() ) + return 1; + + ds_send_status("Creating vlv index ..."); + + /* + * Get var's value + */ + backendNames = ds_get_cgi_var("backendID"); + if ( (NULL == backendNames) || (strlen(backendNames) < 1) ) { + rpt_err( DS_UNDEFINED_VARIABLE, "backendID", NULL, NULL ); + return 1; + } + + attributes = ds_get_cgi_var("vlvTags"); + if ( (NULL == attributes) || (strlen(attributes) < 1) ) { + rpt_err( DS_UNDEFINED_VARIABLE, "vlvTags", NULL, NULL ); + return 1; + } + + tmparg = strdup( attributes ); + nItem = 0; + for(i=0 ; i < strlen(attributes) ; i++) { + if ( tmparg[i] == ';' ) nItem++; + } + /* Allocate for worst possible case */ + attrList = (char **)malloc(sizeof(*attrList) * (nItem + 2) ); + nItem = 0; + /* strtok() is not MT safe, but it is okay to call here because this is a command line */ + attrList[nItem++] = strtok( tmparg, ";" ); + do { + nextItem = strtok( NULL, ";" ); + attrList[nItem++] = nextItem; + } while( nextItem != NULL ); + + tmparg = strdup( backendNames ); + nItem = 0; + for(i=0;i<strlen(tmparg); i++) { + if ( tmparg[i] == ';' ) nItem++; + } + backendList = (char **)malloc(sizeof(*backendList) * nItem + 2); + nItem = 0; + backendList[nItem++] = strtok( tmparg, ";" ); + do { + nextItem = strtok( NULL, ";" ); + backendList[nItem++] = nextItem; + } while( nextItem != NULL ); + + status = ds_vlvindex(backendList, attrList); + + if ( !status ) { + rpt_success("Success! The index has been created."); + status = 0; + } else { + rpt_err( status, backendList[0], NULL, NULL ); + status = 1; + } + + return status; +} |